[AT32F423]3【AT-START-F423测评】多路电压采集系统

【项目简介】
在工业冶具行业中,经常会有多路电压测试的需求,如下图所示:
 


这种解决方案,虽然适配简单,但是如果对其进行人工判断,一来观测的人容易产生误差,而且需要人工值守,成本也比较高。
而用AT32F423的ADC,可以实现一个单片机对应测量24路电压。并且可以通过设定正常电压范围,就可以实现智能的电压监测,对于异常情况可以通过多种途径进行报警提示,后台数据记录等。
【AT32F423的ADC简介】
在数据手册《DS_AT32F423_V2.00_CH.pdf》中如下图所描述:
 


AT32F423中有一个ADC1,总共26个通道,ADC_IN0 至 ADC_IN15 为外部模拟输入,ADC_IN16 为内部温度传感器,ADC_IN17 为内部参考电压,ADC_IN20 至 ADC_IN27 为外部模拟输入。这样就有24个通道可以做输入检测。
【程序的实现步骤】
使用雅特力的图形化配置工具Work Bench对24个通的ADC进行图形化配置:
 


在代码预览中复制ADC的配置代码到工程模板中的adc的gpio初始化函数中:
 


 


参照adc的DMA例程中添加ADC的配置,具体程序如下:

复制

/**

  * [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的测量预期效果。如果结合放大器等辅助,可以实现高精的电压、电流测量。:
---------------------
作者:lulugl
链接:https://bbs.21ic.com/icview-3338918-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值