文章目录
STM32 HAL库 CUBEMX配置 ADC采集 软硬件型号 1.单通道不定时任意时刻采集信号 CUBEMX配置 代码添加 2.单通道ADC采集+DMA传输 CUBEMX添加配置 代码添加 3.定时器触发转换(1khz)+DMA传输 CUBEMX配置 代码添加 采集频率满足条件STM32 HAL库 CUBEMX配置 ADC采集
软硬件型号
正点原子阿波罗STM32F428IG开发板
STM32CUBEMX+KEIL5编程
STM32F4 1.24.2 库版本
1.单通道不定时任意时刻采集信号
CUBEMX配置
1.打开RCC
2.配置时钟树
3.选择ADC通道
4.使能持续转换
5.开启中断
简单说一下这个配置,
Clock Prescaler 时钟预分频 为保证采集精度最好使分频后时钟在36Mhz以下 Resolution 分辨率 有8位,10位,12位的,这里选择最高的就行 Date Alignment 数据对齐方式 我们ADC转换后的数据存在寄存器中,12位的,这12位是左对齐右对齐都行 Scan Conversion Mode 扫描模式,当我们使用多通道采集的时候需要使能他去轮询读取每个通道值 Continous Conversion Mode 持续转换模式,一般我们都是连续转换,这个我们需要使能他 Discontinous Conversion Mode 与上边序号5相反 DMA Continous Requests 不经过cpu去提取转换的数据,直接交给DMA操作。具体的使用在下边会讲解更详细的讲解可以看下边这个博客(转载,侵权即删)
ST CubeMX翻译
6.开启USART
7.选择KEIL5模式
8.生成独立文件
9.生成代码
代码添加
10.代码中串口重定向
//usart.h 添加
#include "stdio.h"
//usart.c 添加
int fputc(int ch, FILE *f) //轮询方式,超时机制,输出到串口函数重定义
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, sizeof(ch), 0xFFFF);
return ch;
}
/*HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)*/
int fgetc(FILE *f) //轮询方式,超时机制,接收到串口函数重定义
{
uint8_t ch;
HAL_UART_Receive(&huart1, (uint8_t *)&ch, sizeof(ch), 0xFFFF);
return ch;
}
11.ADC采集准备
// adc.h
uint16_t GET_ADC(ADC_HandleTypeDef hadc,uint32_t ch);
uint16_t GET_ADC_AVERAGE(ADC_HandleTypeDef hadc,uint32_t ch,uint8_t times);
//adc.c
//获得ADC值
//ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
//返回值:转换结果
uint16_t GET_ADC(ADC_HandleTypeDef hadc,uint32_t ch)
{
ADC_ChannelConfTypeDef ADC_ChanConf;
ADC_ChanConf.Channel=ch; //通道
ADC_ChanConf.Rank=1; //第1个序列,序列1
ADC_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES; //采样时间
ADC_ChanConf.Offset=0;
HAL_ADC_ConfigChannel(&hadc,&ADC_ChanConf); //通道配置
HAL_ADC_Start(&hadc); //开启ADC
HAL_ADC_PollForConversion(&hadc,10); //轮询转换
return (uint16_t)HAL_ADC_GetValue(&hadc); //返回最近一次ADC1规则组的转换结果
}
//获取指定通道的转换值,取times次,然后平均
//times:获取次数
//返回值:通道ch的times次转换结果平均值
uint16_t GET_ADC_AVERAGE(ADC_HandleTypeDef hadc,uint32_t ch,uint8_t times)
{
uint32_t temp_val=0;
uint8_t t;
for(t=0;t<times;t++)
{
temp_val+=GET_ADC(hadc,ch);
HAL_Delay(5);
}
return temp_val/times;
}
12.主函数采集打印
//main.c 添加
uint16_t temp_adc_value;
float AD_Value;
while (1)
{
/* USER CODE END WHILE */
temp_adc_value=GET_ADC_AVERAGE(hadc1,ADC_CHANNEL_0,20);
AD_Value=temp_adc_value*3.3/4096;
printf("\r\n %f \r\n",AD_Value);
printf("\r\n The adc value is %f \r\n",AD_Value);
HAL_Delay(300);
/* USER CODE BEGIN 3 */
}
这是上边实验的源码,需要的可以下载 工程源码
2.单通道ADC采集+DMA传输
CUBEMX添加配置
说明:在前边配置好时钟,ADC通道和串口的基础上进行添加。
1.添加DMA通道
2.选择对应的ADC通道
3.选择循环模式
4.使能ADC的DMA采集
代码添加
5.重新生成文件在main函数添加代码
//main函数中添加
uint16_t temp_ADC_Value; //暂时存储DMA从DC通道转移的数值
float ADC_Value; //换算后的电压值
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&temp_ADC_Value, 100);
HAL_Delay(1);
while (1)
{
/* USER CODE END WHILE */
ADC_Value= (float)(temp_ADC_Value) / 4096 * 3.3;
printf("adcValue= %f V \r\n",ADC_Value);
HAL_Delay(500);
/* USER CODE BEGIN 3 */
}
3.定时器触发转换(1khz)+DMA传输
CUBEMX配置
1.关闭ADC持续转换
2.选择定时器触发模式
我这里选择的是定时器的通道二作为触发源,并设置成上升沿触发
3.打开定时器时钟并配置PWM模式
4.配置定时器频率
这里的定时器在AHP1 TIME CLOCK总线上,频率为90Mhz,先将他90预分频,降为1Mhz,重装载值设置成1000,此时采集频率为1khz,关于PWM的占空比,CCR这里设置成500,占空比%50
代码添加
5.main函数添加
//main函数
uint16_t temp_ADC_Value;
float ADC_Value;
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2); //开启定时器PWM模式
HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&temp_ADC_Value, 100);
HAL_Delay(1);
while (1)
{
ADC_Value=(float)temp_ADC_Value*3.3/4096;
printf("%f",ADC_Value);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
采集频率满足条件
采集频率需要满足奈奎斯特定律,fs>fh/2, 否则会出现频谱混叠的现象,具体具体可看人家的博客: 奈奎斯特采样定理 (转载,侵权即删)