实例
通过配置 ADC,采集 R37 电位器的电压,并显示到 LCD 显示屏上。
电路分析
该电位器的可调端接到了 M PB0 引脚,查阅 STM32F1 系列数据手册,PB0 引脚可复用为 ADC12_IN8。
工程建立
本次工程在上一次的工程上继续修改,复制上一次的工程作为本次的工程基础。
添加库函数
本例中使用到了 ADC 采集功能,故要添加以下库函数:
初始化 ADC1
将 PB0 配置为模拟输入,使能 PB 和 ADC1 时钟,配置 ADC 参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| void ADC1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_ADC1,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; ADC_InitStructure.ADC_ContinuousConvMode=DISABLE; 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_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); }
|
特别提醒
在初始化 ADC 的时候,需要注意以下两点:
- RCC_ADCCLKConfig (RCC_PCLK2_Div6); 这条语句的用于降低 ADC 采集速度,其作用实际上就是对 ADC 时钟进行 6 分频,提升 AD 采集的精确度。
- 在进行 ADC 校准前,一定要先使能 ADC,再进行校准,否则会导致程序在校准的地方卡死。
获取 ADC 数据
初始化完成后,通过软件触发 AD 转换的方式获取 AD 值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| u16 ADC_Get(u8 channel) { u16 temp; ADC_RegularChannelConfig(ADC1,channel,1,ADC_SampleTime_239Cycles5); ADC_SoftwareStartConvCmd(ADC1,ENABLE); while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==0); temp=ADC_GetConversionValue(ADC1); ADC_SoftwareStartConvCmd(ADC1,DISABLE); return temp; }
|
定义全局变量 ADC_Flag 作为触发标志:
修改定时器 1 中断,配置为每 500ms 触发一次 AD 转换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void TIM1_UP_IRQHandler(void) { static u16 cnt=0,adc_cnt=0; if(TIM_GetITStatus(TIM1,TIM_IT_Update)==SET) { TIM_ClearITPendingBit(TIM1,TIM_IT_Update); if(++cnt>=50) { cnt=0; Flag50ms=1; if(++adc_cnt>=10) { adc_cnt=0; ADC_Flag=1; } } } }
|
结果处理和显示
此时我们可以通过调用 u16 ADC_Get (u8 channel); 来获取 AD 采集到的数字量,查阅手册可知,STM32F103RBT6 的 ADC 精度为 12 为,也就是 即采集到的 AD 数字量在 0-4096 之间,当板载参考电压为 3.3V 时,每 1 数字量对应的电压为 。若要显示电压值,则应修改主程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| int main(void) { float ADC_Value=0;
SysTick_Config(SystemCoreClock/1000); Delay_Ms(200);
STM3210B_LCD_Init(); LCD_Clear(Black); LCD_SetBackColor(Black); Timer1_Init(); LED_Init(); Key_Init();
ADC1_Init(); LCD_SetTextColor(White); LCD_DisplayStringLine(Line1,(u8*)" Welcome!");
while(1) { if(Flag50ms) { Flag50ms=0; Key_Scan(); } sprintf((char*)Display_String," LED1-I/O:%d",L1_Status); LCD_SetTextColor(Blue); LCD_DisplayStringLine(Line2,Display_String); if(ADC_Flag) { ADC_Flag=0; ADC_Value=ADC_Get(8)*3.3/4096; sprintf((char*)Display_String," ADC:%.2fV",ADC_Value); LCD_DisplayStringLine(Line3,Display_String); } } }
|
下载测试
将程序下载到开发板,可以看到第三行显示了 ADC 采集到的 R37 的电压值,调整电位器,显示的数值随调整发生改变。