STM32G0-ADC+DMA采集50HZ市电

 1.STM32CubeMX的基础配置

 首先勾选Serial Wire(串行线配置调试), 使用内部时钟

勾选ADC1,根据需要配置对应的采集通道(见下图)

Clock Prescaler:是ADC工作频率,选择Asynchronous clock mode divided by 2(2分频)。

Resolution :ADC分辨率,设置为12位分辨率。

Data Alignment:数据对齐方式,配置为右对齐。

Sequencer:Sequencer set to fully configurable (完全序列模式)。

Scan Conversion Mode:ENABLE扫描转化模式。

Continuous Conversion Mode:ENABLE连续转换模式,这种模式下,ADC会持续不断地采样并转换模拟信号,并且对所有通道进行一 次转换,随后会自动重启并持续执行相同的转换序列

DMA Continuous Requests:ENABLE允许外设在每次数据传输完成后自动发出请求。这个请求会持续地触发DMA传输,直到传输完成或被外部事件停止。

 End Of Conversion Selection:ENABLE End of Single Conversion(单次转换结束)。

 SamplingTime Common 1 :设定采样周期。

 Number Of Conversion:转换通道数,数值代表一次性转换几个通道。

 External Trigger Conversion Source :此处选择软件触发方式。

 配置DMA:

         DMA选择Circular,开启不断循环;Half Word存放uint16_t类型数据

 采用内部时钟,DMA中断默认打开,ADC中断不打开,定义好之后直接生成。

 ADC采样时间计算:

       1.ADC采样时间长短由分频系数和采样周期决定,计算公式:转换时间=采样周期+12.5周期

eg:工程里面的时钟频率是64MHZ,T = 1/f = 1/64=0.015625;则55.5+12.5 = 68周期,68*1/64 = 1.0625us。

       2.由于要采集频率为50HZ,220V的交流电,硬件方面需要做好采集和隔离使其产生的信号能快速的让ADC采集到,此处具体电路不做论述;ADC采集的思路:利用交流电20ms产生一个周期的波形,设置定时器1ms触发一次中断,在中断服务函数里面循环读取20msADC采集的瞬时值,这20ms的值就是市电的一个周期,之后将20次数据之和就可以判断市电是否接入。

static uint8_t ADC_Count = 0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* AdcHandle)
{
	if(AdcHandle->Instance == ADC1)
	{
		ADC_Count++;
		if(ADC_Count >= 20)
		{
			// 清零临时存储
            adcValue.value1 = 0;
            adcValue.value2 = 0;
            adcValue.value3 = 0;
            adcValue.value4 = 0;
            adcValue.value5 = 0;
            adcValue.value6 = 0;
			
			for(uint8_t i=0;i<20;i++)
			{
				adcValue.value1 += ADC_value[0+6*i];                
				adcValue.value2 += ADC_value[1+6*i];
				adcValue.value3 += ADC_value[2+6*i];                
				adcValue.value4 += ADC_value[3+6*i];
				adcValue.value5 += ADC_value[4+6*i];                
				adcValue.value6 += ADC_value[5+6*i];
			}
			
			ADC_Count = 0;
		}
	}
}

uint8_t Collect_data()          //采集单次瞬时数据
{
	// 处理瞬时值
	total_sum1[count] = (adcValue.value1/20);
	total_sum2[count] = (adcValue.value2/20);
	total_sum3[count] = (adcValue.value3/20);
	total_sum4[count] = (adcValue.value4/20);
	total_sum5[count] = (adcValue.value5/20);
	total_sum6[count] = (adcValue.value6/20);
	count++;
	if(count >= 20)
	{
		total_1 = 0;
		total_2 = 0;
		total_3 = 0;
		total_4 = 0;
		total_5 = 0;
		total_6 = 0;
		for(uint8_t i=0;i<20;i++)
		{
			total_1 += total_sum1[i];
			total_2 += total_sum2[i];
			total_3 += total_sum3[i];
			total_4 += total_sum4[i];
			total_5 += total_sum5[i];
			total_6 += total_sum6[i];
		}
		
		if(total_1>=200)       {PDU_stusta |= (1<<0);}
		else                   {PDU_stusta &= ~(1 << 0);}

		if(total_2>=200)       {PDU_stusta |= (1<<1);}
		else                   {PDU_stusta &= ~(1 << 1);}
		
		if(total_3>=200)       {PDU_stusta |= (1<<2);} 
		else                   {PDU_stusta &= ~(1 << 2);}
		
		if(total_4>=200)       {PDU_stusta |= (1<<3);}
	    else                   {PDU_stusta &= ~(1 << 3);}

		if(total_5>=200)       {PDU_stusta |= (1<<4);}
		else                   {PDU_stusta &= ~(1 << 4);}
		
		if(total_6>=200)       {PDU_stusta |= (1<<5);}
		else                   {PDU_stusta &= ~(1 << 5);}
	
		count = 0;
	}
	return 0;
}

  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,需要配置定时器 TIM2 以产生 50Hz 的采样率。TIM2 的时钟源为 APB1,因此需要在 RCC 中使能 APB1 的时钟。然后配置 TIM2 的预分频器和自动重载值,使得定时器的时钟为 1MHz,采样率为 50Hz。具体配置如下: ```c RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_TimeBaseInitStruct.TIM_Prescaler = 64-1; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Period = 20000-1; TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); TIM_Cmd(TIM2, ENABLE); ``` 然后需要配置 ADC,使其使用 DMA 进行数据传输。首先需要在 RCC 中使能 ADCDMA 和 GPIO 的时钟。然后配置 ADC 的通道和采样时间,以及 DMA 的数据传输方向和数据长度。最后启动 ADCDMA。具体配置如下: ```c RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; GPIO_Init(GPIOA, &GPIO_InitStruct); ADC_InitTypeDef ADC_InitStruct; ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_TRGO; ADC_InitStruct.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising; ADC_InitStruct.ADC_NbrOfConversion = 1; ADC_InitStruct.ADC_Resolution = ADC_Resolution_12b; ADC_InitStruct.ADC_ScanConvMode = DISABLE; ADC_Init(ADC1, &ADC_InitStruct); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); DMA_InitTypeDef DMA_InitStruct; DMA_InitStruct.DMA_BufferSize = 192; DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&adc_data; DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStruct.DMA_Priority = DMA_Priority_High; DMA_Init(DMA1_Channel1, &DMA_InitStruct); ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular); ADC_DMACmd(ADC1, ENABLE); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_Cmd(ADC1, ENABLE); ``` 最后在每次 DMA 传输完成后,可以在 DMA 的传输完成中断中进行数据处理。每次 DMA 传输完成后,会有 192 个采样数据存储在 adc_data 数组中。具体实现可以参考以下代码: ```c void DMA1_Channel1_IRQHandler(void) { if (DMA_GetITStatus(DMA1_IT_TC1) != RESET) { DMA_ClearITPendingBit(DMA1_IT_TC1); // 在这里进行数据处理 } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值