问题:在蓝桥杯嵌入式学习过程中,在多通道采集PB5、PB11这里遇到了问题.
网上做法大部分都是
非DMA:单次转换+扫描模式+不连续转换+间断模式。然后在代码里面按分配的顺序依次扫描
DMA:单次转换+扫描模式+连续转换。然后在代码里面按分配的顺序依次扫描
需求
如果不DMA的话,在多个通道的情况下,你无法知道当前读取的是哪个通道,扫描过程比较不确定,一旦出现问题,那这次扫描就会出问题。
而DMA的配置又比较麻烦,而且不需要如此高效率,不方便移植和修改。
需要一个在同一个ADC外设的情况下,也能指定读取某个通道的办法。
解决
这里感谢江协科技的思路。
【STM32入门教程-2023版 细致讲解 中文字幕】P22的41:44位置
我使用HAL库成功实现
非DMA:单次转换+非扫描模式
可控制的多通道扫描办法
思路:每次ADC转换将通道修改为对应的读取通道
查看源码,可知,单次扫描的初始化代码中,有配置通道的过程。
既然这样,每次我需要读取其它通道时,就改变需要读取的通道不就行了嘛
如下面ADC初始化源码:
其中红框部分就是ADC初始化的通道初始化,这里指定了通道11。
每次读取ADC值前,将红框部分的代码拿出来用于通道的选择就行了。
具体实现步骤
cubemx配置:
引脚选择
![](https://i-blog.csdnimg.cn/blog_migrate/45ae06737fe0814ab12c1fab040abada.png)
外设配置
外设参数配置
可以看出,这就是单次ADC单通道的的配置。无DMA,无NVIC。
生成工程,打开源码打开void MX_ADC1_Init(void)
应该是这样
红框部分就是我们要借用的代码。
代码实现
下面是最开始的单通道读取代码
//ADC单通道读取,单次转换,非连续,非扫描
double getADC(ADC_HandleTypeDef *pin)
{
unsigned int value;
HAL_ADC_Start(pin);
HAL_ADC_PollForConversion(pin,0xffff);
value = HAL_ADC_GetValue(pin);
return value*3.3/4096;
}
下面是基于单通道优化后的多通道的读取代码:
//ADC多通道读取,单次转换,非连续,非扫描
double getADCByChannel(ADC_HandleTypeDef *pin,unsigned char channel)
{
ADC_ChannelConfTypeDef sConfig = {0}; //建立结构体
if(channel == 11)sConfig.Channel = ADC_CHANNEL_11;//将通道修改为通道11
else if(channel == 5)sConfig.Channel = ADC_CHANNEL_5;//将通道修改为通道5
sConfig.Rank = ADC_REGULAR_RANK_1;//ADC的第一个常规转换
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;//每次转换的采样时间为2.5个时钟周期
sConfig.SingleDiff = ADC_SINGLE_ENDED;//了ADC的输入模式为单端
sConfig.OffsetNumber = ADC_OFFSET_NONE;//不使用偏移校准,下同
sConfig.Offset = 0;
if (HAL_ADC_ConfigChannel(pin, &sConfig) != HAL_OK)//初始化通道和ADC
{
Error_Handler();
}
unsigned int value;
HAL_ADC_Start(pin);//开始转换
HAL_ADC_PollForConversion(pin,0xffff);//等待完成
value = HAL_ADC_GetValue(pin);//读取转换置
HAL_ADC_Stop(pin);//关闭转换
return value*3.3/4096;//返回计算值
}
之后在主函数调用读取
ADC11_value = getADCByChannel(&hadc1,11);//打开ASC1,通道11的电压读取
ADC5_value = getADCByChannel(&hadc1,5);//打开ASC1,通道5的电压读取
读取后通过串口打印还是屏幕显示都可