本帖最后由 xi_liang 于 2014-5-10 00:00 编辑
百为STM32开发板教程之十六——ADC
实验目的:采集百为STM32开发板上的可调电阻分压AD值,把采集到的AD值显示到LCD上
主要内容:
一、STM32的ADC简介
二、STM32的ADC的使用步骤
三、编程实现把采集到的AD值显示到LCD上(非DMA模式)
一、STM32的ADC简介
STM32的ADC是12位的,是逐次逼近型模数转换器。
其中STM32F103ZET6有3个12位ADC,共有23个通道。可测量21个外部通道和2个内部信号源。
图中的引脚名称标注中出现的ADC12_INx(x表示4~9或14~15之间的整数),表示这个引脚可以是ADC1_INx或ADC2_INx。例如:ADC12_IN9表示这个引脚可以配置为ADC1_IN9,也可以配置为ADC2_IN9。同样,图中的引脚名称标注中出现的ADC123_INx(x表示0~3或10~13之间的整数),表示这个引脚可以是ADC1_INx或ADC2_INx或ADC3_INx。
各通道的A/D转换可以是单次、连续、扫描或间断模式的转换。
ADC转换的结果可以以左对齐或右对齐的方式存储在16位数据寄存器中。
ADC的输入时钟是由PCLK2经分频产生的,不得超过14MHz。
ADC结构框图(部分通道未画出):
1.ADC3的规则转换和注入转换触发与ADC1和ADC2的不同
这里要搞清下面几个概念:
(1)规则通道和注入通道
STM32的每个ADC模块通过内部的模拟多路开关,可以切换到不同的输入通道并进行转换。STM32特别地加入了多种成组转换的模式,可以由程序设置好之后,对多个模拟通道自动地进行逐个地采样转换。
有2种划分转换组的方式:规则通道组和注入通道组。通常规则通道组中可以安排最多16个通道,而注入通道组可以安排最多4个通道。
在执行规则通道组扫描转换时,如有例外处理则可启用注入通道组的转换。一个不太恰当的比喻是:规则通道组的转换好比是程序的正常执行,而注入通道组的转换则好比是程序正常执行之外的一个中断处理程序。
再举一个不一定使用的例子:
假如你在家里的院子内放了5个温度探头,室内放了3个温度探头;你需要时刻监视室外温度即可,但偶尔你想看看室内的温度;因此你可以使用规则通道组循环扫描室外的5个探头并显示AD转换结果,当你想看室内温度时,通过一个按钮启动注入转换组(3个室内探头)并暂时显示室内温度,当你放开这个按钮后,系统又会回到规则通道组继续检测室外温度。
从系统设计上,测量并显示室内温度的过程中断了测量并显示室外温度的过程,但程序设计上可以在初始化阶段分别设置好不同的转换组,系统运行中不必再变更循环转换的配置,从而达到两个任务互不干扰和快速切换的结果。可以设想一下,如果没有规则组和注入组的划分,当你按下按钮后,需要从新配置AD循环扫描的通道,然后在施放按钮后需再次配置AD循环扫描的通道。
——————————————
上面的例子因为速度较慢,不能完全体现这样区分(规则组和注入组)的好处,但在工业应用领域中有很多检测和监视探头需要较快地处理,这样对AD转换的分组将简化事件处理的程序并提高事件处理的速度。
(2)单次转换和连续转换,扫描转换和非扫描转换 (扫描转换其实可以理解为循环转换)
实际应用中可以有4种组合:
单次转换+非扫描转换:转换完一个通道即停止
单次转换+扫描转换: 转换完一个通道后,重复转换
连续转换+非扫描转换:按指定的顺序依次转换每个通道,转换完后停止
连续转换+扫描转换: 按指定的顺序依次转换每个通道,转换完后从头开始转换。
二、STM32的ADC的使用步骤
1、开启ADC时钟和GPIO时钟
/* 使能 ADC1 和 GPIOC 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
2、配置PC.04(ADC通道14)
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);
}
3、开启ADC的NVIC中断
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure and enable ADC interrupt */
NVIC_InitStructure.NVIC_IRQChannel = ADC1_2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
4、配置ADC1
/* ADC1 configuration ------------------------------------------------------*/
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描转换关闭
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不用外部事件启动转换
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐为右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //规则通道序列长度为1
ADC_Init(ADC1, &ADC_InitStructure);
5、配置ADC采样时间,转换序列
/* ADC1 regular channels configuration */
ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_28Cycles5); //设置ADC采样时间寄存器1(ADC_SMPR1),设置ADC规则序列寄存器3(ADC_SQR3)
6、使能ADC中断(非DMA方式)
/* Enable ADC1 EOC interupt */
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
7、使能ADC
/* Enable ADC1 */
ADC_Cmd(ADC1, ENABLE);
8、校准ADC
/* Enable ADC1 reset calibaration register */
ADC_ResetCalibration(ADC1);
/* Check the end of ADC1 reset calibration register */
while(ADC_GetResetCalibrationStatus(ADC1));
/* Start ADC1 calibaration */
ADC_StartCalibration(ADC1);
/* Check the end of ADC1 calibration */
while(ADC_GetCalibrationStatus(ADC1));
9、开始ADC转换
/* Start ADC1 Software Conversion */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
10、中断处理
void ADC1_2_IRQHandler(void)
{
/* Clear ADC1 EOC pending interrupt bit */
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
/* Get converted value of Channel14 converted by ADC1 */
ADCConvertedValue = ADC_GetConversionValue(ADC1);
}
三、编程实现把采集到的AD值显示到LCD上(非DMA模式)
/* 初始化LCD */
STM3210E_LCD_Init();
/* Clear the LCD */
LCD_Clear(LCD_COLOR_WHITE);
/* Set the LCD Back Color */
LCD_SetBackColor(LCD_COLOR_BLUE);
/* Set the LCD Text Color */
LCD_SetTextColor(LCD_COLOR_WHITE);
/* 配置SysTick定时器为1ms中断 */
if (SysTick_Config(SystemCoreClock / 1000))
{
/* Capture error */
while (1);
}
while (1)
{
Delay(1000);
sprintf(buffer," adc value = %d ",ADCConvertedValue); //AD转换值存放在全局变量ADCConvertedValue 中,把它格式化转换为字符串显示到LCD上
LCD_DisplayStringLine(LCD_LINE_6, buffer);
}
|