本文说明

项目所要实现的功能

  1. 采用轮询模式每隔0.5秒进行ADC采集
  2. 格式化输出采样值和电压值
  3. 在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);     //轮询模式开启ADC
HAL_ADC_Start_IT(&hadc1); //中断模式开启ADC
HAL_ADC_Start_DMA(&hadc1);//DMA模式开启ADC

关闭ADC函数

HAL_ADC_Stop(&hadc1);    //轮询模式关闭ADC
HAL_ADC_Stop_IT(&hadc1); //中断模式关闭ADC
HAL_ADC_Stop_DMA(&hadc1);//DMA模式关闭ADC

读取ADC转换值

HAL_ADC_GetValue(&hadc1);

ADC校准函数(通常在ADC初始化之后加上该函数)

MX_ADC1_Init();                     //ADC初始化
HAL_ADCEx_Calibration_Start(&hadc1);//AD校准 

等待转换结束函数(用于轮询模式)

void HAL_ADC_PollForConversion(&hadc1, 50){//第二个参数为等待时间
//判断转化函数是否结束的条件语句
if(HAL_ADC_PollForConversion(&hadc1,10) == HAL_OK){
	/*User Code*/
}
}

ADC中断回调函数(用于中断模式,中断发生则进入该函数)

void HAL_ADC_ConvCpltCallback(&hadc1){
if(hadc->Instance == ADC1){
	/*User Code*/
}
}

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()函数输出数据信息

/* printf重定向 */
int fputc(int ch ,FILE *f){
	uint8_t temp[1] = {ch};
	HAL_UART_Transmit(&huart1, temp, 1, 2);
	return ch;
}

由于经常使用,这里我们把它写入Keil的Template下,以便随时调用

在这里插入图片描述
新建一个模板,名为"printf",然后编辑代码,如图所示

在这里插入图片描述
还有一点需要注意的,使用fput和fgetc函数达到重定向C语言HAL库输入输出函数必须在MDK的工程选项把“Use MicroLIB”勾选上,如图所示
MicoroLIB是缺省C库的备选库,它对标准C库进行了高度优化使代码更少,占用更少资源。

在这里插入图片描述

自定义转换函数

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);		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

写完了,编译运行生成hex文件即可

Proteus仿真

原理图如下

在这里插入图片描述
注意虚拟终端的连线方式,由于只要输出即可,所以我们只要将TX(PA9端口)连RXD

滑动变阻器如何找到?
在元件库里搜索"POT-HG"即可找到带数显的滑动变阻器,普通款就是"POT"

仿真结果

程序没问题
采样结果一直是0,不知道是为什么

在这里插入图片描述
但是把ADC线直接接电源上却能正常显示

在这里插入图片描述
就很奇怪,希望有人能解答一下,先感谢一下了,困扰好多天了

总结

  1. 学习了ADC的相关概念
  2. 学习与ADC相关的重要函数
  3. 轮询方式和中断方式其实就是阻塞式和非阻塞式,一个等待处理结束再写用户命令,另一个在中断回调函数写用户命令
  4. 本文展示了轮询方式,中断方法就不写了,挺简单的,有空再补
  5. 用具体的项目实现ADC采集,采集的电压其实也不精准

我是爱学习的诸葛铁锤,觉得有用的话点个赞哈,啾咪

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐