STM32G431轮询ADC DMA实验总结
一,关于ADC的简单介绍
STM32芯片上的ADC(模数转换器)是一个模拟电路,可以将模拟信号转换为数字信号。这些数字信号可以用来表示被转换的模拟信号值,例如测量温度、光强、压力、电压等。
框图:
二,STM32Cubemx可配置部分参数说明
一,ADC部分
配置参数 可选项
ADCs_Common_Settings (模式选择) |
选lndependent mode 独立模式,同一时刻一个管脚只有一个ADC转换 |
Clock Prescaler (时钟分频) |
选Asynchronous clock mode divided by 1 同异步时钟1分频 |
Resolution (分辨率) |
一般选ADC12-bit resolution (12位分辨率) |
Gain Compensation (增益介质) |
一般选0,校准用的 |
Scan Conversion Mode (扫描模式) |
多通道的时候使能 |
Continuous Conversion Mode (连续转换模式) |
使能后完成当前ADC转换自动开始下一次ADC转换 |
Discontinuous Conversion Mode (不连续转换模式) |
多通道的时候使能,(例子:你使能了4个ADC通道为1-4,使能这个可以做的让1,2先转换,3,4再转换不能单独配置,要配合其他的参数配置) |
DMA Continuous Requests (DMA连续请求) |
使能后DMA完成一次搬运请求后自动开始下一次搬运请求,要配合DMA的循环模式使用 |
Enable Regular Conversions (启用常规转换) |
即规则通道使能 |
Enable Regular Oversampling (启用常规过采样) |
过采样时使用(如12位分辨率变16位时) |
Number Of Conversion (转换数) |
使能的规则通道数量 |
External Trigger Conversion Source (外部触发转换源) |
一般选Regular Conversion launched by software (软件启动的定期转换,即软件触发) |
Rank (规则通道的转换顺序) |
多通道时,按照这个顺序配置进行转换 (如:配置了1-3,从1开始转换一直到3) |
Channel (通道) |
通道相关序号 |
Sampling Time (取样时间) |
选择的时间越大,转换越精准,耗时越长 (1个Cycles为ADC时钟频率的倒数,如 ADC时钟为40MHZ,1Cycles=0.025us) |
Oversampling Right Shift (过采样右移) |
使能过采样可选(如分辨率为16位时右移一位变成15位分辨率) |
Oversampling Ratio (过采样比) |
12位分辨率时选Oversampling ratio 16x 可变为16位分辨率(它们的关系自己类推) |
Regular Oversampling Mode (规则过采样模式) |
一般选Oversampling Continued Mode (过采样连续模式,完成当前的过采样,立即开始下一次) |
Triggered Regular Oversampling (触发规则过采样) |
一般选Single trigger for all oversampled conversions (所有过采样转换的单触发器,触发一次完成所有通道过采样) |
Data Alignment (数据对齐) |
一般选Right alignment (右侧对齐) |
二,MDA部分
配置参数 可选项
DMA Request (DMA请求) |
选择相应的外设 |
Channel (通道) |
选择对应DMA与通道(如:DMA1 Channel 2) |
Direction (方向) |
一般选Peripheral To Memory外设到内存 (也可以是内存到外设,内存到内存,指数据的流向,如ADC的DMA模式就是外设到内存) |
Priority (优先权) |
有高,超高,中低等,越高可以先运行 |
DMA Request Settings DMA(请求设置) |
其下有Mode,lncrement Address,Data Width 参数可配置 |
Mode (模式) |
Normal(搬运完一次需要再次使能) Circular(完成本次搬运离开开始下一次) |
lncrement Address (增值地址) |
Peripheral(使能这个,外设地址自增,一般不使能) Memory (使能这个内存地址自增,即自己写代码时,用数组来存数据时,数据自动逐个放入数组中,一般使能) |
Data Width (数据宽度) |
根据自己的需求选(DAM一次搬多少位数据) 选Half Word半字,即为一次搬16位 |
三,实战
一,单规则通道非DMA
STM32Cubemx配置
以下实验皆为该时钟配置
核心代码:
/*
函数名:MyAdcInit
作用 :进行ADC校准
参数 :无
返回值 ;无
*/
void MyAdcInit(void)
{
//校准
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
}
/*
函数名:AdcGetValue
作用 :获得ADC的值
参数 hadc :ADC的句柄
参数 time :取多少个数进行平均
返回值 temp :返回测到的电压
*/
float AdcGetValue(ADC_HandleTypeDef* hadc,u8 time)
{
float temp=0;
uint32_t value=0;
HAL_ADC_Start(hadc);
//等待通道转换完成
HAL_ADC_PollForConversion(hadc, 10);
for(int i=0;i<time;++i)
{
value+=HAL_ADC_GetValue(hadc);
HAL_Delay(5);
}
value=value/time;
temp = (float)value * (3.3 / 4096);
return temp;
}
使用说明:
将校准函数放入main()函数中初始化的相应位置即可,因为是轮询AdcGetValue()要放入while(1)中一次调用。
二,单规则通道DMA
STM32Cubemx配置
核心代码:
/*-----------------------------------相关变量------------------------------------------*/
#define bufSize 100
uint16_t buf[bufSize]={0};
uint32_t Value=0;
float endValue=0;
/*-----------------------------------相关函数------------------------------------------*/
/*
函数名 :AdcToDmaGetValue
作用 :获取电压值
参数 :无
返回值 :ADC获取的电压
*/
float AdcToDmaGetValue(void)
{
HAL_ADC_Start_DMA(&hadc2,(uint32_t*)buf,bufSize);
//等待DMA搬运完成
while(__HAL_DMA_GET_FLAG(&hdma_adc2,DMA_FLAG_TC1))
{
//hdma_adc2要进行外部声明,cbuemx生成时选分别生产.c .h文件即可在adc.c中找到
__HAL_DMA_CLEAR_FLAG(&hdma_adc2,DMA_FLAG_TC1);
//这个函数是必要的不然标志位查看时会一直卡住
HAL_ADC_Stop_DMA(&hadc2);
}
for(int i=0;i<bufSize;++i)
{
Value+=buf[i];
}
Value/=bufSize;
endValue=(float)Value*(3.3f/4096.0f);
return endValue;
}
/*
函数名 :myAdcToDmaInit
作用 :ADC校准
参数 :无
返回值 :无
*/
void myAdcToDmaInit(void)
{
//校准
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
}
三,多通道DMA
STM32Cubemx配置
核心代码:
/*-----------------------------------相关变量定义---------------------------------------*/
//通道数量
#define TCxNum 2
//每个通道采集的次数
#define TCxCollNumm 20
#define bufSize TCxNum*TCxCollNumm
uint16_t buf[bufSize];
uint32_t sum[2];
float sum0=0,sum1=0;
/*-----------------------------------相关函数-------------------------------------------*/
/*
函数名 :MyAdcToDmaInit
作用 :进行ADC校准
参数 :无
返回值 :无
*/
void MyAdcToDmaInit(void)
{
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
}
/*
函数名 :MyAdcToDmaGetValue
作用 :获取电压值
参数 :无
返回值 :无
*/
void MyAdcToDmaGetValue(void)
{
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)buf,bufSize);
while(__HAL_DMA_GET_FLAG(&hdma_adc1,DMA_FLAG_TC1))
{
__HAL_DMA_CLEAR_FLAG(&hdma_adc1,DMA_FLAG_TC1);
HAL_ADC_Stop_DMA(&hadc1);
}
for(int i=0;i<bufSize;++i)
{
sum[i%2]+=buf[i];
}
sum[0]/=TCxCollNumm;
sum[1]/=TCxCollNumm;
//通道5结果
sum0=sum[0]*(3.3f/4096.0f);
//通道11结果
sum1=sum[1]*(3.3f/4096.0f);
}
四,未完待续
。。。。。。(点击跳转下一篇)
作者:野区萧炎