GD32/STM32ADC采样及滤波
本文主要讨论代码层面的ADC采集及程序滤波。
ADC注意事项
- ADC的参考电压为单片机的VDDA电压。
ADC单采
采用单路采集,然后通过DMA去ADC_RDATA(ADC0)
读取数据。以下为GD32例程。
/*!\brief configure the GPIO peripheral\param[in] none\param[out] none\retval none
*/
void gpio_config(void)
{/* config the GPIO as analog mode */gpio_init(ADC_GPIO_PORT, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, ADC_GPIO_PIN);
}/*!\brief configure the DMA peripheral\param[in] none\param[out] none\retval none
*/
void dma_config(void)
{/* ADC_DMA_channel configuration */dma_parameter_struct dma_data_parameter;/* ADC DMA_channel configuration */dma_deinit(DMA0, DMA_CH0);/* initialize DMA single data mode */dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_data_parameter.memory_addr = (uint32_t)(&adc_value);dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_DISABLE;dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT; dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;dma_data_parameter.number = 1;dma_data_parameter.priority = DMA_PRIORITY_HIGH;dma_init(DMA0, DMA_CH0, &dma_data_parameter);dma_circulation_enable(DMA0, DMA_CH0);/* enable DMA channel */dma_channel_enable(DMA0, DMA_CH0);
}/*!\brief configure the ADC peripheral\param[in] none\param[out] none\retval none
*/
void adc_config(void)
{/* reset ADC */adc_deinit(ADC0);/* ADC mode config */adc_mode_config(ADC_MODE_FREE);/* ADC contineous function enable */adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);/* ADC scan mode disable */adc_special_function_config(ADC0, ADC_SCAN_MODE, DISABLE);/* ADC data alignment config */adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);/* ADC channel length config */adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1);/* ADC regular channel config */adc_regular_channel_config(ADC0, 0, BOARD_ADC_CHANNEL, ADC_SAMPLETIME_55POINT5);/* ADC trigger config */adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);/* enable ADC interface */adc_enable(ADC0);delay_1ms(1);/* ADC calibration and reset calibration */adc_calibration_enable(ADC0);/* ADC DMA function enable */adc_dma_mode_enable(ADC0);/* ADC software trigger enable */adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
}
ADC多路采集+DMA
采用多路采集,然后通过DMA去ADC_RDATA(ADC0)
读取数据。以下为GD32例程。
/***********************************************************************
*@brief :ADC初始化
*@param :None
*@return:None
***********************************************************************/
void ADC_Init(void)
{/* config the GPIO as analog mode */gpio_init(ADC_CHL1_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL1_PIN);gpio_init(ADC_CHL2_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL2_PIN);gpio_init(ADC_CHL3_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL3_PIN);gpio_init(ADC_CHL4_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL4_PIN);gpio_init(ADC_CHL5_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL5_PIN);gpio_init(ADC_CHL6_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL6_PIN);gpio_init(ADC_CHL7_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL7_PIN);gpio_init(ADC_CHL8_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL8_PIN);gpio_init(ADC_CHL9_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL9_PIN);gpio_init(ADC_CHL10_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL10_PIN);gpio_init(ADC_CHL11_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL11_PIN);gpio_init(ADC_CHL12_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL12_PIN);gpio_init(ADC_CHL13_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL13_PIN);gpio_init(ADC_CHL14_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL14_PIN);gpio_init(ADC_CHL15_PORT, GPIO_MODE_AIN, GPIO_OSPEED_2MHZ, ADC_CHL15_PIN);/* enable ADC clock */rcu_periph_clock_enable(RCU_ADC0);/* config ADC clock */rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6); //12MHz;/* reset ADC */adc_deinit(ADC0);/* ADC mode config */adc_mode_config(ADC_MODE_FREE);/* ADC contineous function enable */adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE);/* ADC scan mode disable */adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);/* ADC data alignment config */adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);/* ADC channel length config */adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, ADC_MAX_NUM);adc_tempsensor_vrefint_enable(); // 开启温度传感器/* ADC regular channel config */adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_0, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_1, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 2, ADC_CHANNEL_2, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 3, ADC_CHANNEL_3, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 4, ADC_CHANNEL_5, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 5, ADC_CHANNEL_6, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 6, ADC_CHANNEL_7, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 7, ADC_CHANNEL_8, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 8, ADC_CHANNEL_9, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 9, ADC_CHANNEL_10, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 10, ADC_CHANNEL_11, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 11, ADC_CHANNEL_12, ADC_SAMPLETIME_41POINT5);adc_regular_channel_config(ADC0, 12, ADC_CHANNEL_13, ADC_SAMPLETIME_41POINT5);adc_regular_channel_config(ADC0, 13, ADC_CHANNEL_14, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 14, ADC_CHANNEL_15, ADC_SAMPLETIME_41POINT5); adc_regular_channel_config(ADC0, 15, ADC_CHANNEL_16, ADC_SAMPLETIME_41POINT5);/* ADC trigger config */adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);/* enable ADC interface */adc_enable(ADC0);
// delay_1ms(1);/* ADC calibration and reset calibration */adc_calibration_enable(ADC0);/* ADC DMA function enable */adc_dma_mode_enable(ADC0);/* ADC software trigger enable */adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
}
/***********************************************************************
*@brief :DMA初始化
*@param :ADC传送
*@return:None
***********************************************************************/
void DMA_Init(void)
{/* enable DMA0 clock */rcu_periph_clock_enable(RCU_DMA0);/* ADC_DMA_channel configuration */dma_parameter_struct dma_data_parameter;/* ADC DMA_channel configuration */dma_deinit(DMA0, DMA_CH0);/* initialize DMA single data mode */dma_data_parameter.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));dma_data_parameter.periph_inc = DMA_PERIPH_INCREASE_DISABLE;dma_data_parameter.memory_addr = (uint32_t)(&adc_memory[0]);dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT; dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;dma_data_parameter.number = ADC_MAX_NUM;dma_data_parameter.priority = DMA_PRIORITY_HIGH;dma_init(DMA0, DMA_CH0, &dma_data_parameter);dma_circulation_enable(DMA0, DMA_CH0);/* enable DMA channel */dma_channel_enable(DMA0, DMA_CH0);
}
去极值求平均值滤波
采用一个数组采样10次,去掉一个最大值一个最小值,剩下八个求平均值。
#include <stdio.h>
#include <stdlib.h>int main() {// 定义数组和变量int arr[10];int i, j, temp;float avg;// 获取 10 个样本值printf("Enter 10 sample values:\n");for (i = 0; i < 10; i++) {scanf("%d", &arr[i]);}// 排序数组for (i = 0; i < 10; i++) {for (j = i + 1; j < 10; j++) {if (arr[i] > arr[j]) {// 交换 arr[i] 和 arr[j]temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}}// 去掉最大值和最小值for (i = 1; i < 9; i++) {avg += arr[i];}// 计算平均值avg /= 8;// 打印去极值后的平均值printf("Average of the remaining 8 values: %.2f\n", avg);return 0;
}
滑动求平均值滤波
一组数据采用10位数组,队列式进队和出队,然后求平均值得到最终的值。
#include <stdio.h>
#include <stdlib.h>#define ARRAY_SIZE 10int main() {// 定义队列数组和变量int queue[ARRAY_SIZE];int head = 0;int tail = 0;int count = 0;float avg;// 获取 10 个样本值printf("Enter 10 sample values:\n");for (int i = 0; i < ARRAY_SIZE; i++) {scanf("%d", &queue[tail]);tail = (tail + 1) % ARRAY_SIZE;count++;}// 滑动求平均值while (count > 0) {// 计算平均值avg = 0;for (int i = 0; i < count; i++) {avg += queue[head];head = (head + 1) % ARRAY_SIZE;}avg /= count;// 打印平均值printf("Average: %.2f\n", avg);// 出队count--;}return 0;
}
振幅平均滤波法
#include <stdio.h>
#include <stdlib.h>// 定义滑动窗口大小
#define WINDOW_SIZE 5int main() {// 定义输入信号和滤波器参数int input_signal[] = {1, 3, 5, 10, 15, 20, 25, 30, 25, 20, 15, 10, 5, 3, 1};int threshold = 10;int window[WINDOW_SIZE];int head = 0;int tail = 0;int count = 0;float avg;// 循环处理输入信号for (int i = 0; i < sizeof(input_signal) / sizeof(int); i++) {// 限制幅度int limited_value = input_signal[i];if (limited_value > threshold) {limited_value = threshold;}// 滑动窗口进队window[tail] = limited_value;tail = (tail + 1) % WINDOW_SIZE;if (count < WINDOW_SIZE) {count++;}// 计算平均值avg = 0;for (int j = 0; j < count; j++) {avg += window[head];head = (head + 1) % WINDOW_SIZE;}avg /= count;// 打印滤波后的信号printf("Filtered signal: %.2f\n", avg);}return 0;
}
总结
大家可以取其精华然后结合具体进行应用。