STM32开发实战系列5-数模转换器ADC(单通道)
1.ADC简介
1.1.ADC模数转换器是什么
ADC,Analog-to-DigitalConverter的缩写,指模/数转换器或者模数转换器。是指将连续变化的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字形式。模/数转换器可以实现这个功能,在各种不同的产品中都可以找到它的身影。
与之相对应的DAC,Digital-to-AnalogConverter,它是ADC模数转换的逆向过程。
ADC最早用于对无线信号向数字信号转换。如电视信号,长短播电台发接收等。
1.2.ADC模数转换器构成及特点
模数转换器的种类很多,按工作原理的不同,可分成间接ADC和直接ADC。
间接ADC是先将输入模拟电压转换成时间或频率,然后再把这些中间量转换成数字量,常用的有中间量是时间的双积分型ADC。直接ADC则直接转换成数字量,常用的有并联比较型ADC和逐次逼近型ADC。
并联比较型ADC:由于并联比较型ADC采用各量级同时并行比较,各位输出码也是同时并行产生,所以转换速度快是它的突出优点,同时转换速度与输出码位的多少无关。并联比较型ADC的缺点是成本高、功耗大。因为n位输出的ADC,需要2n个电阻,(2n-1)个比较器和D触发器,以及复杂的编码网络,其元件数量随位数的增加,以几何级数上升。所以这种ADC适用于要求高速、低分辩率的场合。逐次逼近型ADC:逐次逼近型ADC是另一种直接ADC,它也产生一系列比较电压VR,但与并联比较型ADC不同,它是逐个产生比较电压,逐次与输入电压分别比较,以逐渐逼近的方式进行模数转换的。逐次逼近型ADC每次转换都要逐位比较,需要(n+1)个节拍脉冲才能完成,所以它比并联比较型ADC的转换速度慢,比双分积型ADC要快得多,属于中速ADC器件。
另外位数多时,它需用的元器件比并联比较型少得多,所以它是集成ADC中,应用较广的一种。双积分型ADC:属于间接型ADC,它先对输入采样电压和基准电压进行两次积分,以获得与采样电压平均值成正比的时间间隔,同时在这个时间间隔内,用计数器对标准时钟脉冲(CP)计数,计数器输出的计数结果就是对应的数字量。双积分型ADC优点是抗干扰能力强;稳定性好;可实现高精度模数转换。主要缺点是转换速度低,因此这种转换器大多应用于要求精度较高而转换速度要求不高的仪器仪表中,例如用于多位高精度数字直流电压表中。
1.3. ADC的作用
采集传感器的数据,测量输入电压,检查电池电量剩余,监测温湿度等。
1.4.ADC的性能指标
量程:能测量的电压范围
分辨率:ADC的分辨率通常以输出二进制数的位数表示,位数越多,分辨率越高,一般来说分辨率越高,转化时间越长。
转化时间:模拟输入电压在允许的最大变化范围内,从转换开始到获得稳定的数字量输出所需要的时间称为转换时间。
1.5.STM32F0-ADC特性
- 12位精度下转换速度可高达1MHz
- 可配置的转换精度:6位,8位,10位,12位
- 转换电压范围:0 ~ 3.6V,V SSA ~ V DDA
- 供电范围:2.4V ~ 3.6V
- 19个转换通道: 16个外部通道、 3个内部通道
- 采样时间可配置
- ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中
1.6.STM32F0-ADC时钟
1.6.1.APB时钟的2或4分频,最高14MHz
优点:不会有时钟域之间的同步带来的抖动,触发事件和转换的起始时刻之间的延迟是确定 的,从 而保证转换之间的时间间隔是固定的
缺点: ADC的转换时间和系统时钟频率相关,受系统频率的影响较大
1.6.2.片上14MHZ HSI RC振荡器
优点:无论MCU的运行频率,都可以保证最高的ADC工作频率可以使用自动节电模式(自动开启或关闭14MHz的内部振荡器)
缺点:触发信号的同步会带来抖动,触发事件和转换的起始时刻之间的延迟不确定
1.7.STM32F0-ADC时钟
1.7.1.APB时钟的2或4分频,最高14MHz
优点:不会有时钟域之间的同步带来的抖动,触发事件和转换的起始时刻之间的延迟是确定 的,从 而保证转换之间的时间间隔是固定的
缺点: ADC的转换时间和系统时钟频率相关,受系统频率的影响较大
1.7.2.片上14MHZ HSI RC振荡器
优点:无论MCU的运行频率,都可以保证最高的ADC工作频率可以使用自动节电模式(自动开启或关闭14MHz的内部振荡器)
缺点:触发信号的同步会带来抖动,触发事件和转换的起始时刻之间的延迟不确定
1.8.STM32F0-ADC通道的选择
19路复用通道
● 16 个从 GPIO 引脚引入的模拟输入 (ADC_IN0...ADC_IN15)
● 3 个内部模拟输入 ( 温度传感、内部参考电压、 VBAT 通道 )
ADC 可以转换一个单一通道或自动扫描一个序列通道。被转换的通道序列必须在通道选择寄存器 ADC_CHSELR 中编程选择:每个模拟输入通道有专门的一位选择位 (CHSEL0...CHSEL18).
1.9.STM32F0-ADC转化时间
可编程采样时间 (SMP)
T Sampling 可配置: SMP[2:0]@ADC_SMPR
需要和外部电路的输入阻抗匹配,采样时间适用于所有通道
转化的时间
T conversion 取决于转换精度: RES[1:0]@ADC_CFGR1
1.10.STM32F0-ADC转化时间
转换时间快速预览表
不需要高转换精度的应用,可以通过降低精确度来提高转换速度
假设ADC模块工作在14MHz的最高工作频率下
1.11.STM32F0-ADC触发方式
软件触发
软件设置ADC_CR的ADSTART=1 时,触发选择有效。
外部事件触发
外部事件 ( 例如:定时器TRGO、输入引脚 ) 触发,可以设置触发源以及触发极性
2.STM32-单通道采集实例(光敏电阻)
2.1实验目标:
利用ADC采集光照传感器的数据,并在中断中获取采集的结果
根据电路板接线图PA4引脚作为ADC读数据信号引脚。
2.2.CubeMX项目建模
新建项目,选择MCU型号STM32F051K8Ux
串口留着要打印输出内容,所以配置一下串口1,波特率115200.
重点是在PA4引脚点击鼠标左键,选择ADC_IN4.
选中ADC配置,NVIC让中断使能。当ADC转换成功后输出一个中断。
输入项目名称,选择IDE是ARM-MDK,然后导出,注意路径中不要包含中文。
导出后系统提示是否打开项目,如果安装了Keil,点击Open会启动Keil编译器
2.3.代码编辑
2.3.1中断使能
在main.c文件初始化的代码中,添加ADC中断使能代码,注意要写在注释BEGIN和END里面,否则CubeMX编辑导出时会丢掉
/* USER CODE BEGIN 2 */
HAL_ADC_Start_IT(&hadc);
/* USER CODE END 2 */
在文件startup_stm32f051x8.s中可以找到中断函数ADC1_COMP_IRQHandler,调转到调用的函数
//D:\makeru\lv16\ADC_IN\MDK-ARM\startup_stm32f051x8.s
DCD ADC1_COMP_IRQHandler ; ADC1, COMP1 and COMP2
//D:\makeru\lv16\ADC_IN\Core\Src\stm32f0xx_it.c
void ADC1_COMP_IRQHandler(void)
{
/* USER CODE BEGIN ADC1_COMP_IRQn 0 */
/* USER CODE END ADC1_COMP_IRQn 0 */
HAL_ADC_IRQHandler(&hadc); //要转到此函的实现处
/* USER CODE BEGIN ADC1_COMP_IRQn 1 */
/* USER CODE END ADC1_COMP_IRQn 1 */
}
//D:\makeru\lv16\ADC_IN\Drivers\STM32F0xx_HAL_Driver\Src\stm32f0xx_hal_adc.c
void HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc)
{
/* Note: into callback, to determine if conversion has been triggered */
/* from EOC or EOS, possibility to use: */
/* " if( __HAL_ADC_GET_FLAG(&hadc, ADC_FLAG_EOS)) " */
#if (USE_HAL_ADC_REGISTER_CALLBACKS == 1)
hadc->ConvCpltCallback(hadc);
#else
HAL_ADC_ConvCpltCallback(hadc);
#endif /* USE_HAL_ADC_REGISTER_CALLBACKS */
}
//D:\makeru\lv16\ADC_IN\Drivers\STM32F0xx_HAL_Driver\Src\stm32f0xx_hal_adc.c
//若函数可以重写
__weak void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(hadc);
/* NOTE : This function should not be modified. When the callback is needed,
function HAL_ADC_ConvCpltCallback must be implemented in the user file.
*/
}
在adc.c中合适的地方重新定义这个方法
/* USER CODE BEGIN 1 */
uint32_t light_value=0;
/**
* @brief Conversion complete callback in non blocking mode
* @param hadc ADC handle
* @retval None
*/
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
light_value = HAL_ADC_GetValue(hadc);
printf("light_value = %d\n", light_value);
}
/* USER CODE END 1 */
main.c里面的主要实现
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f) //
{
while(!(USART1->ISR & (1 << 7)));
USART1->TDR = ch;
}
/* USER CODE END 0 */
////////////////////////////////////////////
/* USER CODE BEGIN 2 */
HAL_ADC_Start_IT(&hadc);
/* USER CODE END 2 */
//////////////////////////////////////////////////////
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(1000);
HAL_ADC_Start_IT(&hadc);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
这样一个光敏传感器输出了。注意的地方就是选择的单次转换,所以每次需要软件方式启动中断
- 点赞
- 收藏
- 关注作者
评论(0)