GD32 ADC采样(2)

上一篇讲的是简单版的采样。这一篇讲要求比较高的采样。比较精准。


1、定时器初始化

void TimerAdc0Init(void)
{ 
		timer_oc_parameter_struct    timer_ocintpara;
		timer_parameter_struct       timer_initpara;
	
		rcu_periph_clock_enable(RCU_TIMER1);  
			/*************************TIMER1_CH0配置为互补输出******************************/
		/* TIMER1 configuration */
		timer_deinit(TIMER1);
		timer_initpara.prescaler		 = 0;			         //预分频系数    不分频
		timer_initpara.alignedmode		 = TIMER_COUNTER_EDGE;   //对齐方式      边沿对齐
		timer_initpara.counterdirection  = TIMER_COUNTER_UP;     //计数方向      向上计数
		timer_initpara.period			 = ADC0_TRIGGER_PWM_PTPER;   //PWM周期       20K
		timer_initpara.clockdivision	 = TIMER_CKDIV_DIV1;     //系统时钟分频  不分频
		timer_initpara.repetitioncounter = 0;                    //重复计数值    不重复计数
		timer_init(TIMER1,&timer_initpara);	

    /* CH0--trigger ADC config*/
    timer_ocintpara.ocpolarity  = TIMER_OC_POLARITY_LOW;     //通道输出极性低有效
    timer_ocintpara.outputstate = TIMER_CCX_ENABLE;          //CH通道使能  
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_HIGH; //空闲输出低,只有上升沿才能触发ADC采样,
                                                             //若空闲输出高只能在周期开始触发ADC采样
    timer_channel_output_config(TIMER1,TIMER_CH_0,&timer_ocintpara);       
    /* PWMHL---CH0--trigger ADC*///采样点在充电主开关管占空比一半 
    timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_0,ADC0_DEFAULT_TRIGGER_TIME);   //定时器通道脉冲值设置
    timer_channel_output_mode_config(TIMER1,TIMER_CH_0,TIMER_OC_MODE_PWM0);                 //定时器输出模式
    timer_channel_output_shadow_config(TIMER1,TIMER_CH_0,TIMER_OC_SHADOW_ENABLE); //定时器影子寄存器设置
; 

    /* TIMER1 primary output function enable */
    timer_primary_output_config(TIMER1,ENABLE);//定时器输出使能

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER1);//定时器自动重装载使能
    timer_counter_value_config(TIMER1,0);//定时器初始计数值

    /* TIMER1 counter enable */
    timer_enable(TIMER1);
}

2、ADC初始化

void Adc0Init(void)
{
		dma_parameter_struct dma_data_parameter;
	
		rcu_periph_clock_enable(RCU_ADC0);	 
		rcu_periph_clock_enable(RCU_DMA0);
		rcu_periph_clock_enable(RCU_GPIOA);
		rcu_periph_clock_enable(RCU_GPIOB);

	  //采样通道GPIO引脚配置
        gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_4); //VLA1
        gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_5); //ILB1
        gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_6); //VLB1  
        gpio_init(GPIOA, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_7); //ILA1
        gpio_init(GPIOB, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_0); //VoutA1
        gpio_init(GPIOB, GPIO_MODE_AIN, GPIO_OSPEED_50MHZ, GPIO_PIN_1); //VoutB1

	    adc_deinit(ADC0);        //  reset ADC
	
		/* config ADC clock */
		rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV4); // 120M/4 = 30MHZ
		
	    /*inserted channel NVIC  configure */ 
		NVIC_SetPriority(ADC0_1_IRQn,0);
		NVIC_EnableIRQ(ADC0_1_IRQn);
		
		/* ADC DMA_channel configuration */
		dma_deinit(DMA0,DMA_CH0);
		
		/* initialize DMA single data mode */
		dma_data_parameter.periph_addr    = (uint32_t)(&ADC_RDATA(ADC0));   // DMA传输数据源地址
		dma_data_parameter.periph_inc	  = DMA_PERIPH_INCREASE_DISABLE;    // DMA传输地址不增加
		dma_data_parameter.memory_addr    = (uint32_t)cAdc0Sample;          // DMA传输目的地
		dma_data_parameter.memory_inc	  = DMA_MEMORY_INCREASE_ENABLE;     // DMA传输内存地址增加
		dma_data_parameter.periph_width   = DMA_PERIPHERAL_WIDTH_16BIT;     // 外设数据宽度为16bit
		dma_data_parameter.memory_width   = DMA_MEMORY_WIDTH_16BIT;	        // 内存数据宽度为16bit
		dma_data_parameter.direction	  = DMA_PERIPHERAL_TO_MEMORY;       // 传输方向:外设到内存
		dma_data_parameter.number		  = 2;                              // 传输次数
		dma_data_parameter.priority	      = DMA_PRIORITY_HIGH;              // 优先级
		dma_init(DMA0,DMA_CH0,&dma_data_parameter);
		/* configure DMA mode */
		dma_circulation_enable(DMA0,DMA_CH0);
		dma_memory_to_memory_disable(DMA0,DMA_CH0);
		
		adc_special_function_config(ADC0,ADC_SCAN_MODE |ADC_CONTINUOUS_MODE, ENABLE);   // adc连续功能使能
		adc_external_trigger_source_config(ADC0,ADC_REGULAR_CHANNEL, ADC0_1_2_EXTTRIG_REGULAR_NONE);     //软件触发
		adc_external_trigger_source_config(ADC0,ADC_INSERTED_CHANNEL, ADC0_1_EXTTRIG_INSERTED_T1_CH0);   //T1_CH0触发
		
	    adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT); //数据对齐方式
		adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL, 2); //规则通道长度
		adc_channel_length_config(ADC0,ADC_INSERTED_CHANNEL, 4);//注入通道长度
		
		adc_regular_channel_config(ADC0,0, CH0_ADC_OUT_A_VOLT,ADC_SAMPLETIME_71POINT5);//规则通道设置
		adc_regular_channel_config(ADC0,1, CH0_ADC_OUT_B_VOLT,ADC_SAMPLETIME_71POINT5);

		adc_inserted_channel_config(ADC0,0,CH0_ADC_IN_A_VOLT , ADC_SAMPLETIME_7POINT5);//注入通道设置
		adc_inserted_channel_config(ADC0,1,CH0_ADC_IN_B_VOLT , ADC_SAMPLETIME_7POINT5);
        adc_inserted_channel_config(ADC0,2,CH0_ADC_IN_A_CURRENT , ADC_SAMPLETIME_7POINT5);
        adc_inserted_channel_config(ADC0,3,CH0_ADC_IN_B_CURRENT, ADC_SAMPLETIME_7POINT5);

    //adc_oversample_mode_config(ADC_OVERSAMPLING_ALL_CONVERT,ADC_OVERSAMPLING_SHIFT_3B,ADC_OVERSAMPLING_RATIO_MUL8);
    //adc_oversample_mode_enable();
		adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL, ENABLE); // 外部触发使能
		adc_external_trigger_config(ADC0,ADC_INSERTED_CHANNEL, ENABLE);
		adc_dma_mode_enable(ADC0);//DMA模式使能
		adc_interrupt_enable(ADC0,ADC_INT_EOIC);//ADC中断使能
		adc_enable(ADC0);//ADC使能

		Afx_Delay10us(1000);  
		adc_calibration_enable(ADC0);//ADC复位
		Afx_Delay10us(1000);

		dma_channel_enable(DMA0,DMA_CH0);//DMA通道使能
		adc_software_trigger_enable(ADC0,ADC_REGULAR_CHANNEL);//使能ADC软件触发
}

经过上面两个部分,采样的底层已经配置的差不多了。接下来就是获取采样值和计算采样值。

3、ADC基准系数

我这边硬件的基准为1.5v,所以,采样基准系数为1.5/3.3*4096=1862,所以采样基准为1862

    AdcSampleRef.i16LineAInVolAd     = 1862;

4、ADC采样系数

ADC采样值的计算为3.3/4096/硬件的采样系数

    AdcSampleKscal.i16LineAInVolAd     = 0.118654*4096;

5、获取ADC采样值

ADC通道采样值-ADC基准系数

    AdcSampleData.i16LineAInVolAd     = ADC_IDATA0(ADC0) - AdcSampleRef.i16LineAInVolAd;//注入组0
    AdcSampleData.i16LineAOutVolAd     = cAdc0Sample[0] - AdcSampleRef.i16LineAOutVolAd;//规则组0

6、获取ADC真实值

ADC采样值*ADC采样系数 = ADC真实值

采样系数*4096,真实值得/4096(>>12)

    i32AdcRealDataCal                     = AdcSampleData.i16LineAInVolAd * AdcSampleKscal.i16LineAInVolAd;
    AdcSampleRealData.i16LineAInVolAd     = (i32AdcRealDataCal>>12);

7、计算ADC真实值平均值

void sGetSampleDataSum(void)
{
    AdcDataSum.i32LineAInVol    += AdcSampleRealData.i16LineAInVolAd * AdcSampleRealData.i16LineAInVolAd;
}
int16_t sAvergerSqrtCal(int32_t i32RealDataSum, int32_t i32SumCounter)
{
    int16_t i16RealDataSqrt = 0;
		i16RealDataSqrt  = (int16_t)(sqrt(i32RealDataSum / i32SumCounter));
   	return i16RealDataSqrt;
}
void sGetEffectiveDataCal(void)//此任务最好放在过零点捕获中断中
{
    AdcEffectiveData.i16LineAInVolAd     = sAvergerSqrtCal(AdcDataSum.i32LineAInVol,AdcDataSum.i32AdSumTimes);
}

这样就可以计算出ADC采样电压了。

8、最后补一个ADC中断

void ADC0_1_IRQHandler(void)
{
    //PWM每周期触发一次ADC采样,触发周期是PWM的两倍
    //故1个中断进行一次PI运算
	  if(adc_interrupt_flag_get(ADC0,ADC_INT_FLAG_EOIC))
		{
				adc_interrupt_flag_clear(ADC0,ADC_INT_FLAG_EOIC); 		//清除中断标志位
				sGetAdc0ScanSampleData();                             //ADC0规则、注入组采样
				sGetAdc0SampleRealData();                             //基准采样和计算
				sGetSampleDataSum();                                  //ADC真实值累加
		}
}

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,以下是配置GD32F303 ADC+DMA采样使用注入模式的代码: ```c #include "gd32f30x.h" #define ADC_GPIO_PORT GPIOA #define ADC_GPIO_PIN GPIO_PIN_0 #define ADC_CHANNEL ADC_CHANNEL_0 #define ADC_SAMPLE_TIME ADC_SAMPLETIME_55POINT5 #define ADC_INJ_SEQ ADC_INSERTED_CHANNEL_1 #define ADC_INJ_SEQ_LEN 1 #define DMA_CHANNEL DMA_CHANNEL_0 #define DMA_PRIORITY DMA_PRIORITY_HIGH #define DMA_MODE DMA_CIRCULAR #define DMA_INC DMA_INC_DISABLE #define DMA_SIZE DMA_SIZE_16BITS void adc_dma_init(void); void adc_gpio_init(void); int main(void) { /* 使能 DMA 和 ADC 时钟 */ rcu_periph_clock_enable(RCU_DMA0); rcu_adc_clock_enable(); /* 初始化 GPIO 和 ADC */ adc_gpio_init(); adc_dma_init(); /* 配置注入序列 */ adc_inserted_channel_config(ADC0, ADC_INJ_SEQ, ADC_CHANNEL, ADC_SAMPLE_TIME, ADC_INJ_SEQ_LEN); /* 配置 DMA 触发源为 ADC 注入完成事件 */ dma_channel_parameter_struct dma_channel; dma_deinit(DMA0, DMA_CHANNEL); dma_channel_init(DMA0, DMA_CHANNEL, &dma_channel); dma_circulation_disable(DMA0, DMA_CHANNEL); dma_periph_address_config(DMA0, DMA_CHANNEL, (uint32_t)&ADC_RDATA(ADC0)); dma_memory_address_config(DMA0, DMA_CHANNEL, (uint32_t)data_array); dma_transfer_direction_config(DMA0, DMA_CHANNEL, DMA_PERIPHERAL_TO_MEMORY); dma_transfer_number_config(DMA0, DMA_CHANNEL, 1); dma_periph_inc_mode_config(DMA0, DMA_CHANNEL, DMA_INC_DISABLE); dma_memory_inc_mode_config(DMA0, DMA_CHANNEL, DMA_INC_ENABLE); dma_periph_data_size_config(DMA0, DMA_CHANNEL, DMA_SIZE); dma_memory_data_size_config(DMA0, DMA_CHANNEL, DMA_SIZE); dma_priority_config(DMA0, DMA_CHANNEL, DMA_PRIORITY_HIGH); dma_circulation_enable(DMA0, DMA_CHANNEL); dma_channel_enable(DMA0, DMA_CHANNEL); /* 启动 ADC 和 DMA */ adc_software_trigger_enable(ADC0, ADC_INSERTED_CHANNEL); adc_dma_mode_enable(ADC0); adc_enable(ADC0); while (1) { /* 循环等待 DMA 传输完成 */ while (dma_flag_get(DMA0, DMA_CHANNEL, DMA_FLAG_FTF) == RESET); /* 处理数据 */ // ... /* 清除 DMA 标志 */ dma_flag_clear(DMA0, DMA_CHANNEL, DMA_FLAG_FTF); } } void adc_dma_init(void) { /* 配置 DMA 时钟和中断 */ nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); dma_interrupt_enable(DMA0, DMA_CHANNEL, DMA_INT_FTF); } void adc_gpio_init(void) { /* 配置 GPIO 时钟 */ rcu_periph_clock_enable(RCU_GPIOA); /* 配置 GPIO 为模拟输入 */ gpio_mode_set(ADC_GPIO_PORT, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, ADC_GPIO_PIN); } ``` 以上代码实现了 ADC+DMA 采样,使用了注入模式。在代码中,我们使用了 DMA 进行数据传输,并启用了循环模式,使得 DMA 可以不断地将 ADC 采集到的数据传输到内存中。同时,我们还配置了注入序列,并将 DMA 触发源设置为 ADC 注入完成事件,以便 DMA 能够及时地捕获到 ADC 采集完成的事件。在主循环中,我们循环等待 DMA 传输完成,并在传输完成后对数据进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一叶舞澎湃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值