STM32 ADC 使用心得分享

01/29 19:18
阅读数 30

作者:螺丝松掉的人

最近对 stm32 的 adc 使用的比较多,也稍微有一点深入,之前都是简单使用,没有过多研究,发现还是有很多很意思的地方,并且一些功能在网上的介绍和使用也是比较少的,就想分享一下自己摸索的过程和思考,有些功能可能我用的也不太对或者有更好的用法,欢迎大家交流

基本功能


我们通过 adc 可以直接读取到电压的大小,通过对读取到的电压进行转换可以获取到电流、温度等模拟信号的数字转换结果。在 stm32 中通常具备 3 个 adc ,每个 adc 又具备十多个通道,每个通道可以对应引脚采集数据(部分通道仅用于采集内部数据,没有引出外部引脚),其中规则通道最多有16路,注入通道最多有4路。有的 adc 之间还可以配置为主从模式,进行交叉采样等更复杂高级的操作,一般电机控制时用的比较多。但是需要注意的是,对于 adc 中的多个通道,一般是不能直接指定通道进行读取的,除非将通道使能为注入模式(稍后介绍)。之前我一般 adc 只会用到 1 个通道,是否指定其实都只能读到那一个通道,所以并没有注意到这个地方。但要写设备驱动就必须要做好通用性,为用户屏蔽好这些比较绕的问题。

规则模式


规则模式(Regular)就是一般的普通模式,也是使用的比较多的。一般可以设置三个寄存器序列,可以根据自己的需要将多个规则通道划分到指定序列中的指定位置,开启 adc 序列转换后,就会开始按顺序对序列中的通道进行扫描转换。单数需要注意的是,每个 adc 只有一个规则数据寄存器,只够存储一个通道的数据,数据是会被覆盖的。也就是说在每个通道的数据读取完成以后,我们需要及时取出,并按顺序进行区分。可以用一个数组去存取转换的数据,之前设定的序列,也就知道的指定通道对应的数据。

一般还可以采用结合 DMA 的方式,在读取到数据后,将数据按顺序进行逐个装填,我们也能得到指定通道顺序的数据。

注入模式


注入模式有点像中断,可以选择多种触发源,也可以用户软件触发,可以直接打断正在进行的规则通道转换。最多可以使能 4 个通道作为注入通道,并且每个通道都具备自己的数据寄存器,不会存在数据覆盖的问题。对于 DMA 资源紧张,不想引入阻塞,不便于维护转换序列时,可以选择采用该模式。

交叉模式


交叉模式需要将两个adc配置为主从关系进行,一般是 ADC1/2,具体可参考官方手册。

注意事项


  • 规则通道数据寄存器只有一个,会存在数据覆盖问题,需要做好数据维护对应工作;

  • 通道使能为注入模式后无法使用连续转换模式;

  • 每个ADC只能使用4个注入模式通道,需要主要资源分配;

  • ADC的数据寄存器不会存在读取到脏数据的情况;


设备驱动对比


接下来分析对比一下主流RTOS的adc设备驱动都是怎么写的,是如何为用户屏蔽好这些比较绕的底层细节的。

RT-Thread

adc初始化设置如下,关闭连续采样模式:

 1
2
3#define ADC1_CONFIG                                                \
4

5    {                                                              \
6
7       .Instance                   = ADC1,                         \
8
9       .Init.DataAlign             = ADC_DATAALIGN_RIGHT,          \
10
11       .Init.ScanConvMode          = ADC_SCAN_DISABLE,             \
12
13       .Init.ContinuousConvMode    = DISABLE,                      \
14
15       .Init.NbrOfConversion       = 1,                            \
16
17       .Init.DiscontinuousConvMode = DISABLE,                      \
18
19       .Init.NbrOfDiscConversion   = 1,                            \
20
21       .Init.ExternalTrigConv      = ADC_SOFTWARE_START,           \
22
23    }
24
25#endif /* ADC1_CONFIG */

均设置为规则通道,并放到同一个序列中:

1ADC_ChanConf.Rank = ADC_REGULAR_RANK_1;

读取函数:(入参有 channel,但并没有用)

 1static rt_err_t stm32_adc_get_value(struct rt_adc_device *device, rt_int8_t channel, rt_uint32_t *value)
2
{
3    ADC_HandleTypeDef *stm32_adc_handler;
4    RT_ASSERT(device != RT_NULL);
5    RT_ASSERT(value != RT_NULL);
6    stm32_adc_handler = device->parent.user_data;
7    /* Wait for the ADC to convert */
8    HAL_ADC_PollForConversion(stm32_adc_handler, 100);
9    /* get ADC value */
10    *value = (rt_uint32_t)HAL_ADC_GetValue(stm32_adc_handler);
11    return RT_EOK;
12}

去adc设备设备驱动看看怎么维护的:

 1static rt_ssize_t _adc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
2{
3    rt_err_t result = RT_EOK;
4    rt_size_t i;
5    struct rt_adc_device *adc = (struct rt_adc_device *)dev;
6    rt_uint32_t *value = (rt_uint32_t *)buffer;
7    for (i = 0; i < size; i += sizeof(int))
8    {
9        result = adc->ops->convert(adc, pos + i, value);
10        if (result != RT_EOK)
11        {
12            return 0;
13        }
14        value++;
15    }
16    return i;
17}

可以看出来就是我们说的第一种方法,所有通道为规则模式,同一转换序列,逐个读取并对按序存储到数组中。

Refer

  • STM32H723/733, STM32H725/735 and STM32H730 Value line advanced Arm®-based 32-bit MCUs - Reference manual

  • 野火]STM32库开发实战指南——基于野火指南者开发板 文档 (embedfire.com)


————————————————

版权声明:本文为RT-Thread论坛用户「螺丝松掉的人」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:

https://club.rt-thread.org/ask/article/3c37ce454d8fecc4.html

———————End——————



👇 点击阅读原文进入官网

本文分享自微信公众号 - RTThread物联网操作系统(RTThread)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部