【CubeIDE】STM32 HAL库史上最详细教程(二):单/多通道ADC读取电压

0x00前言

小葵花妈妈课堂:

   由ST数据手册AN4195可知STM32 F1 F3系列ADC为12bit精度的逐级逼近式ADC,属于中速ADC,F1系列拥有16个外部单端输入,而F3系列有15个外部单端/差分ADC和三个内部通道。

学习内容:

      1.轮询方式单通道ADC读取电压

      2.中断方式单通道ADC读取电压

      3.DMA方式单通道ADC读取电压

      4.DMA方式多通道ADC读取电压

      5.STM32 ADC工作模式介绍

      6.STN32 HAL库相关ADC函数

使用硬件:

      1.F103C8T6核心板

      2.光敏电阻模块(可选)

 

0x01软件配置

1.配置外部晶振

配置时钟树(根据自己板子情况而定)

2.配置SW Debug接口

     注:因为博主ADC选的是IN0通道,占用了PA0,所以 System Wake-UP 就无法选中,如果需要 System Wake-UP  可以使用其他的ADC通道

3.配置USART串口

如果对HAL库串口操作不是很了解。可以参考我的上一篇博客:

【CubeIDE】STM32 HAL库史上最详细教程(一):UART串口收发

3.配置ADC (单通道)

 

0x02 模式讲解

  • 间断/连续模式:

       1.如果开启间断模式,每次需要先使用HAL_ADC_Start()或HAL_ADC_Start_IT(),HAL_ADC_Start_DMA()下文不再赘述)启动转换,需要使用HAL_ADC_PollForConversion()等待转换完成,HAL_ADC_GetState()获取ADC转换状态(若返回值为HAL_OK说明转换完成),转换完成后使用HAL_ADC_GetValue()读取ADC原始值,读取完成后,使用HAL_ADC_Stop()停止转换,如需再次获取ADC数据,需重复执行上述步骤。

      2.间断模式的缺点很明显:麻烦~  优点就是节省系统资源,安全性更高,而间断模式会不断抛出DMA,IT中断,导致系统安全性降低~

      3.如果开启连续模式,只需要使用一次HAL_ADC_Start(),开启转换,ADC会马不停蹄的电压转换成数字量,用户只需要调用HAL_ADC_GetValue(),读取ADC原始值

      4.连续模式的优缺点和间断模式真好相反~

  • 扫描模式(开启/关闭)

     1.如果设置了多个ADC转换通道(不是勾选的通道数量,是Number Of Conversion里配置的数量),扫描模式自动开启,且无法关闭,如果只有一个转换通道,则扫描模式默认关闭,且无法开启。

     2.假设开启了扫描模式,且RANK1 RANK2 RANK3分别对应IN3 IN2 IN1 通道,则转换一次通道顺序为IN3 IN2 IN1

 

0x03 ADC单通道采样

(模式:间断模式   非扫描模式)

1.重定向 printf(),不清楚怎么操作见上一篇博客

【CubeIDE】STM32 HAL库史上最详细教程(一):UART串口收发

#include "stdio.h"

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1,100);
    return ch;
}

2.打开浮点数转义,CubeIDE 默认不支持浮点数类型进行字符转义(这里困扰了我很久~)

选项目->属性(CubeIDE下拉框没法截图QAQ)

一定要记得点应用啊喂~

3.串口打印电压值

    定义两个变量,分别用于储存原始值和转换完的电压值

    这里要插一嘴,stm32f1系列是12bit ADC,所以转换完是12位的无符号整型,C语言中没有能够12bit的数据类型,所以取最节省系统资源又能保持数值不变的uint16_t (就是unsigned short)类型,由于ADC采样电压范围是0-3.3v,采样值呈线性分布,假设ADC转换值为Ax 那么实际电压就等于 Ax * 3.3 / 2 ** 12 即  Ax * 3.3 / 4096

串口打印电压值

运行结果

4.使用连续采样模式打印电压值

使能连续模式

别忘了生成代码~

在原来的基础上修改代码

运行结果

5.中断方式读取电压值

(模式:连续模式  非扫描模式)

使能ADC全局中断

在原有的基础上修改代码

运行结果

6.DMA方式读取电压值

(模式:连续模式 非扫描模式)

配置DMA

增大转换周期

CubeIDE默认配置1.5Cycles的转换周期,导致DMA触发的中断干扰CPU导致串口无法正常发送数据。

解决方法有二,一者取消DMA中断,但CubeIDE 图形化配置中 DMA全局中断无法取消,网上有很多大佬通过修改DMA初始化代码取消DMA中断,这样既麻烦还会影响到其他需要DMA的外设,所以博主采取第二种方法,即增大转换时间

如果有不信邪的小伙伴可以试试用默认的1.5Cycles~

在原来的基础上修改代码

运行结果

 

0x04 ADC DMA方式多通道采样

    由数据手册可知,F1和F3系列ADC外设用于储存数据的ADC_DR只有16bit,所以一个ADC配置多个通道的时候,下一个通道的转换数据就会覆盖这次的数据,如果DMA方式进行多通道读取数据就可以解决这个问题(具体怎么个原理我也不知道),所以本文只讨论DMA方式ADC多通道读取数据。 

1.配置 ADC多通道

2.定义用于储存 电压和的ADC原始值的变量

Tip: 多通道ADC转换顺序跟RANK有关,详见SCAN模式讲解部分

3.添加代码

运行结果

0xFF 完

既然都看完了,点个赞吧

  • 233
    点赞
  • 576
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
stm32hal库提供了多通道ADC的源码实现。下面是一个简要的示例代码,用于配置和读取STM32微控制器的ADC多通道输入。 首先,我们需要在主函数中初始化ADC模块。假设我们使用的是STM32F4系列的微控制器,并且要使用ADC1和ADC2两个通道: ```c #include "stm32f4xx.h" void ADC_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_ADC2, ENABLE); ADC_InitTypeDef ADC_InitStruct; ADC_CommonInitTypeDef ADC_CommonInitStruct; ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; ADC_InitStruct.ADC_ScanConvMode = ENABLE; ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStruct.ADC_NbrOfConversion = 2; ADC_Init(ADC1, &ADC_InitStruct); ADC_Init(ADC2, &ADC_InitStruct); ADC_CommonInitStruct.ADC_Mode = ADC_Mode_Independent; ADC_CommonInitStruct.ADC_Prescaler = ADC_Prescaler_Div2; ADC_CommonInitStruct.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; ADC_CommonInitStruct.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStruct); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_84Cycles); ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_84Cycles); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_Cmd(ADC2, ENABLE); ADC_SoftwareStartConv(ADC1); } ``` 接下来,我们可以编写一个ADC读取函数,以获取ADC转换结果: ```c uint16_t ADC_Read(uint8_t channel) { ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_84Cycles); ADC_SoftwareStartConv(ADC1); while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); return ADC_GetConversionValue(ADC1); } ``` 通过调用ADC_Init()函数进行初始化,我们可以开始对ADC通道进行读取了。例如,我们希望读取ADC1的通道0和ADC2的通道1两个通道: ```c int main(void) { ADC_Init(); uint16_t result1 = ADC_Read(ADC_Channel_0); uint16_t result2 = ADC_Read(ADC_Channel_1); // result1为ADC1的通道0的转换结果 // result2为ADC2的通道1的转换结果 while(1); } ``` 这样,我们就可以使用stm32hal库来实现ADC多通道读取。注意,以上代码只是一个示例,实际应用中可能需要根据具体需求进行更多的配置和处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值