声明
此文档主要来源于GD32官方例程,不涉及公司内部关键代码,主要用于自己回顾。
前言
此程序是基于GD32F130F8P6,目的是运用NTC,检测9路温度,此文档仅涉及DMA配置及ADC采样值获取。
一、时钟配置
void rcu_config(void)
{
/* enable GPIO clock */
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
/* enable ADC clock */
rcu_periph_clock_enable(RCU_ADC);
/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA);
/* config ADC clock */
rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);
}
二、ADC初始化配置
void adc_config(void)
{
/* gpio config */
gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 |
GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 |
GPIO_PIN_6 | GPIO_PIN_7 );
gpio_mode_set(GPIOB, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1);
/* ADC channel length config */
adc_channel_length_config(ADC_REGULAR_CHANNEL,ADC_Num);
/* ADC regular channel config */
adc_regular_channel_config(0,ADC_CHANNEL_0,ADC_SAMPLETIME_13POINT5);
adc_regular_channel_config(1,ADC_CHANNEL_1,ADC_SAMPLETIME_13POINT5);
adc_regular_channel_config(2,ADC_CHANNEL_2,ADC_SAMPLETIME_13POINT5);
adc_regular_channel_config(3,ADC_CHANNEL_3,ADC_SAMPLETIME_13POINT5);
adc_regular_channel_config(4,ADC_CHANNEL_4,ADC_SAMPLETIME_13POINT5);
adc_regular_channel_config(5,ADC_CHANNEL_5,ADC_SAMPLETIME_13POINT5);
adc_regular_channel_config(6,ADC_CHANNEL_6,ADC_SAMPLETIME_13POINT5);
adc_regular_channel_config(7,ADC_CHANNEL_7,ADC_SAMPLETIME_13POINT5);
adc_regular_channel_config(8,ADC_CHANNEL_9,ADC_SAMPLETIME_13POINT5);
/* ADC external trigger enable */
adc_external_trigger_config(ADC_REGULAR_CHANNEL,ENABLE);
/* ADC external trigger source config */
adc_external_trigger_source_config(ADC_REGULAR_CHANNEL,ADC_EXTTRIG_REGULAR_SWRCST);
/* ADC data alignment config */
adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
/* ADC discontinuous mode */
adc_discontinuous_mode_config(ADC_REGULAR_CHANNEL,4);
/* enable ADC interface */
adc_enable();
/* ADC calibration and reset calibration */
adc_calibration_enable();
/* ADC DMA function enable */
adc_dma_mode_enable();
/* ADC contineous function enable */
// adc_special_function_config(ADC_CONTINUOUS_MODE,ENABLE);
/* ADC software trigger enable */
// adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
}
在ADC转化的过程中,需注意 adc_software_trigger_enable(ADC_REGULAR_CHANNEL)的使用,在运用到多通道ADC采样过程中,使用不当可能会出现数据错位。我的工程中是在主循环while(1)中进行触发。
三、DMA初始化
void dma_config(void)
{
/* enable DMA clock */
rcu_periph_clock_enable(RCU_DMA);
/* ADC_DMA_channel configuration */
dma_deinit(DMA_CH0);
dma_periph_address_config(DMA_CH0,(uint32_t)(&ADC_RDATA));
dma_memory_address_config(DMA_CH0,(uint32_t)(&adc_value));
dma_transfer_direction_config(DMA_CH0,DMA_PERIPHERAL_TO_MEMORY);
dma_memory_width_config(DMA_CH0,DMA_MEMORY_WIDTH_16BIT);
dma_periph_width_config(DMA_CH0,DMA_PERIPHERAL_WIDTH_16BIT);
dma_priority_config(DMA_CH0,DMA_PRIORITY_HIGH);
dma_transfer_number_config(DMA_CH0,ADC_Num);
dma_periph_increase_disable(DMA_CH0);
dma_memory_increase_enable(DMA_CH0);
dma_circulation_enable(DMA_CH0);
dma_channel_enable(DMA_CH0);
}
在上述配置的过程中,需要注意的是:
1、 dma_memory_address_config(DMA_CH0,(uint32_t)(&adc_value)),adc_value[]是一个用于储存DMA数据的缓冲区。
2、dma_transfer_number_config(DMA_CH0,ADC_Num);此处的ADC_Num是采样通道数量,我这里是把ADC_Num宏定义为 0x09。
需特别注意adc_value[]与ADC_Num的配合。
四、主函数处理与部分变量定义
#define AVE_NUM 8
#define ADC_Num 9
uint16_t adc_value[9];
int main(void)
{
uint8_t i;
static uint8_t adc_date_realdy_flag = 0;
static uint16_t adc_sum_count = 0;
static uint16_t adc_date_buffer[AVE_NUM][ADC_Num] = {0};
static uint32_t adc_sum[ADC_Num] = {0};
static uint16_t adc_ave[ADC_Num] = {0};
rcu_config();
/* ADC configuration */
adc_config();
dma_config();
while(1)
{
/*adc software trigger*/
adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
/* get adc value, 8 times*/
if (adc_sum_count < 8)
{
/* 9 ch */
for (i=0; i<ADC_Num; i++)
{
adc_date_buffer[adc_sum_count][i] = adc_value[i];
}
adc_sum_count++;
}
else
{
adc_sum_count = 0;
adc_date_realdy_flag = 1;
}
/* frist times get complete data after boot */
if (adc_date_realdy_flag == 1)
{
for(i=0; i<ADC_Num; i++)
{
/* calculate sum data of ch */
adc_sum[i] = adc_date_buffer[0][i] + adc_date_buffer[1][i] + adc_date_buffer[2][i] + adc_date_buffer[3][i]
+ adc_date_buffer[4][i] + adc_date_buffer[5][i] + adc_date_buffer[6][i] + adc_date_buffer[7][i];
/* Calculated average*/
adc_ave[i] = adc_sum[i] >> 3;
}
}
}
}
在主函数中,DMA传输的数据存在一个二维数组中,每个通道取8次值,轮询更新。求和,再取平均值,这里建议取2的次方,在求平均值时,采用移位操作即可。但是会丢失部分精度。