基于STM32F103C8T6ADC检测交流电压

本文介绍了一种利用STM32单片机及其ADC外设配合DMA进行高效交流电压采集的方法。通过硬件电路设计,实现了信号的放大与调理,并详细阐述了STM32 ADC初始化设置及采样过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上篇文章写了硬件部分的实现思路,通过采样电阻的到小电压后经过二级放大电路得到单片机可处理的交流电压,此文介绍了如何采用单片机采集交流电压以及stm32ADC外设的使用。首先是硬件电路部分。

 电路没有采用核心板,而是直接将芯片焊接到主板上,采用type-c接口供电,调参采用五轴按键,参数及测量结果显示采用0.96寸OLED显示,采用有源蜂鸣器作为报警电路。PCB如图所示

 交流电压经放大后到达ADC口,此时即可进行ADC采样。

ADC采样采用DMA的方式,初始化主要有两个方面:

一:GPIO的初始化


static void ADCx_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
	
	  //打开 ADC IO 端口时钟
    ADC_GPIO_APBxClock_FUN(ADC_GPIO_CLK,ENABLE);
  
    //配置ADC IO 引脚模式
    //必须为模拟输入
    GPIO_InitStructure.GPIO_Pin = ADC_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    
    //初始化ADC IO
    GPIO_Init(ADC_PORT,&GPIO_InitStructure);	
}

二:DMA的初始化

static void ADCx_Mode_Config(void)
{
    DMA_InitTypeDef DMA_InitStructure;
	  //打开DMA时钟
	  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);  
	  
	  //复位DMA
	  DMA_DeInit(ADC_DMA_CHANNEL);
	  DMA_InitStructure.DMA_PeripheralBaseAddr = ( uint32_t ) ( & (ADC_x->DR ) );
	  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue;
	  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	  DMA_InitStructure.DMA_BufferSize = 1;
	  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
	  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
	  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
	  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//Normal是一直传输
	  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	  DMA_Init(ADC_DMA_CHANNEL,&DMA_InitStructure);
	  DMA_Cmd(ADC_DMA_CHANNEL,ENABLE);
	
	  ADC_InitTypeDef ADC_InitStruct;
	  
	  ADC_APBxClock_FUN ( ADC_CLK, ENABLE );
	  ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
	  ADC_InitStruct.ADC_ScanConvMode = DISABLE;
	  ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //一直转换
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   //软件触发
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;  //右对齐
    ADC_InitStruct.ADC_NbrOfChannel = 1;    //转换通道为一个	
	  
	  ADC_Init(ADC_x, &ADC_InitStruct);
	  
	  RCC_ADCCLKConfig(RCC_PCLK2_Div8);
	  ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL,1, ADC_SampleTime_55Cycles5);

    //使能ADC DMA请求
		ADC_DMACmd(ADC_x,ENABLE);

	  ADC_Cmd(ADC_x,ENABLE);
	  //校准ADC
	  ADC_StartCalibration(ADC_x);
	  //等待校准完成
	  while(ADC_GetCalibrationStatus(ADC_x));

	  //采用软件触发
		ADC_SoftwareStartConvCmd(ADC_x,ENABLE);
}

此时采用DMA传输,ADC采样使用软件触发。在这里我的理解是只要ADC一个周期转换完成即开始下一次转换。DMA时刻在更新变量的值。

u16  ch_rms_value(void)
{
    u32 sum = 0;
    u32 value[200] = {0};
    u16 rms = 0;
    u16 i = 0;
		float squ = 0;
    for(i = 0; i < 200; i++)		   //20ms  采样200个点
    {
        value[i] = ADC_ConvertedValue;
        delay_us(100);
    }
		for(i = 0; i < 200; i++)
    {
				squ= __fabs(value[i] - 2085.236);
				sum += squ*squ;
    }
    rms = mySqrt(sum / 200);			//求均方根值
    return rms;
}

计算交流电压主要是均方根算法,因交流电压为市电50Hz,故我们选择在20ms的周期内采样200个点。采用的算法是简单的delay 100us然后采样二百个。在精度要求不高的情况下是可以接受的,若精度要求较高可以自行写在中断中自动读取。具体的工程可在主页中获取

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值