前期准备:
- STM32CubeMX
- STM32RCT6核心板
- IDE Keil(MDK-ARM)
STM32CubeMX部分
1. 配置时钟
选择STM32F103RCTx系列芯片,配置时钟的同时会自动配置IO口引脚
将HCLK设置为最大频率72MHz
2. 配置ADC
什么是ADC?
ADC即模拟数字转换器(Analog-to-digital converter)是用于将模拟形式的连续信号转换为数字形式的离散信号的一类设备。一个模拟数字转换器可以提供信号用于测量。与之相对的设备成为数字模拟转换器。
简单来说就是将看不见摸不着的数据转换成我们能直观看到感受到的数字
比如空气中的温度、湿度。
你真的知道周围空气中真实的温度和湿度吗?你了解到的温度无非是温度计、手机上看到的数字,原来人体的温度是37°,37°是这么个感觉
12位ADC:
12位ADC是一种逐次逼近型模拟数字转换器。它有,3个ADC控制器,多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。
12位ADC, 即212 = 4096, 也就是说你希望采集到的量被分成了4096份,根据测出的ADC值即可推出实际的值
例:一节电池的最大电压为3V,现在用了一些电,我不知道还剩多少电,我用12位ADC测一下,测得的ADC值为2048。3V被分成了4096份,现在还剩2048份,也就是现在还剩1.5V
实际电压 = ( 测得的ADC / 4096 ) * 3 V
3个ADC:
STM32共有3个ADC:
ADC1
ADC2
ADC3
18个输入通道:
16个外部通道,2个内部通道
ADC的转换模式:
1 单次转换模式: 只执行一次转换
2 连续转换模式: 转换结束之后马上开始新的转换
3 扫描模式: 对所有所选中的通道进行转换
4 间断模式: 触发一次,转换一个通道
总结:
- 只有一个ADC通道,并且这个通道只转换一次,选择单次转换模式
- 只有一个ADC通道,需要连续转换,选择连续转换模式
- ADC通道多于一个,并且所有的通道只转换一次,选择单次转换模式,同时使能扫描模式
- ADC通道多于一个,需要连续转换,选择连续转换模式,同时使能扫描模式
- 假如有4个通道需要转换,设定扫描模式+连续转换,那么顺序是ch0->ch1->ch2->ch3->ch0->ch1…这个过程无法被打断。如果我希望通道之间转换有可调的时间间隔,那么就引入间断模式(有点类似中断的意思)
左/右对齐:
ADC数据是12位精度的,但是数据是存储在 16 位数据寄存器中,所以ADC的存储结果可以分为左对齐或右对齐两种方式
ADC输入电压范围:
因为ADC是采集的模拟信号,电压不能过大,基本上都是在 0~3.3V
注入通道,规则通道:
- 注入通道:
程序正常运行的通道 - 规则通道:
注入通道可以打断规则通道,如果在规则通道转换过程中,有注入通道进行转换,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程(类似于中断)
ADC时钟:
- ADC模块的时钟来源是ADC预分频器的ADCCLK
- RCC控制器为ADC时钟提供一个专用的可编程预分频器。 分频因子由RCC_CFGR的ADCPRE[1:0]配置,可配置2/4/6/8分频
- STM32的ADC最大的转换速率为1MHz,也就是说最快转换时间为1us,为了保证ADC转换结果的准确性,ADC的时钟最好不超过14M
触发转换:
- 外部触发:ADC_CR2 的ADON控制 ;定时器捕获;EXIT
- 中断触发:规则 / 注入通道转换结束(转换完一次即进入中断);模拟看门狗状态位被设置(当转换的模拟电压值低于低阈值或高于高阈值时,便会产生中断。阈值的高低值由ADC_LTR和ADC_HTR配置)
- DMA触发:规则 / 注入通道转换结束后会产生DMA请求(只有ADC1和ADC3可以)
下面就以ADC1_IN3 PA3 引脚为例
选择PA3的ADC1_IN3,然后才可以设置ADC的时钟
ADC时钟超过14M会报错
然后配置ADC参数
- ADCs_Common_Settings(ADC模式设置): ADC_Mode_Independent(独立模式):
不需要ADC同步或者只是用了一个ADC的时候,设成独立模式,多个ADC同时使用时会有其他模式,如双重ADC同步模式,两个ADC同时采集一个或多个通道,可以提高采样率 - Data Alignment (数据对齐方式): 右对齐
- Scan Conversion Mode( 扫描模式 ) : DISABLE
- Continuous Conversion Mode(连续转换模式): ENABLE
- Discontinuous Conversion Mode(间断模式): DISABLE
- Enable Regular Conversions (启用常规转换模式): ENABLE
- Number OF Conversion(转换通道数):1(用到几个通道就设置为几)
- Extenal Trigger Conversion Source (外部触发转换源):
Regular Conversion launched by software(规则的软件触发,调用函数触发即可)
Timer X Capture Compare X event (外部引脚触发)
Timer X Trigger Out event (定时器通道输出触发) - Rank(转换顺序):
可以修改通道采样时间、每个通道的转换顺序(多个通道时),这里默认即可
ADC转换时间 = 采样时间 + 12.5个周期
例:ADCCLK(ADC时钟)=14MHz(最大),采样时间为1.5Cycles(最快),ADC转换时间 = 1.5 + 12.5 = 14周期 = 1us
- ADC注入通道设置: 与规则通道一致
- Enable Analog WatchDog Mode(使能模拟看门狗中断): 不勾选
3. 配置USART
配置USART有讲过,这里和下面涉及USART的知识点快进不再讲解,不了解的具体请看
【STM32】HAL库 CubeMX例程三—串口中断通信(2)(附工程源码)
4. 工程生成
工程管理依旧是这几个选项,然后GENERATE CODE,STM32CubeMX部分完成。
MDK 5部分
//ADC函数
• HAL_ADC_Start(&hadcx); //轮询模式开启ADC
• HAL_ADC_Start_IT(&hadcx); //中断轮询模式开启ADC
• HAL_ADC_Start_DMA(&hadcx); //DMA模式开启ADC
• HAL_ADC_Stop() //轮询模式关闭ADC
• HAL_ADC_Stop_IT() //中断轮询模式关闭ADC
• HAL_ADC_Stop_DMA() //DMA模式关闭ADC
• HAL_ADCEx_Calibration_Start(&hadcx); //ADC校准函数
• HAL_ADC_GetValue() //读取ADC转换值
• HAL_ADC_PollForConversion(&hadc1, 50); //等待转换结束函数,50为等待时间(ms)
• HAL_ADC_ConvCpltCallback() //ADC中断回调函数,转换完成后回调,DMA模式下DMA传输完成后调用
• HAL_ADC_ConfigChannel() //配置规则组通道
• HAL_ADC_AnalogWDGConfig() //看门狗配置
首先在stm32f1xx_hal.c中重写fgetc和fputc函数
/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx_hal.h"
#include <stdio.h>
extern UART_HandleTypeDef huart1;
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
接着在main.c文件定义一个变量
/* USER CODE BEGIN PTD */
uint16_t ADC_Value; //ADC值
/* USER CODE END PTD */
在ADC初始化之后加上AD校准函数
MX_ADC1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_ADCEx_Calibration_Start(&hadc1); //AD校准
/* USER CODE END 2 */
接着在while里写
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_ADC_Start(&hadc1); //启动ADC转换
HAL_ADC_PollForConversion(&hadc1, 50); //等待转换完成,时间为50ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
ADC_Value = HAL_ADC_GetValue(&hadc1); //获取AD值
printf("ADC1 读取 : %d \r\n",ADC_Value);
printf("PA3 实时电压 : %.4f \r\n",ADC_Value*3.3f/4096);
}
HAL_Delay(1500);
}
/* USER CODE END 3 */
编译下载时需要选择相对应的下载器,勾选以下
运行即可
当我旋转PA3脚的电位器(旋转即改变电压)