前言
电源方向资料免费开源到QQ群280730348,欢迎进群交流沟通。博客地址edadong.com,博文同步发布在知乎、bilibili,其中bilibili主要以视频为主。建议去B站听详细视频解说。
交流电压检测需要通过单片机ADC分点采集交流电压周期内多点电压,求均方根后才能求得。STM32F4系列单片机内部有DSP库,所以直接调用DSP库内函数就可以得到交流信号有效值,今天就是对F4系列单片机的交流电压采样进行代码分享。
交流电压检测代码思路
交流电压存在周期,我们需要设定如下思路,才能够还原交流电压信号的有效值:
- 确认PWM驱动波频率,如20KHz驱动情况下,采集交流信号的频率必须是这个频率的1/整数倍。通常我们在定时器中断中完成这个功能。
- 确认采样点数,一个周期内采样点数越高,得到的有效值就更稳定可靠。比如一个周期内采集200个点做均方根,但这个过程会出现一个问题,采样点数过高,系统运行过于缓慢,会影响到波形的产生,拉宽波形频率,并且在最终均方根运算的时候占用过多的时间。
- 确认ADC采样路数,采样时间,计算单次采样所需要的时间,避免时间不够无法获得最新的电压数据。
- 确认基准电压大小,减去对应基准电压值。
- 确认交流电压缩放倍数,用于还原对应真实交流电压大小。
- 采集到足够多的数据后,执行均方根算法。
以上就是采集交流电压的代码思路,那我们开始介绍每一段代码
(1)确认PWM驱动频率和采样点数,开启采集交流信号的对应频率中断,此处我们采取同频定时器,中断内部计数的方式。由于我们采样点数确认为200,交流正弦波输出为50Hz,交流信号频率为20KHz,所以一个完整周期会执行400次中断。每进入2次中断执行一次交流单点电压采集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
| Inverter_SPWM_Iint(20000,0);
void Inverter_SPWM_Iint(uint32_t pfreq, uint16_t psc) { GPIO_InitTypeDef GPIO_InitStruct; TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; TIM_OCInitTypeDef TIM_OCInitStruct; TIM_BDTRInitTypeDef TIM_BDTRInitStruct; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz; GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_TIM8); GPIO_PinAFConfig(GPIOA, GPIO_PinSource7, GPIO_AF_TIM8);
TimerPeriod = (SystemCoreClock / pfreq) - 1;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);
TIM_DeInit(Inverter_TIMX);
TIM_TimeBaseInitStruct.TIM_ClockDivision = 0; TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInitStruct.TIM_Period = TimerPeriod; TIM_TimeBaseInitStruct.TIM_Prescaler = psc; TIM_TimeBaseInit(Inverter_TIMX, &TIM_TimeBaseInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStruct.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OCInitStruct.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStruct.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStruct.TIM_OCNIdleState = TIM_OCNIdleState_Reset; TIM_OCInitStruct.TIM_Pulse = TimerPeriod / 2 - 1; TIM_OC1Init(Inverter_TIMX, &TIM_OCInitStruct); TIM_OC1PreloadConfig(Inverter_TIMX, TIM_OCPreload_Enable);
TIM_BDTRInitStruct.TIM_OSSIState = TIM_OSSIState_Disable; TIM_BDTRInitStruct.TIM_OSSRState = TIM_OSSRState_Disable; TIM_BDTRInitStruct.TIM_LOCKLevel = TIM_LOCKLevel_1; TIM_BDTRInitStruct.TIM_DeadTime = 0; TIM_BDTRInitStruct.TIM_BreakPolarity = TIM_BreakPolarity_Low; TIM_BDTRInitStruct.TIM_Break = TIM_Break_Disable; TIM_BDTRInitStruct.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig(Inverter_TIMX, &TIM_BDTRInitStruct);
TIM_ITConfig(Inverter_TIMX, TIM_IT_Update, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_TIM13_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
TIM_ARRPreloadConfig(Inverter_TIMX, ENABLE);
TIM_Cmd(Inverter_TIMX, ENABLE);
TIM_CtrlPWMOutputs(Inverter_TIMX, ENABLE); }
void TIM8_UP_TIM13_IRQHandler(void) { if(TIM_GetITStatus(Inverter_TIMX, TIM_IT_Update) == SET) { static u32 count=0; if(count++%2) { calculate_rms(); }
} TIM_ClearITPendingBit(Inverter_TIMX, TIM_IT_Update); }
|
(2)配置ADC和高速DMA采集代码,一个通道输出,同时配置采样精度(也就是配置采样时间)
adc.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| #include "adc.h" #include "stm32f4xx_adc.h" #include "stm32f4xx_dma.h"
#define BufferSize (6*10)
static u16 DMA_Buf[BufferSize]={0}; u16 *adc_result=DMA_Buf; static void DMA_Config(void); static void GPIO_Config(void); static void ADC1_CH3_CH4_CH14_Config(void); static void ADC2_CH5_CH6_CH15_Config(void);
void adc_init(void) { ADC_CommonInitTypeDef ADC_CommonInitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE); DMA_Config(); GPIO_Config();
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult; ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4; ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1; ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles; ADC_CommonInit(&ADC_CommonInitStructure); ADC1_CH3_CH4_CH14_Config(); ADC2_CH5_CH6_CH15_Config(); ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE); ADC_Cmd(ADC1, ENABLE); ADC_Cmd(ADC2, ENABLE); ADC_SoftwareStartConv(ADC1); } static void DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&DMA_Buf; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(ADC1_BASE+0x300+0x8); DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = BufferSize; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &DMA_InitStructure); DMA_Cmd(DMA2_Stream0, ENABLE); }
static void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4 | GPIO_Pin_5; GPIO_Init(GPIOC, &GPIO_InitStructure); }
static void ADC1_CH3_CH4_CH14_Config(void) { ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 3; ADC_Init(ADC1, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 1, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 2, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 3, ADC_SampleTime_56Cycles); }
static void ADC2_CH5_CH6_CH15_Config(void) { ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfConversion = 3; ADC_Init(ADC2, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC2, ADC_Channel_5, 1, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 2, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC2, ADC_Channel_15, 3, ADC_SampleTime_56Cycles); }
|
adc.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| #ifndef ADC_H #define ADC_H
#include "stm32f4xx.h"
void adc_init(void); extern u16 *adc_result;
#endif
|
(3)定义基准电压和交流电压缩放倍数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
float AC_Vout_vref=1.54650f; float AC_Vout_ratio=50.4557f;
float AC_Iout_vref=1.51600f; float AC_Iout_ratio=3.3333f;
float AC_Vin_verf=1.52400f; float AC_Vin_ratio=51.2035f;
float DC_Vin_verf=0.0000f; float DC_Vin_ratio=33.0655f;
float DC_Iin_verf=0.0000f; float DC_Iin_ratio=1.2280f;
|
(4)定义采集函数
measure.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
| #include "measure.h" #include "adc.h" #include "main.h" #include "math.h" #include "arm_math.h"
#define COLS 6 #define ROWS 10 #define SAMPLE_LEN 200
rms_type AC_rms={0, 0, 0, 0, 0, 0}; float AC_sample_mat[6][SAMPLE_LEN]={0};
void calculate_rms(void) { static u32 count=0; u32 temp=count %SAMPLE_LEN; count++; AC_sample_mat[0][temp]= get_dcv_in(); AC_sample_mat[1][temp]= get_dci_in(); AC_sample_mat[2][temp]= get_acv_out(); AC_sample_mat[3][temp]= get_aci_out(); AC_sample_mat[4][temp]= get_acv_in(); AC_sample_mat[5][temp]= get_aci_in(); if(SAMPLE_LEN-1==temp) { count=0; arm_rms_f32(AC_sample_mat[0], SAMPLE_LEN, &AC_rms.VDC_rms); arm_rms_f32(AC_sample_mat[1], SAMPLE_LEN, &AC_rms.IDC_rms); arm_rms_f32(AC_sample_mat[2], SAMPLE_LEN, &AC_rms.Vout_rms); arm_rms_f32(AC_sample_mat[3], SAMPLE_LEN, &AC_rms.Iout_rms); arm_rms_f32(AC_sample_mat[4], SAMPLE_LEN, &AC_rms.Vin_rms); arm_rms_f32(AC_sample_mat[5], SAMPLE_LEN, &AC_rms.Iin_rms); } }
float get_dcv_in(void) { float temp=0; u32 sum=0; int i; for(i=0;i<ROWS;i++) { sum+=adc_result[i*COLS +0]; } temp =(double)sum/ROWS/4095*3.3; return (temp*DC_Vin_ratio); }
float get_dci_in(void) { float temp=0; u32 sum=0; int i; for(i=0;i<ROWS;i++) { sum+=adc_result[i*COLS +1]; } temp =(double)sum/ROWS/4095*3.3; return (temp*DC_Iin_ratio); }
float get_acv_out(void) { float temp=0; u32 sum=0; int i; for(i=0;i<ROWS;i++) { sum+=adc_result[i*COLS +2]; } temp =(double)sum/ROWS/4095*3.3; return (temp-AC_Vout_vref)*AC_Vout_ratio; }
float get_aci_out(void) { float temp=0; u32 sum=0; int i; for(i=0;i<ROWS;i++) { sum+=adc_result[i*COLS +3]; } temp =(double)sum/ROWS/4095*3.3; return (temp-AC_Iout_vref)*AC_Iout_ratio; }
float get_acv_in(void) { float temp=0; u32 sum=0; int i; for(i=0;i<ROWS;i++) { sum+=adc_result[i*COLS +4]; } temp =(double)sum/ROWS/4095*3.3; return (temp-AC_Vin_verf)*AC_Vin_ratio; }
float get_aci_in(void) { float temp=0; u32 sum=0; int i; for(i=0;i<ROWS;i++) { sum+=adc_result[i*COLS +5]; } temp =(double)sum/ROWS/4095*3.3; return (temp-AC_Vin_verf)*AC_Vin_ratio; }
float measure_rms(uint8_t i,uint8_t size) { float sum=0,result; int j;
for(j=0;j<i;j++) { sum+=(float)(AC_sample_mat[size][j]*AC_sample_mat[size][j]); } sum=(double)(sum/i); result=(float)(1.0*sqrt(sum)); return result; }
|
measure.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| #ifndef __MEASURE_H #define __MEASURE_H #include "stm32f4xx.h"
typedef struct _AC_RMS //定义有效值结构体 { float Vin_rms; float Vout_rms; float Iout_rms; float VDC_rms; float IDC_rms; float Iin_rms; }rms_type;
extern rms_type AC_rms; void calculate_rms(void); float get_acv_in(void); float get_dcv_in(void); float get_acv_out(void); float get_dci_in(void); float get_aci_out(void); float get_aci_in(void); float measure_rms(uint8_t i,uint8_t size);
#endif #ifndef __MEASURE_H #define __MEASURE_H #include "stm32f10x.h"
typedef struct _AC_RMS //定义有效值结构体 { float V1_rms; }rms_type;
extern rms_type AC_rms; void calculate_rms(void); u16 get_acv1_in(void); float measure_rms(uint8_t i);
#endif
|
总结
代码资料如下
post9资料合集
链接: https://pan.baidu.com/s/12rAj4YzHQUONdo3RPmqAUA
提取码: c2em –来自百度网盘超级会员v6的分享