一、工具
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