文章目录
- ADC
- TIM
- DMA
- 其他一些初始化
- main
- 总结
使用芯片为GD32F307
ADC
连续转换模式,可以运行在规则组通道上,一旦相应软件触发或者外部触发产生,ADC就会采样和转换规定的通道。
采样时间,每个通道可以用不同的时间采样。ADC使用若干个ADC_CLK周期对输入的电压进行采样,在12位分辨率的情况下,总转换时间=采样时间+12.5个ADCCLK周期。
采样周期数目可以通过ADC_SAMPT0和ADC_SAMPT1寄存器的SPTn[2:0]位更改。如下面所示。
如果想要采样的频率比较快,那么可以设置采样时间为1.5个ADCCLK周期。
/* ADC channel sample time */
#define SAMPTX_SPT(regval) (BITS(0,2) & ((uint32_t)(regval) << 0)) /*!< write value to ADC_SAMPTX_SPT bit field */
#define ADC_SAMPLETIME_1POINT5 SAMPTX_SPT(0) /*!< 1.5 sampling cycles */
#define ADC_SAMPLETIME_7POINT5 SAMPTX_SPT(1) /*!< 7.5 sampling cycles */
#define ADC_SAMPLETIME_13POINT5 SAMPTX_SPT(2) /*!< 13.5 sampling cycles */
#define ADC_SAMPLETIME_28POINT5 SAMPTX_SPT(3) /*!< 28.5 sampling cycles */
#define ADC_SAMPLETIME_41POINT5 SAMPTX_SPT(4) /*!< 41.5 sampling cycles */
#define ADC_SAMPLETIME_55POINT5 SAMPTX_SPT(5) /*!< 55.5 sampling cycles */
#define ADC_SAMPLETIME_71POINT5 SAMPTX_SPT(6) /*!< 71.5 sampling cycles */
#define ADC_SAMPLETIME_239POINT5 SAMPTX_SPT(7) /*!< 239.5 sampling cycles */
外部触发输入的上升沿可以触发规则组或注入组的转换。规则组的外部触发源由ADC_CTL1寄存器的ETSRC[2:0]位控制。外部触发信号的上升沿可以启动转换,那么就可以利用定时器的PWM输出模式获得上升沿。
这里选用TIMER0 CH0作为规则组的外部触发源。
DMA请求,设置ADC_CTL1寄存器的DMA位使能,ADC在规则组一个通道转换结束后产生一个DMA请求,DMA接受到请求后,将转换的数据从ADC_RDATA寄存器传输到用户指定的目的地址。RDATA[15:0],规则通道数据,这些位包含了规则通道的转换结果,只读。
下面的程序,其实还是根据手册的说明,修改寄存器的值,只不过用了一些库函数。
void rcu_config(void)
{/* enable GPIOC clock */rcu_periph_clock_enable(RCU_GPIOC);/* enable GPIOA clock */rcu_periph_clock_enable(RCU_GPIOA); /* enable DMA clock */rcu_periph_clock_enable(RCU_DMA0);/* enable TIMER0 clock */rcu_periph_clock_enable(RCU_TIMER0);/* enable ADC0 clock */rcu_periph_clock_enable(RCU_ADC0);/* config ADC clock */rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6);//rcu_periph_clock_enable(RCU_DAC);
}void gpio_config(void)
{gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
}void adc_config(void)
{
//配置ADC同步模式 ADC_MODE_FREE模式每个ADC都独立工作adc_mode_config(ADC_MODE_FREE);
//配置ADCx数据对齐方式adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
//使能或禁能ADC特殊功能-扫描模式选择adc_special_function_config(ADC0,ADC_SCAN_MODE,ENABLE);
//配置规则通道组或注入通道组的长度 通道长度,规则通道组为1-16,注入通道组为1-4adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,1);
//配置ADC规则通道组 ADC通道选择-采样时间adc_regular_channel_config(ADC0, 0,ADC_CHANNEL_10, ADC_SAMPLETIME_1POINT5);
//配置ADC外部触发adc_external_trigger_config(ADC0, ADC_REGULAR_CHANNEL, ENABLE);
//配置ADC外部触发源 TIMER0 CH0事件adc_external_trigger_source_config(ADC0, ADC_REGULAR_CHANNEL, ADC0_1_EXTTRIG_REGULAR_T0_CH0);
//使能ADCx外设adc_enable(ADC0);delay_1ms(1);
//ADCx校准复位 A/D 转换前执行校准操作,软件设置CLB=1来对校准进行初始化,
//校准期间CLB位会一直保持1,直到校准完成,该位由硬件清0。adc_calibration_enable(ADC0);
//ADCx DMA请求使能adc_dma_mode_enable(ADC0);
}
TIM
输出比较模式,TIMERx可以产生时控脉冲,当一个输出通道的TIMERx_CHxCV寄存器与计数器的值匹配时,根据CHxCOMCTL的配置,这个通道的输出可以被置高电平,被置低电平或者反转。
在PWM输出模式下,通道根据TIMERx_CAR寄存器和TIMERx_CHxCV寄存器的值,输出PWM波形,EAPWM(边沿对齐PWM)的周期由TIMERx_CAR寄存器值决定,占空比由TIMERx_CHxCV寄存器值决定。
PWM0模式,在向上计数时,一旦计数器值小于TIMERx_CH0CV时,O0CPRE为有效电平,否则为无效电平。在向下计数时,一旦计数器的值大于TIMERx_CH0CV时,O0CPRE为无效电平,否则为有效电平。
void timer_config(void)
{timer_oc_parameter_struct timer_ocintpara;timer_parameter_struct timer_initpara;/* TIMER0 configuration */timer_initpara.prescaler = 0;timer_initpara.alignedmode = TIMER_COUNTER_EDGE;//对齐模式timer_initpara.counterdirection = TIMER_COUNTER_UP;timer_initpara.period = 224;timer_initpara.clockdivision = TIMER_CKDIV_DIV1;timer_initpara.repetitioncounter = 0;timer_init(TIMER0, &timer_initpara);/* CH0 configuration in PWM mode0 */timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;//通道输出极性timer_ocintpara.outputstate = TIMER_CCX_ENABLE;//通道输出状态timer_channel_output_config(TIMER0, TIMER_CH_0, &timer_ocintpara);//外设TIMERx的通道输出配置timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 56);//配置外设TIMERx的通道输出比较值timer_channel_output_mode_config(TIMER0, TIMER_CH_0, TIMER_OC_MODE_PWM0);//配置外设TIMERx通道输出比较模式 PWM模式0timer_channel_output_shadow_config(TIMER0, TIMER_CH_0, TIMER_OC_SHADOW_DISABLE);//禁能输出比较影子寄存器/* TIMER0 所有的通道输出使能 */timer_primary_output_config(TIMER0, ENABLE);/* TIMERx自动重载影子使能 */timer_auto_reload_shadow_enable(TIMER0); /* enable TIMER0 */timer_enable(TIMER0);
}
DMA
ADC0外设请求被映射到DMA0通道0,下面就对DMA0通道0配置。
设置方向是外设到存储器。
CNT[15:0],该寄存器表明还有多少数据等待被传输。一旦通道使能,该寄存器为只读的,并在每个DMA传输之后值减1。
设置循环模式,循环模式用来处理连续的外设请求,循环模式中,当每次DMA传输完成后,CNT寄存器会被自动重装载为初始设置值。
源地址,规则数据寄存器 (ADC_RDATA) :RDATA[15:0],规则通道数据,这些位包含了规则通道的转换结果,只读。
uint32_t adc_value[120];
void dma_config(void)
{/* ADC_DMA_channel configuration DMA初始化结构体 */dma_parameter_struct dma_data_parameter;/* ADC_DMA_channel deinit */dma_deinit(DMA0, DMA_CH0);/* initialize DMA single 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_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 = 120;//DMA通道数据传输数量dma_data_parameter.priority = DMA_PRIORITY_HIGH; dma_init(DMA0, DMA_CH0, &dma_data_parameter);dma_circulation_enable(DMA0, DMA_CH0);//设置dma中断优先级//nvic_irq_enable(DMA0_Channel0_IRQn, 0, 0);/* enable DMA transfer complete interrupt *///dma_interrupt_enable(DMA0,DMA_CH0, DMA_INT_FTF);/* enable DMA channel */dma_channel_enable(DMA0, DMA_CH0);
}
其他一些初始化
这个里面修改rcu_adc_clock_config可以改变ADC采集的频率。
//存储adc数据的内存数组
uint32_t adc_value[120];
void rcu_config(void)
{/* enable GPIOC clock */rcu_periph_clock_enable(RCU_GPIOC);/* enable GPIOA clock */rcu_periph_clock_enable(RCU_GPIOA); /* enable DMA clock */rcu_periph_clock_enable(RCU_DMA0);/* enable TIMER0 clock */rcu_periph_clock_enable(RCU_TIMER0);/* enable ADC0 clock */rcu_periph_clock_enable(RCU_ADC0);/* enable ADC1 clock */rcu_periph_clock_enable(RCU_ADC1);/* config ADC clock */rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6);rcu_periph_clock_enable(RCU_DAC);
}void gpio_config(void)
{gpio_init(GPIOC, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_0);
}
main
int main(void)
{rcu_config();systick_config(); gpio_config();timer_config();dma_config();adc_config();gd_eval_com_init(EVAL_COM0);sin_app();uint16_t i =0;while(1){if(i==120) i=0;printf("%.3f\r\n",(float)adc_value[i]* 3.3f / 4096.0f);++i;}
}
总结
连续转换模式运行在规则组通道上,TIMER0 CH0外部触发产生,ADC就会采样和转换指定的通道(ADC0 CHANNEL_10,采集PC0引脚的电压)。
外部触发输入的上升沿可以触发规则组或注入组的转换,利用定时器的PWM输出模式获得上升沿,其中设置定时器的时候,改变计数器自动重载值(TIMERx_CAR)和输出比较值(TIMERx_CH0CV寄存器)可以改变触发的频率。
ADC在规则组一个通道转换结束后产生一个DMA请求,DMA接受到请求后,将转换的数据从ADC_RDATA寄存器传输到用户指定的目的地址。(ADC0外设请求被映射到DMA0通道0)
DAC输出一个电压,加到PC0引脚上,然后用ADC采集。
改采集的频率:使其刚好在一个波形周期采120个点。
主要修改的地方:
rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV6);//RCU_CKADC_CKAPB2_DIV6
adc_regular_channel_config(ADC0, 0,ADC_CHANNEL_10, ADC_SAMPLETIME_1POINT5);//ADC_SAMPLETIME_1POINT5
timer_initpara.period = 224;
timer_channel_output_pulse_value_config(TIMER0, TIMER_CH_0, 56);//配置外设TIMERx的通道输出比较值
dma_data_parameter.number = 120;//DMA通道数据传输数量