ADC模块是将模拟量转换成数字量,也是多数芯片最常用到的模块。相对于DAC来说,ADC是比较常考的。接下来简单介绍蓝桥杯嵌入式开发板上的ADC模块的使用方法。
ADC的电路连接
蓝桥杯嵌入式的ADC是通过一个电位器的扭转来改变滑动变阻器的阻值,从而测得滑动变阻器的电压。通过PB0的输入得到模拟量,在芯片内部进行ADC的转换。可以将准换后的值显示到LCD液晶显示屏上。
ADC的初始化
ADC的初始化需要用到stm32f10x_adc.c和stm32f10x_adc.h文件。
ADC的初始化函数为
/**
* @说明 ADC时钟源及工作模式配置
* @参数 none
* @返回值 None
*/
void ADC_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
//PB0-ADC channel 8
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOB, &GPIO_InitStructure);
// ADC1 工作模式配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
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_RegularChannelConfig(ADC1, ADC_Channel_8, 1, ADC_SampleTime_13Cycles5);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
}
首先是端口的时钟使能。可以用FCT117E嵌入式竞赛板V1.1\CT117E嵌入式竞赛板\STM32_MCU\stm32f10x_stdperiph_lib\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Examples\ADC\ADC1_DMA中的main.c文件进行修改。源代码是
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
可以将RCC_APB2Periph_GPIOC替换成RCC_APB2Periph_GPIOB。
其次是端口模式的设置。同上的文件,源代码是
/**
* @brief Configures the different GPIO ports.
* @param None
* @retval None
*/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure PC.04 (ADC Channel14) as analog input -------------------------*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
只需将相应的I/O进行修改即可。
最后是ADC工作模式的配置。同上的文件,源代码是
ADC_InitTypeDef ADC_InitStructure;
/* ADC1 configuration ------------------------------------------------------*/
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);
/* ADC1 regular channel14 configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);
/* Enable ADC1 DMA */
ADC_DMACmd(ADC1, ENABLE);
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
/* Enable ADC1 reset calibration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
需要将结构体ADC_InitStructure的元素ADC_ScanConvMode、ADC_ContinuousConvMode 的值变为DISABLE。有兴趣的可以查一查这两个值的作用。如果不改变的话,对ADC的采集影响不大。
其次是改变ADC的通道和采样周期。例程中选择的是通道8,采样周期为ADC_SampleTime_13Cycles5。即将ADC_Channel_14替换成ADC_Channel_8,将ADC_SampleTime_55Cycles5替换成ADC_SampleTime_13Cycles5即可。
因为没有使用到DMA,所以对于DMA的使能函数也就不需要了。即可以删除ADC_DMACmd(ADC1, ENABLE);。ADC_SoftwareStartConvCmd(ADC1, ENABLE);是软件打开ADC的工作,在初始化函数中可以不需要该函数。
ADC的读取和转换
ADC的读取和转换代码为
/**
* @说明 读取ADC转换结果
* @参数 none
* @返回值 ADC_VALUE:ADC转换结果
*/
float Read_ADC(void)
{
float ADC_VALUE;
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
Delay_Ms(5);
ADC_VALUE = ADC_GetConversionValue(ADC1)*3.30/0xfff;
return ADC_VALUE;
}
函数ADC_SoftwareStartConvCmd(ADC1,ENABLE);是软件打开ADC的工作,可以在初始化函数中复制。函数是得到ADC转换后的数字值,定义在stm32f10x_adc.c中的第708行,声明在stm32f10x_adc.h中的第444行。其参数是对ADC的选择,在这里为ADC1。因为ADC的值是实型,所以应用实型变量保存转换后的ADC的值。转换公式是需要自己记忆的,比赛时没有明确的提供。
ADC数字值的显示
例程中ADC的显示代码为
//200毫秒扫描一次ADC
if(ADC_Flag){
ADC_Flag = 0;
adc_temp = Read_ADC();
sprintf((char *)string,"%s%.3f","ADC Value:",adc_temp);
LCD_DisplayStringLine(Line7,string);
}
每200毫秒进行ADC的读取。变量ADC_Flag是ADC读取标志。stm32f10x_it.c文件中对SysTick中断函数的改变成
void SysTick_Handler(void)
{
TimingDelay--;
if(++Ms == 200){
Ms = 0;
ADC_Flag = 1;
}
}
文件开头添加
extern uint8_t ADC_Flag;
uint8_t Ms = 0;
即当变量Ms加到200时表示200毫秒达到,将Ms赋值成0,等待下一个200毫秒的到来。并将采集标志量ADC_Flag置1。采集标志量在main.c文件中的定义为
uint8_t ADC_Flag;
ADC温度采集初始化讲解
该芯片内部有对温度进行采集和转换的电路,所以可以直接利用该ADC得到周围环境的温度,也是基础板唯一一个可以或得温度的模块。但是由于温度是比较难以控制的,所以省赛或国赛一般不会考。但是也不能完全不知道。
因为ADC温度采集的所有工作都是在内部完成,所以不需要任何的I/O口。初始化代码为
/**
* @说明 ADC时钟源及工作模式配置
* @参数 none
* @返回值 None
*/
void ADC_Config(void)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
// RCC_ADCCLKConfig(RCC_PCLK2_Div4);
// ADC1 工作模式配置
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
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_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5);
ADC_TempSensorVrefintCmd(ENABLE); //使能温度传感器
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
}
与普通ADC初始化相比,温度的初始化没有对I/O口时钟和模式选择的设置;也是利用ADC1,所以不能与普通的ADC转换同时使用;采集温度的ADC通道为16,即ADC_Channel_16,采集周期为ADC_SampleTime_239Cycles5。
ADC温度采集读取讲解
与普通ADC采集相比,只是增加了一行公式。其代码为
/**
* @说明 通过ADC计算温度
* @参数 none
* @返回值 tempeeature:温度
*/
float Read_Temperature(void)
{
uint16_t tempdata;
float temperature;
float volt;
// Current Temperature = (V25-Vsensor)/AVG_SLOP + 25
ADC_SoftwareStartConvCmd(ADC1,ENABLE);
// Delay_Ms(5);
tempdata = ADC_GetConversionValue(ADC1);
volt = (tempdata*3.3)/0xfff;
temperature = (1430 - 1000*volt)/4.3 + 25;
return temperature;
}
增加的公式为。同样在比赛的时候没有明确的提示,需要记忆。
ADC温度采集后显示讲解
ADC温度采集后的显示与普通ADC采集后的显示一样,只是显示的变量不一样,即要显示读取函数Read_Temperature返回的值temperature。