GD32+ADC+DMA定时采集+acs712霍尔电流传感器
目的:本文使用定时器定时触发adc采样,并且通过dma搬运数据。
环境:KEIL
GD32F107vct6+ADC01_IN5(PA5)+TIMER3 CH3
时钟初始化
rcu_periph_clock_enable(RCU_ADC0);
rcu_periph_clock_enable(RCU_DMA0);
rcu_periph_clock_enable(RCU_TIMER3);
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8);
通过GD32F450+TIM定时器(1)可知,芯片使用外部晶振,时钟频率是108MHz。
APB2的频率= 108Mhz。
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV8) 初始化adc的时钟频率为13Mhz。
io初始化
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_AF);//打开复用时钟
gpio_init(GPIOA,GPIO_MODE_AIN,GPIO_OSPEED_50MHZ, GPIO_PIN_5);
定时器初始化
timer_parameter_struct initpara;
timer_oc_parameter_struct ocpara;
timer_deinit(TIMER3);
initpara.alignedmode = TIMER_COUNTER_EDGE;
initpara.clockdivision = TIMER_CKDIV_DIV1;
initpara.counterdirection = TIMER_COUNTER_UP;
initpara.period = SAMPLE_TIME;
initpara.prescaler = 107;
initpara.repetitioncounter = 0;
timer_init(TIMER3,&initpara);
ocpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
ocpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
ocpara.ocnpolarity = TIMER_OCN_POLARITY_LOW;
ocpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
ocpara.outputnstate = TIMER_CCXN_DISABLE;
ocpara.outputstate = TIMER_CCX_ENABLE;//通道使能
timer_channel_output_config(TIMER3,TIMER_CH_3,&ocpara);
timer_channel_output_mode_config(TIMER3,TIMER_CH_3,TIMER_OC_MODE_PWM0);//pwm模式
timer_channel_output_pulse_value_config(TIMER3,TIMER_CH_3,50);
timer_auto_reload_shadow_enable(TIMER3);
SAMPLE_TIME:ADC采集数据间隔
ADC初始化
adc_deinit(ADC0);
adc_mode_config(ADC_MODE_FREE);//ADC独立工作
adc_special_function_config(ADC0,ADC_CONTINUOUS_MODE,DISABLE);//不连续转换
adc_special_function_config(ADC0,ADC_SCAN_MODE,DISABLE);//不扫描
adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);//右对齐
adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,1);//1个通道转换
adc_regular_channel_config(ADC0,0,ADC_CHANNEL_5,ADC_SAMPLETIME_13POINT5);//第0个序列,采样时间
adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,ENABLE);//规则组外部触发使能
adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL,ADC0_1_EXTTRIG_REGULAR_T3_CH3);
adc_enable(ADC0);
DelayMicroSeconds(1);
adc_calibration_enable(ADC0);//复位并校准
adc_dma_mode_enable(ADC0);
adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL);//规则组转换开始
因为是用定时器定时触发采样,所以采用不连续模式。只有一个ADC通道,所以不扫描。
注意:adc_enable(ADC0)和adc_software_trigger_enable(ADC0, ADC_REGULAR_CHANNEL)的顺序不能颠倒。
从手册里可知,adc_enable()只是唤醒ADC,并不是开启转换。adc_software_trigger_enable()是开启规则组转换。
ADC_SAMPLETIME_13POINT5:采样时间
总转换时间=采样时间+12.5 个 ADCCLK 周期 = 26个ADCCLK周期= 26/13000000s = 2us。
定时器采集间隔一定要大于转换时间。
DMA初始化
uint16_t rev_data[PER_NUM] = {0};
dma_deinit(DMA0,DMA_CH0);
init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;//外设到寄存器
init_struct.memory_addr = (uint32_t)(&rev_data);//存储器地址
init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;//地址自增
init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;//16位
init_struct.number = PER_NUM;//1个通道 PER_NUM个数据
init_struct.periph_addr = (uint32_t)(&ADC_RDATA(ADC0));//外设地址
init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;//外设不增
init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;//16位 取决于存储数据的类型
init_struct.priority = DMA_PRIORITY_HIGH;//优先级
dma_init(DMA0,DMA_CH0,&init_struct);
dma_circulation_enable(DMA0,DMA_CH0);//循环模式
nvic_irq_enable(DMA0_Channel0_IRQn, 1, 1);
dma_interrupt_enable(DMA0,DMA_CH0,DMA_INT_FTF);//全部数据转换完成中断
dma_channel_enable(DMA0,DMA_CH0);
timer_enable(TIMER3);//放到底下
PER_NUM :每次采集数据数目。
通过手册可知ADC0对应DMA0_CH0。
数据处理
通过DMA中断可以知道是否转换完成。所用器件是acs712霍尔电流传感器。
公式为:Vout (V)= 0.5Vcc+IP*0.1。通过ADC采集电压就能知道电流了。
总结:
以上仅为个人理解,如果有误,请大家多多指正,谢谢!