一、硬件连接
1、电压信号处理电路仿真
图1.1.1
-----------------------------------------------------------
2、单片机连接
主控MCU:STM32F103ZET6,LM293输出连接在PB0上检测电压信号的频率,如图1.1.1与图1.2.1所示。
图1.2.1
图1.2.2
如图1.2.2所示,注意其中的TIM3_CH2N是PWM捕获比较输出,TIM3_CH3才是输入捕获。
图1.2.3
-----------------------------------------------------------------------------------------------------------------
二、程序部分
这里通过STM32输入捕获或FFT转换两种方式实现频率的测量,在实际工程中都已实现。STM32输入捕获信号幅度小于2V时,单片机检测不到跳变沿,需硬件对信号适当处理(如图1.1.1)。PB0/ADC8也可用ADC读信号电压值,ADC值为0时进行记录,再次为0就相当于经过了半个周期。计算两次ADC为0的时间差,就可以计算出信号的频率,这种方法不会受限于信号幅度的限制。
--------------------------------
1、通过STM32输入捕获
下面的程序采集PB0口(图1.2.1)的电压信号,因频率较低,且要求继电器出口时间小于35mS,采用测周法计算频率。给出主要部分定时器配置与定时器中断程序。因上升沿示波器测试并不陡峭(图1.1.1仿真图也可看出),故取一周波两次下降沿。
注意后期的处理程序必须捕获到两个下降沿的前提下,才能作相应的处理,采集程序未完成,处理会出错。
图2.1.1
1)定时器配置
void adc_TIM_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定时器
GPIO_InitTypeDef GPIO_InitStructure; //端口
TIM_ICInitTypeDef TIM_ICInitStructure; //输入捕获
//初始化GPIO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入模式
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_0);
//使能时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //TIM3
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
//初始化TIM3定时
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 17; //1MHz计数脉冲 1uS
TIM_TimeBaseStructure.TIM_Period = 65535;
TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
//初始化TIM3 Channel3输入捕获IC(Input Capture)
TIM_ICInitStructure.TIM_Channel=TIM_Channel_3;
TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Falling; //下降沿捕获
TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI; //管脚与寄存器一一对应
TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1; //有下降沿就捕获,不分频
TIM_ICInitStructure.TIM_ICFilter=0x00; //不打开输入捕获滤波器
TIM_ICInit(TIM3,&TIM_ICInitStructure);
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时中断
TIM_ITConfig(TIM3,TIM_IT_CC3,ENABLE); //允许CC3捕获中断
TIM_Cmd(TIM3,ENABLE);
…………
}
--------------------------------
2)定时溢出和输入捕获中断处理
void TIM3_IRQHandler(void) //TIM3
{
static u8 CapStatus=0; //捕获状态,CapStatus=0未捕获到第1个下降沿,CapStatus=1捕获到第1个下降沿
static u8 TIM3_CH3_Capture=0; //总的计数次数
u32 FrequencyTemp=0;
if(TIM_GetITStatus(TIM3,TIM_IT_Update)) //TIM3定时溢出更新中断
{
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位
if(CapStatus)
TIM3_CH3_Capture++;
}
if(TIM_GetITStatus(TIM3,TIM_IT_CC3)) //RB0输入捕获中断
{
TIM_ClearITPendingBit(TIM3,TIM_IT_CC3); //清除中断标志位
if(!CapStatus)
{
CapStatus=1;
TIM_SetCounter(TIM3,0); //计数器清零
}
else if(CapStatus) //已经捕获到第1个下降沿
{
CapStatus=0;
FrequencyTemp=TIM_GetCapture3(TIM3)+TIM3_CH3_Capture*65536; //计算两个下降沿总计数
TIM3_CH3_Capture=0; //溢出次数清零
TIM_SetCounter(TIM3,0); //计数器清零
FrequencyValue=400000000/FrequencyTemp; //计算频率,比如5000,单位0.01Hz
}
}
}
图2.1.2
图2.1.3
-----------------------------------------------------------
2、通过FFT实现
下面是采集PC1口(图1.2.1)的小通道电流信号,计算频率,其固件具ST官方DSP库实现FFT,测试固件移步:FFT(具ST官方DSP库实现)。
--------------------------------
1)用STM32F103自带的12位ADC进行数据采集,定时器触发ADC采集,DMA搬运,定时器时间自行设置,采样频率已知。此部分相关内容移步:AD转换汇总(STM32、取平均、过采样)。
--------------------------------
2)通过FFT可以准确测量电压值、电流值、有功功率、无功功率、频率、谐波分量(比如显示2~32次谐波)、相角(电压与电流夹角)。互感器二次值精确到小数点后2位无压力,电流范围大,硬件增加大小通道、程序分别采集即可;涌流二次谐波含量最多,故可实现二次谐波制动,相关介绍移步:电力-涌流抑制与谐波。
图2.2.1
-----------------------------------------------------------
3、屏显驱动介绍
移步:12864液晶显示原理(C程序)。
-----------------------------------------------------------------------------------------------------------------
附录1:测频法计算频率
网上找的资料,不保证正确性,没有实际测试过,仅供参考。
通过在一定时间内检测跳边沿的个数可计算出频率 频率=上升沿或下降沿个数/统计时间。
-----------------------------------------------------------
方法1:利用外部中断统计跳边沿个数,配置一个定时器每隔一定时间对频率进行计算。部分代码如下。
void exti_init() //外部中断初始化函数
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource2);//选择GPIO引脚用作外部中段线路
//此处一定要记住给端口管脚加上中断外部线路
EXTI_InitStructure.EXTI_Line=EXTI_Line2;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling; //下降沿进中断
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //打开EXTI2的全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //设置优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStructure);
}
外部中断中断函数
void EXTI2_IRQHandler()
{
if(EXTI_GetITStatus(EXTI_Line2)==SET)
{
EXTI_ClearITPendingBit(EXTI_Line0);//清中断
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2)==Bit_RESET) //确定沿
{
cnt++;
}
}
}
定时器中断函数
void TIM3_IRQHandler()
{
frequent=cnt; //定时器设置时间为1s时
cnt=0; //清零计数cnt
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清标志位
}
-----------------------------------------------------------
方法2:采用定时器外部计数的方法,另外一个定时器负责每隔一段时间计算频率,部分代码如下。
void time_init()
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM2_TimeBaseInitStructure;
TIM_TimeBaseInitTypeDef TIM3_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);//清除TIM2中断标志位
TIM2_TimeBaseInitStructure.TIM_Period = 0xFFFF;//设置自动重装载值
TIM2_TimeBaseInitStructure.TIM_Prescaler = 0;//设置分频
TIM2_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM2_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInit(TIM2,&TIM2_TimeBaseInitStructure);
TIM_ETRClockMode1Config(TIM2, TIM_ExtTRGPSC_OFF,TIM_ExtTRGPolarity_NonInverted, 0x00); //设置为采用外部时钟计数,可设定滤波参数消除信号干扰
TIM_Cmd(TIM2,ENABLE);
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
TIM3_TimeBaseInitStructure.TIM_Period = 999;
TIM3_TimeBaseInitStructure.TIM_Prescaler = 3599;
TIM3_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM3_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3,&TIM3_TimeBaseInitStructure);
TIM_Cmd(TIM3,ENABLE);
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE );
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
定时器中断函数
void TIM3_IRQHandler()
{
static u8 i;
static u32 frequent_sum;
TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清中断
if(i<19)
{
cnt += TIM_GetCounter(TIM2); //,获取计数器的值,累加减少误差
TIM_SetCounter(TIM2,0); //计数器清零
i++;
}
else
{
cnt += TIM_GetCounter(TIM2);
TIM_SetCounter(TIM2,0);
cnt += cnt*0.000025; //根据实际情况修改系数线性补偿
frequent = cnt;
i = 0;
cnt = 0;
}
}
-----------------------------------------------------------------------------------------------------------------
上一篇:STM32单片机-资料查找
下一篇:STM32单片机-PWM波形输出
推荐阅读最新更新时间:2024-11-17 01:08
推荐帖子
- zigbee修改发射功率的问题
- 现在想做一个发射终端间隔自动修改发射功率的问题,请大家来出出点子zigbee修改发射功率的问题这个意思不是太明白啊,是要低功耗,还是就是要降低发送功率,让接受不到。低功耗专门有LPMx的设置实现,而RSSI主要和距离有关系,反应的是接受强度。主动降低发射功率应该是有一个寄存器写入就可以实现的,但是没有试过,不大熟悉。cc2530的芯片,在协议栈中写好程序,启动之后然后程序自动从最低功耗开始,到最高功耗,时间间隔2s 请问这个修改要在哪里进行修改编写现在我用的是Ember357芯
- lygqichunyang RF/无线
- 简单实用的调频话筒制作
- 下面的就是调频无线话筒的电路图,电路非常简洁,没有多余的器件。高频三极管V1和电容C3、C5、C6组成一个电容三点式的振荡器,对于初学者我们暂时不要去琢磨电容三点式的具体工作原理,我们只要知道这种电路结构就是一个高频振荡器就可以。三极管集电极的负载C4、L组成一个谐振器,谐振频率就是调频话筒的发射频率,根据图中元件的参数发射频率可以在88~108MHZ之间,正好覆盖调频收音机的接收频率,通过调整L的数值(拉伸或者压缩线圈L)可以方便地改变发射频率,避开调频电台。发射信号通过C4耦合到天线上再发
- maker 单片机
- 关于进程中止的问题,求教!
- 一般对于应用程序的中止上,大家一般用的方法都是Findwindow,terminateProcessing.除了这个方法,还有别的方法吗?不用这个,用什么方法能阻止应用程序的启动?关于进程中止的问题,求教!
- chenmaoxiong 嵌入式系统
- ISE14.7编译时不能Map了是怎么回事?
- 用例程也不能改变这样的情况,可能是360或者什么软件把里面的文件给破坏了,但不知道具体什么原因,具体怎么去解决,希望知道朋友能帮忙解决一下,谢谢!ISE14.7编译时不能Map了是怎么回事?报的什么错啊?会不会是引脚约束的文件没有?会不会是引脚约束的文件没有?不懂帮顶cat3902982发表于2015-9-2215:58报的什么错啊? 他没有报错误,就是编译的时候到这步就停止了。。elvike发表于2015-9-2218:00会不会是引脚
- besideyou FPGA/CPLD
- TI DSP .CMD 文件的编写
- CMD它是用来分配rom和ram空间用的,告诉链接程序怎样计算地址和分配空间……TIDSP.CMD文件的编写CMD它是用来分配rom和ram空间用的,告诉链接程序怎样计算地址和分配空间.所以不同的芯片就有不同大小的rom和ram.放用户程序的地方也不尽相同.所以要根据你的芯片进行修改.分两部分.MEMORY和SECTIONS.MEMORY{PAGE0..........PAGE1.........}SECTIONS{SECTIONS{.vector
- DSP16 DSP 与 ARM 处理器
- 新手关于消影的问题
- 我是新手,正在学习51单片机,也正在做实验。关于消影还是不怎么理解。我用定时器中断做了个0至59秒的计时器,但是影子相对明显,我将硬件情况及程序附上,请各位指点。怎样才能较好地控制消影呢?还有最好能说明白消影的原理,看得比较多,但是还是没有透彻的理解。1、硬件情况:STC89C52,P0口接三极管控制共阳数码管;2、程序如下:#includereg52.h#defineucharunsignedchar#defineuintunsignedintuintnum1,n
- zanexue 单片机
设计资源 培训 开发板 精华推荐
- TAR5S37 点稳压器(低压差稳压器)的典型应用
- 3、用于视频/成像的5V模拟放大
- LT8609AIMSE 5V、2MHz 降压型稳压器的典型应用电路
- 【智能车】遥控小车+1066538A
- ADP7157CP-04-EVALZ,用于评估 ADP7157 1.2 A 超低噪声、可调输出、RF 线性稳压器的评估板
- 使用 ams AG 的 AS1312-BTDT-33 的参考设计
- ADR360A 2.048 Vout 低功耗、低噪声电压基准的典型应用,具有灌/拉能力
- 具有 2.5V LDO 输出的 LTC3633AIFE-1 3.3V/1.8V 降压稳压器的典型应用电路
- usb表接口转换小板(pd usb3.0)
- NCP705 500 mA、超低静态电流、IQ 13 A、超低噪声、可调电压版本的 LDO 稳压器的典型应用
- 非常见问题解答第223期:如何在没有软启动方程的情况下测量和确定软启动时序?
- 兆易创新GD25/55全系列车规级SPI NOR Flash荣获ISO 26262 ASIL D功能安全认证证书
- 新型IsoVu™ 隔离电流探头:为电流测量带来全新维度
- 英飞凌推出简化电机控制开发的ModusToolbox™电机套件
- 意法半导体IO-Link执行器电路板为工业监控和设备厂商带来一站式参考设计
- Melexis采用无磁芯技术缩小电流感测装置尺寸
- 千丘智能侍淳博:用数字疗法,点亮“孤独症”儿童的光
- 数药智能冯尚:ADHD数字疗法正为儿童“多动症”提供更有效便捷服务
- Vicor高性能电源模块助力低空航空电子设备和 EVTOL的发展
- 创实技术electronica 2024首秀:加速国内分销商海外拓展之路