打印
[其他ST产品]

基于STM32F103C8T6ADC检测交流电压

[复制链接]
1568|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
上篇文章写了硬件部分的实现思路,通过采样电阻的到小电压后经过二级放大电路得到单片机可处理的交流电压,此文介绍了如何采用单片机采集交流电压以及stm32ADC外设的使用。首先是硬件电路部分。





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


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

使用特权

评论回复
沙发
结合国际经验|  楼主 | 2023-5-30 15:49 | 只看该作者
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);       
}

使用特权

评论回复
板凳
结合国际经验|  楼主 | 2023-5-30 15:49 | 只看该作者
二: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);
}

使用特权

评论回复
地板
结合国际经验|  楼主 | 2023-5-30 15:50 | 只看该作者
此时采用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;
}

使用特权

评论回复
5
结合国际经验|  楼主 | 2023-5-30 15:50 | 只看该作者
计算交流电压主要是均方根算法,因交流电压为市电50Hz,故我们选择在20ms的周期内采样200个点。采用的算法是简单的delay 100us然后采样二百个。在精度要求不高的情况下是可以接受的,若精度要求较高可以自行写在中断中自动读取。具体的工程可在主页中获取

使用特权

评论回复
6
sdlls| | 2023-6-7 21:21 | 只看该作者
可以测量负电压吗?              

使用特权

评论回复
7
maqianqu| | 2023-6-8 15:34 | 只看该作者
有效电压是你怎么测量的              

使用特权

评论回复
8
uptown| | 2023-6-8 16:49 | 只看该作者
如何检测交流电源的幅值?              

使用特权

评论回复
9
kissdb| | 2023-6-10 15:37 | 只看该作者
学习一下,多发点资料

使用特权

评论回复
10
AloneKaven| | 2023-6-10 23:42 | 只看该作者
精度怎么样啊?

使用特权

评论回复
11
Jacquetry| | 2023-6-11 23:06 | 只看该作者
sdlls 发表于 2023-6-7 21:21
可以测量负电压吗?

反相一下就可以

使用特权

评论回复
12
sesefadou| | 2023-6-13 23:01 | 只看该作者
测量的精度怎么样?
              

使用特权

评论回复
13
macpherson| | 2023-6-14 15:08 | 只看该作者
这个需要电容转换电压的吗?              

使用特权

评论回复
14
modesty3jonah| | 2023-6-15 22:06 | 只看该作者
比较常用的方法是使用变压器来将交流电压降低到单片机可以接受的范围内,然后使用模拟输入口读取电压信号,并通过程序进行处理和计算。

使用特权

评论回复
15
Bowclad| | 2023-6-15 22:43 | 只看该作者
maqianqu 发表于 2023-6-8 15:34
有效电压是你怎么测量的

每采样一个数据后,先对这个数据取平方,然后计算累加和,采样一定数量数据之后,对累加的平方和求平均值,然后再开方

使用特权

评论回复
16
Jacquetry| | 2023-6-18 23:30 | 只看该作者
测量精度怎么样啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

60

主题

692

帖子

1

粉丝