1. 程式人生 > 實用技巧 >基於GD32F30x微控制器_ADC電壓採集(規則並行+DMA方式)

基於GD32F30x微控制器_ADC電壓採集(規則並行+DMA方式)

一、工具

  1、GD32F30x系列微控制器;

  2、編譯環境:KEIL

二、需求分析

  使用微控制器的ADC多通道採集不同的電壓值。因為採集的通道比較多,為了能夠迅速轉換每個通道這裡我使用了ADC的規則並行模式。

  對於規則並行模式,官方文件是如下解釋:

  同時也給出了基於16個通道的規則並行模式取樣和轉換圖,如下圖所示:

三、程式碼實現

  1、ADC通道引腳配置

/**
  * @brief ADC01 引腳配置
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
static void bsp_adc01_gpio_cfg(void
) { /* enable GPIOA GPIOB GPIOC clock */ rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_GPIOB); rcu_periph_clock_enable(RCU_GPIOC); /* enable alternate function clock */ rcu_periph_clock_enable(RCU_AF); /* configure ADC GPIO port */ gpio_init(RCU_GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_4
| GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); gpio_init(RCU_GPIOB, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_0 | GPIO_PIN_1); gpio_init(RCU_GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5); }

  2、ADC功能配置,為了能夠獲取每個通道實時的電壓值,需要開啟掃描模式和連續轉換模式。經過測試發現規則同步模式下是不能轉換內部參考電壓的。

/**
  * @brief ADC01 配置
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
static void bsp_adc01_cfg(void)
{    
    /* enable ADC0 and ADC1 clock */
    rcu_periph_clock_enable(RCU_ADC0);
    rcu_periph_clock_enable(RCU_ADC1);
    /* config ADC clock */
    rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV4);
    
    /* ADC continous function enable */
    adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE);
    adc_special_function_config(ADC0, ADC_CONTINUOUS_MODE, ENABLE); 
    adc_special_function_config(ADC1, ADC_SCAN_MODE, ENABLE);
    adc_special_function_config(ADC1, ADC_CONTINUOUS_MODE, ENABLE); 
    
    /* ADC trigger config */
    adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);
    adc_external_trigger_source_config(ADC1, ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);        
        
    /* ADC data alignment config */
    adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT);
    adc_data_alignment_config(ADC1, ADC_DATAALIGN_RIGHT);
    
    /* ADC mode config,使用規則同步模式,ADC0是主,ADC1是從, 同時轉換兩個通道(同時轉換的通道不能相同) */
    adc_mode_config(ADC_DAUL_REGULAL_PARALLEL); 
    
    /* ADC channel length config */
    adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 5);
    adc_channel_length_config(ADC1, ADC_REGULAR_CHANNEL, 5);    
    
    /* ADC regular channel config,一個通道轉換時長是2.06us */
    adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_4, ADC_SAMPLETIME_55POINT5);
    adc_regular_channel_config(ADC0, 1, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5);
    adc_regular_channel_config(ADC0, 2, ADC_CHANNEL_6, ADC_SAMPLETIME_55POINT5);
    adc_regular_channel_config(ADC0, 3, ADC_CHANNEL_7, ADC_SAMPLETIME_55POINT5);
    adc_regular_channel_config(ADC0, 4, ADC_CHANNEL_8, ADC_SAMPLETIME_55POINT5);
        
    adc_regular_channel_config(ADC1, 0, ADC_CHANNEL_9, ADC_SAMPLETIME_55POINT5);    
    adc_regular_channel_config(ADC1, 1, ADC_CHANNEL_12, ADC_SAMPLETIME_55POINT5);
    adc_regular_channel_config(ADC1, 2, ADC_CHANNEL_14, ADC_SAMPLETIME_55POINT5);
    adc_regular_channel_config(ADC1, 3, ADC_CHANNEL_15, ADC_SAMPLETIME_55POINT5);
    adc_regular_channel_config(ADC1, 4, ADC_CHANNEL_5, ADC_SAMPLETIME_55POINT5);
    
    /* ADC external trigger enable */
    adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);    
    adc_external_trigger_config(ADC1, ADC_REGULAR_CHANNEL, ENABLE);    

    /* enable ADC0 interface */
    adc_enable(ADC0);      
    delay_ms(0xFFFF);
    /* ADC0 calibration and reset calibration */
    adc_calibration_enable(ADC0);
    
    /* enable ADC1 interface */
    adc_enable(ADC1);      
    delay_ms(0xFFFF);
    /* ADC1 calibration and reset calibration */
    adc_calibration_enable(ADC1);    
    
    /* ADC DMA function enable */
    adc_dma_mode_enable(ADC0);        
    
    /* ADC0 software trigger enable */
    adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);
}

  3、ADC的DMA配置

uint32_t adc01_value[5];
/**
  * @brief ADC01 DMA配置
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
void bsp_adc01_dma_cfg(void)
{
    /* ADC_DMA_channel configuration */
    dma_parameter_struct dma_data_parameter;
    /* enable DMA0 clock */
    rcu_periph_clock_enable(RCU_DMA0); 
    /* ADC DMA_channel configuration */
    dma_deinit(DMA0, DMA_CH0);
   
    /* initialize DMA 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)(&adc01_value);
    dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_32BIT;
    dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_32BIT;  
    dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_data_parameter.number = 5;        /* ADC通道數量 */
    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);
}

  4、ADC初始化

/**
  * @brief ADC01 初始化
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
void bsp_adc01_init(void)
{
    bsp_adc01_gpio_cfg();
    bsp_adc01_dma_cfg();
    bsp_adc01_cfg();
}

  5、獲取各通道ADC值

/**
  * @brief 獲取測量端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_mea_adc_value(void)
{
    return (uint16_t)(adc01_value[0]&0xFFFF);
}

/**
  * @brief 獲取bat端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_bat_adc_value(void)
{
    return (uint16_t)(adc01_value[1]&0xFFFF);
}

/**
  * @brief 獲取校準端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_cal_adc_value(void)
{
    return (uint16_t)(adc01_value[2]&0xFFFF);
}

/**
  * @brief 獲取參比端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_ref_adc_value(void)
{
    return (uint16_t)(adc01_value[3]&0xFFFF);
}

/**
  * @brief 獲取-5V端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_minus_5v_adc_value(void)
{
    return (uint16_t)(adc01_value[4]&0xFFFF);
}

/**
  * @brief 獲取+5V端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_pluse_5v_adc_value(void)
{
    return (uint16_t)(adc01_value[0] >> 16);;
}

/**
  * @brief 獲取8.5V端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_8v5_adc_value(void)
{
    return (uint16_t)(adc01_value[1] >> 16);;
}

/**
  * @brief 獲取+12V端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_pluse_12v_adc_value(void)
{
    return (uint16_t)(adc01_value[2] >> 16);;
}

/**
  * @brief 獲取-12V端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-10
  */
uint16_t adc01_get_minus_12v_adc_value(void)
{
    return (uint16_t)(adc01_value[3] >> 16);;
}

/**
  * @brief 獲取bat'端adc值
  * @retval none
  * @author Mr.W
  * @date 2020-11-19
  */
uint16_t adc01_get_batn_adc_value(void)
{
    return (uint16_t)(adc01_value[4] >> 16);;
}

#endif