本文说明
项目所要实现的功能
- 采用轮询模式每隔0.5秒进行ADC采集
- 格式化输出采样值和电压值
- 在ADC转换过程中点亮LED灯
模数转换器(ADC)概述
ADC:Analog-to-Digital Converter 将时间和幅值连续的模拟量转化为时间和幅值离散的数字量 A/D转换一般要经过采样、保持、量化和编码4个过程
ADC性能指标
量程:指ADC所能输入模拟信号的类型和电压范围,即参考电压。信号类型包括单极性和双极性。 转换位数:量化过程中的量化位数n。 A/D转换后的输出结果用n位二进制数来表示。 【例】:10位ADC的输出值就是0~1023。 分辨率:ADC能够分辨的模拟信号最小变化量。计算公式是,分辨率 = 量程 / 2的n次方 【例】:量程为单极性0-5V,8位ADC的分辨率是,5 / 256 = 0.0195V 转换时间:ADC完成一次完整的A/D转换所需要的时间,包括采样、保持、量化、编码的全过程。
ADC数据采样的计算应用
有一个温度测控系统,已知温度传感器在0到100度之间为线性输出,参考电压为5V,采用8为的A/D转换器,0度的时候,测的电压为1.8伏,100度的时候,测的电压为4.3伏。 【问题1】:系统的分辨率是多少? 【问题2】:采集到数据10010001,表示多大电压?温度是多少?
由于温度是线性变化,先求得斜率k,得到温度和电压的关系表达式。 k = (100 – 0)/(4.3-1.8) = 40, y = 40*(x-1.8) (x为采样得到的电压) 由于采用的是8为ADC,参考电压为5V,所以分辨率为: 5 / 256 = 0.0195V = 19.5mV(最小能分辨的电压,分辨率) 0.0195 * 40 = 0.78度(最小能分辨的温度) 因为 10010001B = 91H = 145, 所以 0.0195 * 145 = 2.8275V 该电压信号对应的温度是:(2.83V – 1.8V) * 40 = 41.1摄氏度
HAL库中关于ADC的重要函数
共分为三种:轮询、中断和DMA三种模式 开启ADC函数
HAL_ADC_Start(&hadc1);
HAL_ADC_Start_IT(&hadc1);
HAL_ADC_Start_DMA(&hadc1);
关闭ADC函数
HAL_ADC_Stop(&hadc1);
HAL_ADC_Stop_IT(&hadc1);
HAL_ADC_Stop_DMA(&hadc1);
读取ADC转换值
HAL_ADC_GetValue(&hadc1);
ADC校准函数(通常在ADC初始化之后加上该函数)
MX_ADC1_Init();
HAL_ADCEx_Calibration_Start(&hadc1);
等待转换结束函数(用于轮询模式)
void HAL_ADC_PollForConversion(&hadc1, 50){
if(HAL_ADC_PollForConversion(&hadc1,10) == HAL_OK){
}
}
ADC中断回调函数(用于中断模式,中断发生则进入该函数)
void HAL_ADC_ConvCpltCallback(&hadc1){
if(hadc->Instance == ADC1){
}
}
STM32CubeMX配置ADC
时钟配置 在RCC中选择HSE,配置时钟树 需要注意的是为确保转化精确度,ADC的时钟不能超过14MHz 如图是ADC Prescaler(ADC预分频器,ADC模块的时钟来源)是12MHz 当然你配置的一旦超过14MHz,STM32CubeMX会报错
ADC配置 如图进行配置,ADC选择通道1,自动配置PA1,其他Setting用默认的即可
简单介绍一下有用的参数 Mode——Independent mode 即独立模式,每个ADC独立工作,好像就看到这一个选项。。。 Data Alignment (数据对齐方式) 一般选择右对齐,除非有特殊要求 Scan Conversion Mode( 扫描模式 ) 用到多个通道会自动设置为ENABLE Number OF Conversion(转换通道数) 用到几个通道就选几,默认自然是1 Continuous Conversion Mode(连续转换模式) 连续不连续的区别在于多个数据转化是全部转换完成再停止,还是转换一个停一下,等待下一个触发转化命令 Rank——Sampling Time(采用周期),默认1.5个周期,不知道干嘛用
其他常规配置就不再赘述,可以看我之前的博客 生成代码即可
Keil代码编辑
由于只需要输出,不需要输入,所以就不用串口收发函数了 这里用printf()函数输出数据信息
int fputc(int ch ,FILE *f){
uint8_t temp[1] = {ch};
HAL_UART_Transmit(&huart1, temp, 1, 2);
return ch;
}
由于经常使用,这里我们把它写入Keil的Template下,以便随时调用
新建一个模板,名为"printf",然后编辑代码,如图所示
自定义转换函数
void ADC_TO_VOL()
{
HAL_ADC_Start(&hadc1);
LED_ON;
if(HAL_ADC_PollForConversion(&hadc1,10) == HAL_OK)
{
ADC_Value = HAL_ADC_GetValue(&hadc1);
}
printf("ADC 采样值: %d, 电压值: %.4fV \r\n",ADC_Value,ADC_Value*3.3f/4096);
LED_OFF;
}
注意用printf()函数时,要引入stdio.h文件
#include "stdio.h"
然后我们在main函数while循环里写入代码即可,如下所示
while (1)
{
ADC_TO_VOL();
HAL_Delay(500);
}
写完了,编译运行生成hex文件即可
Proteus仿真
原理图如下
注意虚拟终端的连线方式,由于只要输出即可,所以我们只要将TX(PA9端口)连RXD
滑动变阻器如何找到? 在元件库里搜索"POT-HG"即可找到带数显的滑动变阻器,普通款就是"POT"
仿真结果
程序没问题 采样结果一直是0,不知道是为什么
但是把ADC线直接接电源上却能正常显示
就很奇怪,希望有人能解答一下,先感谢一下了,困扰好多天了
总结
- 学习了ADC的相关概念
- 学习与ADC相关的重要函数
- 轮询方式和中断方式其实就是阻塞式和非阻塞式,一个等待处理结束再写用户命令,另一个在中断回调函数写用户命令
- 本文展示了轮询方式,中断方法就不写了,挺简单的,有空再补
- 用具体的项目实现ADC采集,采集的电压其实也不精准
我是爱学习的诸葛铁锤,觉得有用的话点个赞哈,啾咪
|