stm32f103最少有2個AD模數(shù)轉(zhuǎn)換器,,每個ADC都有18個通道,,可以測量16個外部和2個內(nèi)部模擬量,。最大轉(zhuǎn)換頻率為1Mhz,也就是轉(zhuǎn)換時間為1us(在 ADCCLK = 14Mhz,采樣周期為1.5個時鐘周期時),。最大時鐘超過14Mhz,,將導(dǎo)致ADC轉(zhuǎn)換準(zhǔn)確度降低,。stm32的ADC是12位精度的,。 stm32的ADC轉(zhuǎn)換有兩種通道,規(guī)則通道和注入通道,,注入通道可以搶占式地打斷規(guī)則通道的采樣,,執(zhí)行注入通道采樣后,再執(zhí)行之前的規(guī)則通道采樣,,和中斷類似,。本例只使用規(guī)則通道實現(xiàn)獨立模式的中斷采樣,這里不再贅述兩種通道區(qū)別,。 stm32的ADC可以由外部事件觸發(fā)(例如定時器捕獲,,EXTI線)和軟件觸發(fā)(即在配置相關(guān)寄存器時,直接開啟采樣),。 本例實現(xiàn)AD采樣PB0口,,使用串口輸出PB0口電壓值,。PB0口接變阻器以改變調(diào)整電壓。 效果如下: ADValue = 1.39v ADValue = 1.38v ADValue = 1.40v ADValue = 1.38v ADValue = 1.39v 直接操作寄存器 首先需要配置ADC的時鐘分頻值,,在RCC->CFGR的[15:14]位:
設(shè)定各通道的采樣時間ADCx->SMPR,該寄存器給每個通道3位來選擇8種采樣周期:
采樣時間算法為: (采樣周期+12.5)/分頻后的時鐘 ADC采樣得到的只是一個相對值,,將 轉(zhuǎn)換值/4096*參考電壓 即可得到采樣電壓 這里的4096是因為stm32的adc為12位精度,表示參考電壓時即為 2^12=4096 代碼如下: (system.h 和 stm32f10x_it.h 等相關(guān)代碼參照 stm32 直接操作寄存器開發(fā)環(huán)境配置) User/main.c #include <stm32f10x_lib.h> #include "system.h" #include "usart.h" #include "adc.h" #include "stdio.h" #define LED1 PAout(4) #define LED2 PAout(5) #define VREF 3.3 //參考電壓 void Gpio_Init(void); int main(void) { u16 ADValue; float temp; Rcc_Init(9); //系統(tǒng)時鐘設(shè)置 Usart1_Init(72,9600); //設(shè)置串口時鐘和波特率 Adc1_Init(8,7); //使用8通道采樣,,采樣時間系數(shù)為7(111),,據(jù)手冊可得采樣時間為 (239.5+12.5)/12= 21 (us) Gpio_Init(); while(1){ ADValue = Get_Adc(ADC_1,8); temp = (float)VREF*(ADValue/4096); //ADC精度為12位精度,即達(dá)到 VREF電壓時為 2^12 = 4096 printf("\r\n ADValue = %.2fv\r\n",temp); LED2 = !LED2; delay(100000); //延時100ms } } void Gpio_Init(void) { RCC->APB2ENR|=1<<2; //使能PORTA時鐘 RCC->APB2ENR|=1<<3; //使能PORTB時鐘 GPIOA->CRL&=0xFF0FFFF0; GPIOA->CRL|=0xFF3FFFF0; // PA0設(shè)置為模擬輸入,PA4推挽輸出 GPIOB->CRL&=0xFFFFFFF0; GPIOB->CRL|=0xFFFFFFF0; // PB0設(shè)置為模擬輸入 //USART1 串口I/O設(shè)置 GPIOA -> CRH&=0xFFFFF00F; //設(shè)置USART1 的Tx(PA.9)為第二功能推挽,,50MHz,;Rx(PA.10)為浮空輸入 GPIOA -> CRH|=0x000008B0; } Library/src/adc.c #include <stm32f10x_lib.h> #include "adc.h" //ADC1采樣初始化 //獨立工作模式 //參數(shù)說明: // ADC_CH_x 選擇使用通道(0~17),目前暫支持0~15通道 // ADC_CH_SMP 設(shè)定采樣周期(0~7) //采樣周期算法: void Adc1_Init(u8 ADC_CH_x,u8 ADC_CH_SMP) { RCC -> APB2ENR |= 1<<9; //開啟ADC1時鐘 RCC -> APB2RSTR |= 1<<9; //復(fù)位ADC1 RCC -> APB2RSTR &= ~(1<<9); //ADC1復(fù)位結(jié)束 RCC -> CFGR &= ~(3<<14); //分頻因子清零 RCC -> CFGR |= 2<<14; //設(shè)定分頻因數(shù)為2,PCLK2 6分頻后作為ADC時鐘 ADC1 -> CR1 &= 0xF0FFFF; //工作模式清零 ADC1 -> CR1 |= 0<<16; //設(shè)定為獨立模式 ADC1 -> CR1 &= ~(1<<8); //非掃描工作模式 ADC1 -> CR2 &= ~(1<<1); //關(guān)閉連續(xù)轉(zhuǎn)換 ADC1 -> CR2 &= ~(7<<17); //清除規(guī)則通道啟動事件 ADC1 -> CR2 |= 7<<17; //設(shè)定規(guī)則通道啟動事件為軟件啟動(SWSTART) ADC1 -> CR2 |= 1<<20; //使用外部事件觸發(fā) SWSTART ADC1 -> CR2 &= ~(1<<11); //設(shè)置對齊模式為右對齊 ADC1 -> SQR1 &= ~(0xF<<20); //清零規(guī)則序列的數(shù)量 ADC1 -> SQR1 |= 15<<20; //設(shè)置規(guī)則序列的數(shù)量為16 ADC1 -> SMPR2 &= 0x00000000; //清零通道采樣時間 ADC1 -> SMPR1 &= 0xFF000000; if(ADC_CH_x <= 9 ){ ADC1 -> SMPR2 |= 7<<(ADC_CH_x*3); //設(shè)置通道x采樣時間,,提高采樣時間可以提高采樣精度 } if(ADC_CH_x > 9 ){ ADC1 -> SMPR1 |= 7<<((ADC_CH_x-10)*3); } ADC1 -> CR2 |= 1<<0; //開啟AD轉(zhuǎn)換 ADC1 -> CR2 |= 1<<3; //使能復(fù)位校準(zhǔn),,由硬件清零 while((ADC1 -> CR2)& (1<<3)); //等待校準(zhǔn)結(jié)束 ADC1 -> CR2 |= 1<<2; //開啟AD校準(zhǔn),由硬件清零 while((ADC1 -> CR2)& (1<<2)); //等待校準(zhǔn)結(jié)束 } //取得數(shù)模轉(zhuǎn)換的值 //參數(shù)說明:(參數(shù)定義于adc.h) // ADC_x (0~3),選擇數(shù)模轉(zhuǎn)換器 // ADC_CH_x (0~15),選擇通道 u16 Get_Adc(u8 ADC_x,u8 ADC_CH_x) { u16 data = 0; switch(ADC_x) { case 1 : { ADC1 -> SQR3 &= 0xFFFFFFE0; //清除通道選擇 ADC1 -> SQR3 |= ADC_CH_x; //選擇通道 ADC1 -> CR2 |= 1<<22; //開啟AD轉(zhuǎn)換 while(!(ADC1 -> SR & 1<<1)); //等待轉(zhuǎn)換結(jié)束 data = ADC1->DR; break; } case 2 : {break;} case 3 : {break;} } return data; } Library/inc/adc.h #include <stm32f10x_lib.h> #define ADC_1 0x01 #define ADC_2 0x02 #define ADC_3 0x03 void Adc1_Init(u8 ADC_CH_x,u8 ADC_CH_SMP); u16 Get_Adc(u8 ADC_x,u8 ADC_CH_x); 庫函數(shù)操作 main.c #include "stm32f10x.h" #include "stdio.h" #define PRINTF_ON 1 #define VREF 3.3 // 參考電壓 void RCC_Configuration(void); void GPIO_Configuration(void); void USART_Configuration(void); void ADC_Configuration(void); int main(void) { float ADValue = 0.00; u32 delayTime = 0; RCC_Configuration(); GPIO_Configuration(); USART_Configuration(); ADC_Configuration(); while(1) { if(delayTime++ >=2000000) { delayTime = 0; ADValue = VREF*ADC_GetConversionValue(ADC1)/0x0fff; printf("\r\n ADValue = %.2fv\r\n",ADValue); } } } void GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA , &GPIO_InitStructure); } void ADC_Configuration(void) { ADC_InitTypeDef ADC_InitStructure; RCC_ADCCLKConfig(RCC_PCLK2_Div4); //配置ADC時鐘分頻 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1,&ADC_InitStructure); ADC_RegularChannelConfig(ADC1,ADC_Channel_8,1,ADC_SampleTime_55Cycles5); ADC_Cmd(ADC1,ENABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); ADC_SoftwareStartConvCmd(ADC1,ENABLE); } void RCC_Configuration(void) { /* 定義枚舉類型變量 HSEStartUpStatus */ ErrorStatus HSEStartUpStatus; /* 復(fù)位系統(tǒng)時鐘設(shè)置*/ RCC_DeInit(); /* 開啟HSE*/ RCC_HSEConfig(RCC_HSE_ON); /* 等待HSE起振并穩(wěn)定*/ HSEStartUpStatus = RCC_WaitForHSEStartUp(); /* 判斷HSE起是否振成功,,是則進(jìn)入if()內(nèi)部 */ if(HSEStartUpStatus == SUCCESS) { /* 選擇HCLK(AHB)時鐘源為SYSCLK 1分頻 */ RCC_HCLKConfig(RCC_SYSCLK_Div1); /* 選擇PCLK2時鐘源為 HCLK(AHB) 1分頻 */ RCC_PCLK2Config(RCC_HCLK_Div1); /* 選擇PCLK1時鐘源為 HCLK(AHB) 2分頻 */ RCC_PCLK1Config(RCC_HCLK_Div2); /* 設(shè)置FLASH延時周期數(shù)為2 */ FLASH_SetLatency(FLASH_Latency_2); /* 使能FLASH預(yù)取緩存 */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 選擇鎖相環(huán)(PLL)時鐘源為HSE 1分頻,,倍頻數(shù)為9,則PLL輸出頻率為 8MHz * 9 = 72MHz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* 使能PLL */ RCC_PLLCmd(ENABLE); /* 等待PLL輸出穩(wěn)定 */ while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); /* 選擇SYSCLK時鐘源為PLL */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* 等待PLL成為SYSCLK時鐘源 */ while(RCC_GetSYSCLKSource() != 0x08); } /* 打開APB2總線上的GPIOA時鐘*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOB|RCC_APB2Periph_ADC1, ENABLE); //RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE); } void USART_Configuration(void) { USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge; USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; USART_ClockInit(USART1 , &USART_ClockInitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; USART_Init(USART1,&USART_InitStructure); USART_Cmd(USART1,ENABLE); } #if PRINTF_ON int fputc(int ch,FILE *f) { USART_SendData(USART1,(u8) ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET); return ch; } #endif |
|
來自: 杭州文軒 > 《IT技術(shù)》