STM32入门指南(5)—ADC的使用
文章目录
前言
本文以STM32F103ZET6为例,介绍STM32的ADC如何在STM32CubeMX中配置,以及一些代码上的说明。主要是针对如何用ADC采集分析信号。
硬件:
一块STM32F103ZET6开发板
软件:
- MDK 532
- STM32CubeMX 6.0.1
该芯片的数据手册可以从ST的官网下载到:
ADC简要介绍
这里借鉴一下CSDN上的博客:
https://blog.csdn.net/as480133937/article/details/99627062
https://blog.csdn.net/qq_38410730/article/details/80071349
STM32 拥有 1~3 个 ADC(STM32F101/102 系列只有 1 个 ADC),这些 ADC 可以独立使用,也可以使用双重模式(提高采样率)。STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。
STM32F103 系列最少都拥有 2 个 ADC,我们选择的 STM32F103RCT 包含有 3 个 ADC。STM32 的 ADC 最大的转换速率为 1Mhz,也就是转换时间为 1us(在 ADCCLK=14M,采样周期为 1.5 个 ADC 时钟下得到),不要让ADC 的时钟超过 14M,否则将导致结果准确度下降。
STM32 将 ADC 的转换分为 2 个通道组:规则通道组和注入通道组。规则通道相当于你正常运行的程序,而注入通道呢,就相当于中断。在你程序正常执行的时候,中断是可以打断你的执行的。同这个类似,注入通道的转换可以打断规则通道的转换, 在注入通道被转换完成之后,规则通道才得以继续转换。
ADC主要特性
- 12位逐次逼近型的模拟数字转换器;
- 最多带3个ADC控制器,可以单独使用,也可以使用双重模式提高采样率;
- 最多支持23个通道,可最多测量21个外部和2个内部信号源;
- 支持单次和连续转换模式;
- 转换结束,注入转换结束,和发生模拟看门狗事件时产生中断;
- 通道0到通道n的自动扫描模式;
- 自动校准;
- 采样间隔可以按通道编程;
- 规则通道和注入通道均有外部触发选项;
- 转换结果支持左对齐或右对齐方式存储在16位数据寄存器;
- ADC转换时间:最大转换速率 1us(最大转换速度为 1MHz ,在ADCCLK=14M,采样周期为1.5个ADC时钟下得到);
- ADC供电要求:2.4V-3.6V;
- ADC输入范围:VREF- ≤ VIN ≤ VREF+。
ADC通道映射
STM32F103带3个ADC控制器,一共支持23个通道,包括21个外部和2个内部信号源。ADC1控制器最多有18个通道,包括16个外部和2个内部信号源。
ADC1和ADC2的16个外部通道相同,且ADC1和ADC2共用一个系统中断向量,ADC1不支持DMA,ADC2不支持DMA。可以配置ADC1和ADC2采集同一个通道的信号,达到单个ADC两倍的采样率。
ADC3的中断有自己的中断向量, 可以配置DMA。
通道 | ADC1 | ADC2 | ADC3 |
---|---|---|---|
0 | PA0 | PA0 | PA0 |
1 | PA1 | PA1 | PA1 |
2 | PA2 | PA2 | PA2 |
3 | PA3 | PA3 | PA3 |
4 | PA4 | PA4 | PF6 |
5 | PA5 | PA5 | PF7 |
6 | PA6 | PA6 | PF8 |
7 | PA7 | PA7 | PF9 |
8 | PB0 | PB0 | PF10 |
9 | PB1 | PB1 | |
10 | PC0 | PC0 | PC0 |
11 | PC1 | PC1 | PC1 |
12 | PC2 | PC2 | PC2 |
13 | PC3 | PC3 | PC3 |
14 | PC4 | PC4 | |
15 | PC5 | PC5 | |
16 | 内部温度 | ||
17 | 内部参考电压 |
ADC数据对齐
规则组的ADC有两种数据对齐方式: (一般采用右对齐)
-
左对齐
b15 b14 b13 b12 b11 b10 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 d11 d10 d9 d8 d7 d6 d5 d4 d3 d2 d1 d0 -
右对齐
b15 b14 b13 b12 b11 b10 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 d11 d10 d9 d8 d7 d6 d5 d4 d3 d2 d1 d0
ADC转换模式
下面介绍几种常用的ADC转换模式。
-
单次转换
单个通道,ADC只执行一次转换,然后停止。
可以设置为软件启动或者外部触发启动。
如果设置了中断,转换完成会产生中断。 -
连续转换
单个通道,ADC只执行多次转换。
可以设置为软件启动或者外部触发启动。
如果设置了中断,每一个转换完成都会产生中断。 -
扫描模式
多个通道,ADC按顺序对每一个通道都执行一次单次转换。这里的通道分为两个组: 规则组 和 注入组。
默认执行转换规则组,当注入通道的触发转换时,会打断规则组的转换。
如果设置了中断,所有通道转换完成会产生中断。 -
连续扫描模式
多个通道,ADC对选中通道执行多次扫描模式。
如果设置了中断,所有通道每完成一次转换会产生一次中断。
ADC转换时间
总转换时间如下计算:
Tconv = 采样时间 + 12.5 个周期
例如:当ADCCLK = 14 MHz,采样时间为 1.5 周期时,TCONV = 1.5 + 12.5 = 14周期 = 1μs。
故而,ADC的最小采样时间1μs(ADC时钟=14MHz,采样周期为1.5周期下得到)。
ADC配置及代码解析
1. ADC单通道采样
使用ADC采样单个通道的信号,一般用来采样电压信号或者内部温度信号。
-
在 CubeMX 配置如下:
-
选择通道
-
独立模式(ADC1和ADC2单独运行)
-
数据右对齐
-
使能规则通道,通道数一个,为通道0,采样周期1.5个。
-
对于上面的几个参数稍微解释一下:
-
mode
- 独立模式:ADC1和ADC2独立运行
- 双ADC模式:ADC1和ADC2协同运行,如果同时采一个通道的信号,可以达到单个ADC采样速度的2倍
-
data alignment
- 左对齐
- 右对齐
-
scan coversion mode
- 扫描转换模式,当有多个规则组通道时会自动使能
-
continuous coversion mode
- 连续转换模式,对单个或多个通道按照顺序执行转换,不会主动停下
-
discontinuous coversion mode
- 非连续转换模式,在使能扫面模式的情况下,允许使能该选项,同时需要配置扫描转换的次数,相当于上面的连续转换模式增加了一个次数限制
-
enable regular conversion
- 使能规则转化组
-
number of conversion
-
规则转化组的通道数,下面是对每一个通道的配置
-
rank 顺序
-
channel 通道号
-
sampling time 转换时间
-
-
-
enable injected conversion
- 注入组转换使能,使用较小,请读者自行研究
- 在MDK中,main函数添加代码: (只展示关键的部分)
int main(void)
{
//Initial Code
HAL_ADCEx_Calibration_Start(&hadc1); //ADC校准
uint16_t i;
for( i = 0; i < 100; i++ ) //采集100次数据,每次间隔10ms
{
uint32_t val;
HAL_ADC_Start(&hadc1); //ADC启动转换
HAL_ADC_PollForConversion(&hadc1,10); //等待ADC转换完成,最大等待时间10ms
val = HAL_ADC_GetValue(&hadc1); //读取ADC
//printf("%d\r\n",val);
HAL_Delay(10);
}
HAL_ADC_Stop(&hadc1); //停用ADC
while (1);
}
2. ADC单通道 + TIMER + DMA
使用ADC采样单个通道的信号,用定时器控制采样频率,并用DMA进行数据传输,释放CPU资源。
-
在CubeMX配置如下:
-
选择通道
-
独立模式
-
数据右对齐
-
使能规则通道,通道数一个,外部触发采样设置为定时器3的触发输出事件,通道 0 采样周期 1.5 个。
-
添加DMA通道,模式为Normal,内存地址递增,数据半字传输(16 bit )
-
配置定时器,触发输出选择 Update Event
定时器触发频率为
F t r i g g e r = F s o u r c e C K D ∗ ( P S C + 1 ) ∗ ( R e l o a d + 1 ) Ftrigger = \frac{Fsource}{CKD*(PSC+1)*(Reload+1)} Ftrigger=CKD∗(PSC+1)∗(Reload+1)Fsource
-
- 在MDK中,main函数添加代码:
uint16_t data[1024];
volatile uint8_t ADC1_ConvCplt_Flag = 0; //转换完成标志位
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) //转换完成回调函数
{
if(hadc->Instance == ADC1) //ADC1转换完成,置标志位为1
ADC1_ConvCplt_Flag = 1;
}
int main(void)
{
//Initial code
HAL_ADCEx_Calibration_Start(&hadc1); //ADC校准
HAL_TIM_Base_Start(&htim3); //定时器启动
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)data,1024); //ADC开始转换,通过DMA传输,长度为1024
while(!ADC1_ConvCplt_Flag); //等待转换完成
ADC1_ConvCplt_Flag = 0; //清除标志位
uint32_t i; //串口输出显示
for(i = 0; i< 1024 ;i++)
printf("X1=%d\r\n",data[i]);
while(1);
}