今天周末,抽点时间研究了一下GD32VF103的ADC检测功能,结合视频讲解,简单谈谈ADC。ADC即模数转换,12位ADC是一种采用逐次逼近方式的模拟数字转换器。GD32VF103有18个多路复用通道,可以转换来自16个外部通道和2个内部通道的模拟信号。模拟看门狗允许应用程序来检测输入电压是否超出用户设定的高低阈值。各种通道的A/D转换可以配置成单次、连续、扫描或间断转换模式。ADC转换的结果可以按照左对齐或右对齐的方式存储在16位数据寄存器中。片上的硬件过采样机制可以通过减少来自MCU的相关计算负担来提高性能。
ADC模块框图如下图所示:
ADC带有一个前置校准功能。在校准期间,ADC计算一个校准系数,这个系数是应用于ADC
内部的,它直到ADC下次掉电才无效。在校准期间,应用不能使用ADC,它必须等到校准完
成。在A/D转换前应执行校准操作。通过软件设置CLB=1来对校准进行初始化,在校准期间CLB 位会一直保持1,直到校准完成,该位由硬件清0。当ADC运行条件改变后建议重新执行一次校准操作。内部的模拟校准通过设置ADC_CTL1寄存器的RSTCLB位来重置。
关于ADC的信号同步,在有两个或者两个以上的ADC模块的产品中,可以使用ADC同步模式。在ADC同步模式下,根据ADC_CTL0寄存器中SYNCM[3:0]位所选的模式,转换的启动可以是ADC0主和ADC1从的交替触发或同步触发。在同步模式下,当配置由外部事件触发的转换时,从ADC必须通过软件来配置触发来,从而避免错误的触发引起不必要的转换。此外,对于主ADC和从ADC的外部触发必须被使能。
共有以下几种模式:
– 独立模式
– 规则并行模式
– 注入并行模式
– 快速交叉模式
– 慢速交叉模式
– 交替触发模式
– 注入并行模式 规则并行模式
– 规则并行模式 交替触发模式
– 注入并行模式 交叉模式
在ADC同步模式下,即使DMA不用,也要将DMA置位,从ADC的转换数据可以通过主ADC 数据寄存器读取。ADC同步框图如下:
关于ADC的寄存器如下:
ADC库函数如下:
在原来的串口检测工程中,添加部分代码
部分代码如下: #include "gd32vf103.h" #include "gd32vf103v_eval.h" #include "systick.h" #include <stdio.h> uint32_t adc_value[2]; void rcu_config(void); void gpio_config(void); void dma_config(void); void timer_config(void); void adc_config(void); int main(void) { uint i; uint data; /*配置系统时钟*/ rcu_config(); /*配置GPIO口 */ gpio_config(); /*配置TIMER*/ timer_config(); /*配置DMA*/ dma_config(); /*配置ADC*/ adc_config(); /*使能TIMER1*/ timer_enable(TIMER1); gd_eval_led_init(LED1); /*配置EVAL_COM0*/ gd_eval_com_init(EVAL_COM0); while(1) { gd_eval_led_on(LED1); printf("ADC0 regular data0 = %d \r\n",adc_value[0]); delay_1ms(200); printf("ADC0 regular data0 = %4X \r\n",adc_value[0]); delay_1ms(200); printf("ADC0 regular data1 = %d \r\n",adc_value[1]); delay_1ms(200); printf("ADC0 regular data1 = %4X \r\n",adc_value[1]); delay_1ms(200); if(usart_flag_get(USART0,USART_FLAG_RBNE)!= RESET) { data = usart_data_receive(USART0); usart_data_transmit(USART0,data); while(usart_flag_get(USART0,USART_FLAG_TC)==RESET); usart_data_transmit(USART0,0X0A); while(usart_flag_get(USART0,USART_FLAG_TC)==RESET); usart_data_transmit(USART0,0X0D); while(usart_flag_get(USART0,USART_FLAG_TC)==RESET); } gd_eval_led_off(LED1); delay_1ms(500); } } void rcu_config(void) { /* enable GPIOA clock */ rcu_periph_clock_enable(RCU_GPIOA); /* enable ADC0 clock */ rcu_periph_clock_enable(RCU_ADC0); /* enable DMA0 clock */ rcu_periph_clock_enable(RCU_DMA0); /* enable timer1 clock */ rcu_periph_clock_enable(RCU_TIMER1); /* config ADC clock */ rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8); } void gpio_config(void) { /* config the GPIO as analog mode */ gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_1); } void dma_config(void) { /* ADC_DMA_channel configuration */ dma_parameter_struct dma_data_parameter; /* 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)(&adc_value); dma_data_parameter.memory_inc = DMA_MEMORY_INCREASE_DISABLE; dma_data_parameter.periph_width = DMA_PERIPHERAL_WIDTH_16BIT; dma_data_parameter.memory_width = DMA_MEMORY_WIDTH_16BIT; dma_data_parameter.direction = DMA_PERIPHERAL_TO_MEMORY; dma_data_parameter.number = 1; 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); } void timer_config(void) { timer_oc_parameter_struct timer_ocintpara; timer_parameter_struct timer_initpara; /* TIMER1 configuration */ timer_struct_para_init(&timer_initpara); timer_initpara.prescaler = 5399; timer_initpara.alignedmode = TIMER_COUNTER_EDGE; timer_initpara.counterdirection = TIMER_COUNTER_UP; timer_initpara.period = 9999; timer_initpara.clockdivision = TIMER_CKDIV_DIV1; timer_initpara.repetitioncounter = 0; timer_init(TIMER1,&timer_initpara); /* CH1 configuration in PWM mode1 */ timer_channel_output_struct_para_init(&timer_ocintpara); timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH; timer_ocintpara.outputstate = TIMER_CCX_ENABLE; timer_channel_output_config(TIMER1, TIMER_CH_1, &timer_ocintpara); timer_channel_output_pulse_value_config(TIMER1, TIMER_CH_1, 3999); timer_channel_output_mode_config(TIMER1, TIMER_CH_1, TIMER_OC_MODE_PWM1); timer_channel_output_shadow_config(TIMER1, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE); } void adc_config(void) { /* reset ADC */ adc_deinit(ADC0); /* ADC mode config */ adc_mode_config(ADC_DAUL_REGULAL_FOLLOWUP_FAST); /* ADC continous function enable */ adc_special_function_config(ADC0, ADC_SCAN_MODE, ENABLE); /* ADC data alignment config */ adc_data_alignment_config(ADC0, ADC_DATAALIGN_RIGHT); /* ADC channel length config */ adc_channel_length_config(ADC0, ADC_REGULAR_CHANNEL, 1); /* ADC regular channel config */ adc_regular_channel_config(ADC0, 0, ADC_CHANNEL_1, ADC_SAMPLETIME_55POINT5); /* ADC trigger config */ adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T1_CH1); /* ADC external trigger enable */ adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE); /* enable ADC interface */ adc_enable(ADC0); /* ADC calibration and reset calibration */ adc_calibration_enable(ADC0); delay_1ms(1); /* ADC DMA function enable */ adc_dma_mode_enable(ADC0); }
串口打印信息如下:
接线还是与之前一样
通过测试ADC通道0的数据采样,说明GD32VF103可配置12位、10位、8位或者6位分辨率,支持自校准,可编程采样时间,数据寄存器可配置数据对齐方式,支持规则数据转换的DMA请求。转换开始的发起有软件与硬件触发。此次分享就到这里吧,后续再细究。欢迎各位网友各抒己见,如有异议,烦请留言回复,感谢。