- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] adc configuration.
- * @param none
- * @retval none
- */
- static void adc_config(void)
- {
- adc_common_config_type adc_common_struct;
- adc_base_config_type adc_base_struct;
- crm_periph_clock_enable(CRM_ADC1_PERIPH_CLOCK, TRUE);
- nvic_irq_enable(ADC1_IRQn, 0, 0);
- crm_adc_clock_select(CRM_ADC_CLOCK_SOURCE_HCLK);
-
- adc_common_default_para_init(&adc_common_struct);
- /* config division,adcclk is division by hclk */
- adc_common_struct.div = ADC_HCLK_DIV_4;
- /* config inner temperature sensor and vintrv */
- adc_common_struct.tempervintrv_state = FALSE;
- adc_common_config(&adc_common_struct);
- adc_base_default_para_init(&adc_base_struct);
- adc_base_struct.sequence_mode = TRUE;
- adc_base_struct.repeat_mode = FALSE;
- adc_base_struct.data_align = ADC_RIGHT_ALIGNMENT;
- adc_base_struct.ordinary_channel_length = 24;
- adc_base_config(ADC1, &adc_base_struct);
- adc_resolution_set(ADC1, ADC_RESOLUTION_12B);
- /* config ordinary channel */
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_2, 3, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_3, 4, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_4, 5, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_5, 6, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_6, 7, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_7, 8, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_8, 9, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_9, 10, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_10, 11, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_11, 12, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_12, 13, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_13, 14, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_14, 15, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_15, 16, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_20, 17, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_21, 18, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_22, 19, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_23, 20, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_24, 21, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_25, 23, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_26, 23, ADC_SAMPLETIME_6_5);
- adc_ordinary_channel_set(ADC1, ADC_CHANNEL_27, 24, ADC_SAMPLETIME_6_5);
- /* config ordinary trigger source and trigger edge */
- adc_ordinary_conversion_trigger_set(ADC1, ADC_ORDINARY_TRIG_TMR1CH1, ADC_ORDINARY_TRIG_EDGE_NONE);
- /* config dma mode,it's not useful when common dma mode is use */
- adc_dma_mode_enable(ADC1, TRUE);
- /* config dma request repeat,it's not useful when common dma mode is use */
- adc_dma_request_repeat_enable(ADC1, TRUE);
- /* enable adc overflow interrupt */
- adc_interrupt_enable(ADC1, ADC_OCCO_INT, TRUE);
- /* set oversampling ratio and shift */
- adc_oversample_ratio_shift_set(ADC1, ADC_OVERSAMPLE_RATIO_8, ADC_OVERSAMPLE_SHIFT_3);
- /* disable ordinary oversampling trigger mode */
- adc_ordinary_oversample_trig_enable(ADC1, FALSE);
- /* set ordinary oversample restart mode */
- adc_ordinary_oversample_restart_set(ADC1, ADC_OVERSAMPLE_CONTINUE);
- /* enable ordinary oversampling */
- adc_ordinary_oversample_enable(ADC1, TRUE);
- /* adc enable */
- adc_enable(ADC1, TRUE);
- while(adc_flag_get(ADC1, ADC_RDY_FLAG) == RESET);
- /* adc calibration */
- adc_calibration_init(ADC1);
- while(adc_calibration_init_status_get(ADC1));
- adc_calibration_start(ADC1);
- while(adc_calibration_status_get(ADC1));
- }
参照ADC的DMA程序,配置DMA的配置如下:
- /**
- * @brief dma configuration.
- * @param none
- * @retval none
- */
- static void dma_config(void)
- {
- dma_init_type dma_init_struct;
- crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
- nvic_irq_enable(DMA1_Channel1_IRQn, 0, 0);
- dma_reset(DMA1_CHANNEL1);
- dma_default_para_init(&dma_init_struct);
- dma_init_struct.buffer_size = 120;
- dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
- dma_init_struct.memory_base_addr = (uint32_t)adc1_ordinary_valuetab;
- dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
- dma_init_struct.memory_inc_enable = TRUE;
- dma_init_struct.peripheral_base_addr = (uint32_t)&(ADC1->odt);
- dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
- dma_init_struct.peripheral_inc_enable = FALSE;
- dma_init_struct.priority = DMA_PRIORITY_HIGH;
- dma_init_struct.loop_mode_enable = TRUE;
- dma_init(DMA1_CHANNEL1, &dma_init_struct);
- dmamux_enable(DMA1, TRUE);
- dmamux_init(DMA1MUX_CHANNEL1, DMAMUX_DMAREQ_ID_ADC1);
- /* enable dma transfer complete interrupt */
- dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE);
- dma_channel_enable(DMA1_CHANNEL1, TRUE);
- }
移植TFT的显示程序(略)
在主程序中添加数据转换的命令与数据读取、取平值数,并做显示,附源代码:
- int main(void)
- {
- __IO uint32_t index = 0;
- uint8_t j = 0;
- uint32_t val[24]={0};
- uint8_t show_str[20] = {0};
- nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
- /* config the system clock */
- system_clock_config();
- /* init at start board */
- at32_board_init();
- at32_led_off(LED2);
- at32_led_off(LED3);
- at32_led_off(LED4);
- uart_print_init(115200);
- gpio_config();
- dma_config();
- adc_config();
- printf("tmr_trigger_automatic_preempt \r\n");
-
- at32_led_on(LED2);
- IVO28_GC9306_P4();
- LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
- //LCD_ShowString(10,10, "HELLO AT32F423",BLUE,WHITE,32,0);
- LCD_ShowChinese(20,6,"电压监测系统",BLUE,WHITE,32,0);//显示汉字串
- while(1)
- {
- /* adc1 software trigger start conversion */
- for(index = 0; index < 5; index++)
- {
- adc_ordinary_software_trigger_enable(ADC1, TRUE);
-
- delay_ms(100);
- }
- if((dma_trans_complete_flag == 0) || (adc1_overflow_flag != 0))
- {
- /* printf flag when error occur */
- at32_led_on(LED3);
- at32_led_on(LED4);
- printf("error occur\r\n");
- printf("adc1_overflow_flag = %d\r\n",adc1_overflow_flag);
- printf("dma_trans_complete_flag = %d\r\n",dma_trans_complete_flag);
- }
- else
- {
- /* printf data when conversion end without error */
- printf("conversion end without error\r\n");
- for(index = 0; index < 5; index++)
- {
- for(j=0;j<24;j++)
- {
- val[j] += adc1_ordinary_valuetab[index][j];
- }
- }
- }
- for(j=0;j<8; j++)
- {
- sprintf(show_str,"%02d:%1.3f",j+1,((float)(val[j]/5) * 3.32)/4095);
- LCD_ShowString(0,60+j*32, show_str,BLUE,WHITE,16,0);
- val[j] = 0;
- }
- for(j=8;j<16; j++)
- {
- sprintf(show_str,"%02d:%1.3f",j+1,((float)(val[j]/5) * 3.32)/4095);
- LCD_ShowString(80,60+(j-8)*32, show_str,BLUE,WHITE,16,0);
- val[j] = 0;
- }
- for(j=16;j<24; j++)
- {
- sprintf(show_str,"%02d:%1.3f",j+1,((float)(val[j]/5) * 3.32)/4095);
- LCD_ShowString(160,60+(j-16)*32, show_str,BLUE,WHITE,16,0);
- val[j] = 0;
- }
- dma_trans_complete_flag = 0;
- }
- }
【工程实验效果】
在LCD屏中,按1-24路通道显示电压如下:
用福禄克18B+与之对照,发现电压差距在1MV左右,精度非常的高,对电压的反馈也非常之好。
【讨论】
这个项目主要用到的AT32F423的24路模拟ADC输入,采用DMA的数据传输。同时驱动了TFTLCD屏。把24路电压的测量结果全部展现在显示屏上。同时与福禄克18B+的万用表进行对比测量,误差在正负1mV左右,各路之间的电压差也在正负3mV左右。
此次是用开发板进行了工程的验证,因为采用的参考电压是普通的数字电源,如果用到实际的工程中,需要使用精度高的稳压参考电源来进行测量,这样精度更加好。
在实际的工程中可以引入电压监的范围,来设定显示的颜色,超过规定的范围可以用警告来提示用户,同时可以把数据存到SD卡中,或者是经过UART等外设把数据上传到上位机中供用户进行数据挖掘等。
总之,对AT32F423的多路ADC进行测试,发现达到12位ADC的测量预期效果。如果结合放大器等辅助,可以实现高精的电压、电流测量。
【附工程视频介绍】
https://www.bilibili.com/video/BV1bj411h7zB/?vd_source=e1bd226340c8b87027d5dcfc6b0c3344