51单片机轻松入门—基于STC15W4K系列(C语言版)
李友全 编著 详见:http://www.51hei.com/bbs/dpj-37954-1.html
第16章 频率检测 1 频率检测的用途与频率定义2 频率检测实例1 频率检测的用途与频率定义
0.png (293.61 KB, 下载次数: 136)
下载附件
2016-3-28 22:40 上传
实际工程中有时需要使用单片机检测脉冲信号频率,比如家用恒温型热水器内部 的水流量传感器输出的是12V的矩形脉冲信号,工业运用中的液体流量计输出的 往往也是5~24V的脉冲信号,我们要知道当前液体的瞬时流量就需要测量流量计 输出的脉冲信号频率,然后通过频率换算公式得到当前流量值,脉冲信号可能存 在如下图所示的2种波形,一个波形周期固定不变,另一个波形周期是变动的。
1.png (92.58 KB, 下载次数: 126)
下载附件
2016-3-28 22:40 上传
频率定义:物质在1秒钟内完成周期性变化的次数叫做频率,常用f表示,比如正弦交流电,其频率是50Hz,也就是它在一秒钟内做了50次周期性变化。 假设上图波形总时间为1秒,则上下2个波形频率都是6Hz,对于实际的检测仪表,只要测量出1秒钟内的脉冲个数也就知道频率了,对上面2个波形测量结果 也都会是一致的(6Hz)。2 频率检测实例 例16.1 程序功能:把P3.4 、P3.5在精确1秒钟内输入的脉冲个数值测量出来并 通过串口发送给计算机。 电路如下图所示,由1号单片机输出脉冲信号,2号单片机 P3.4 、P3.5用着频率 检测输入口。
2.png (142.51 KB, 下载次数: 119)
下载附件
2016-3-28 22:40 上传
说明:由于要求同时测量2路脉冲信号频率,使用T0(P3.4)与T1(P3.5)作为外部计数脉冲输入口,T2作串口波特率发生器,1S定时器可以使用T3、 T4,也可使用PCA模块定时,使用频率为22.1184MHz的外部晶振(重点),串口 通信波特率9600,可精确测量外部信号的最高频率的理论值为22.1184MHz/4
= 5.5926 MHz,实验结果:输入6.021MHz时测量结果仍然是精确的,下限测 量到几Hz依然是准确的,只是不能显示小数部分而已。
程序要点分析:
(1)T0与T1是16位计数器,最大计数值为65535,我们需要测量1000000Hz以 上的频率信号,因此需要将计数器扩展为24位,可定义一个unsigned char 变量作为软件计数器, 当16位计数器溢出一次就让软件计数器加1,因此最 大测量范围是65536*255=16711680,即16.7MHz。
(2)PCA定时器定时时间设置为5ms产生一次中断,200次中断即为1秒, 1秒 时间到达时读取计数器T0与T1的值和软件计数器的值。
由于1号单片机的输出信号串联了240Ω电阻,在信号频率很高时接入万用表会对信号波形产生影响,因此需要直接测量1号单片机信号输出引脚相连的测试点, 另外2号单片机晶振一定得选用外部晶振。实测结果如图16-2所示(图中只给一 个输入通道输入了频率信号)。
3.png (295.9 KB, 下载次数: 122)
下载附件
2016-3-28 22:40 上传
1—1号单片机脉冲信号输出程序:
/****************《51单片机轻松入门-基于STC15W4K系列》配套例程 *************
★★★★★★★★★★★★★★★★★★★★★★★★
《51单片机轻松入门-基于STC15W4K系列》 一书已经由北航出版社正式出版发行。
作者亲手创作的与教材配套的51双核实验板(2个MCU)对程序下载、调试、仿真方便,不需要外部
仿真器与编程器,这种设计方式彻底解决了系统中多个最高优先级谁也不能让谁的中断竞争问题。
QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
验证信息:STC15单片机
邮箱:xgliyouquan@126.com
★★★★★★★★★★★★★★★★★★★★★★★★*/
// 晶振频率使用22.1184M
#include "STC15W4K.H"
void CLOCK_Init()
{
//***************** 设置主时钟输出,不分频 *****************
CLK_DIV = 0xc0; // 主时钟输出频率= Fosc /4,R/C时钟频率要求不大于12MHz。
}
void delay2ms(void)
{
unsigned char i,j,k;
for(i=2;i>0;i--) //注意后面没分号
for(j=30;j>0;j--) //注意后面没分号
for(k=180;k>0;k--); //注意后面有分号
}
void main()
{
CLOCK_Init(); // 时钟输出初始化,需要输出高频信号时使用本行代码。
while(1);
// while(1) // 单通道低频输出时使用
// {
// P54=!P54;
// delay2ms();
// }
}
复制代码
1—2号单片机秒计数方式检测频率程序:
/****************《51单片机轻松入门-基于STC15W4K系列》配套例程 *************
★★★★★★★★★★★★★★★★★★★★★★★★
《51单片机轻松入门-基于STC15W4K系列》 一书已经由北航出版社正式出版发行。
作者亲手创作的与教材配套的51双核实验板(2个MCU)对程序下载、调试、仿真方便,不需要外部
仿真器与编程器,这种设计方式彻底解决了系统中多个最高优先级谁也不能让谁的中断竞争问题。
QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
验证信息:STC15单片机
邮箱:xgliyouquan@126.com
★★★★★★★★★★★★★★★★★★★★★★★★*/
// 晶振频率为22.1184MHz外部晶振,串口通信波特率9600
#include "STC15F2K60S2.H"
#include
bit flag; // 需要通过串口向电脑发送数据的标志
sbit LED_1s=P0^0; // 调试指示灯
sbit LED_T0_Over=P0^1; // 调试指示灯
sbit LED_T1_Over=P0^2; // 调试指示灯
unsigned char Read_TH0,Read_TL0; // 读取的定时器T0的高低位计数值
unsigned char Read_TH1,Read_TL1; // 读取的定时器T1的高低位计数值
unsigned char HT0,HT1; // 超过16位的计数值,最大256*65536=16.777 216 MHz
unsigned char Read_HT0,Read_HT1; // 读取的超过16位的计数值,
unsigned char Count=200; // 中断计数变量(1S计时用),200*5mS = 1S
void Uart_Init(void) // 9600bps@22.1184MHz
{
SCON = 0x50; // 8位数据,可变波特率
AUXR |= 0x04; // 定时器2时钟为Fosc,即1T
T2L = 0xC0; // 设定定时初值
T2H = 0xFD; // 设定定时初值
AUXR |= 0x01; // 串口1选择定时器2为波特率发生器
AUXR |= 0x10; // 启动定时器2
TI=1;
}
void JiShuQ_Init() // 计数器初始化,T0和T1共2路计数脉冲输入
{
TMOD=0x55; // 设置T1、T0工作于计数方式,16位计数
HT0=0;TH0=0;TL0=0;HT1=0;TH1=0;TL1=0; // 清空计数器
TR0=1;TR1=1; //开启计数器0 /计数器1
ET0=1;ET1=1; // 开启计数器0与1的中断
}
void DingSQ_Iint_5mS() // PCA定时器初始化为5mS中断
{
CMOD=0x80; // #10000000B 空闲模式下停止PCA计数器工作
// 选择PCA时钟源为fOSC/12,禁止PCA计数器溢出时中断
CCON=0; // 清0 PCA计数器溢出中断请求标志位CF
// CR = 0, 不允许 PCA 计数器计数;清0 PCA 各模块中断请求标志位CCFn
CL=0; // 清0 PCA 计数器
CH=0;
CCAP0L=0; // 给PCA模块0的CCAP0L置初值
CCAP0H=0x24; // 给PCA模块0的CCAP0H 置初值
CCAPM0=0x49; // 设置PCA模块0为16位软件定时器
// ECCF0=1允许PCA模块0中断
// 当[CH,CL]=[CCAP0H,CCAP0L]时,CCF0=1,产生中断请求
EA=1; // 开整个单片机所有中断共享的总中断控制位
CR=1; // 启动PCA计数器(CH,CL)计数
}
void PCA(void) interrupt 7 // PCA中断服务程序,每5ms中断一次
{
union
{ // 定义一个联合,以进行16位加法
unsigned int num;
struct
{ // 在联合中定义一个结构
unsigned char Hi,Lo;
}Result;
}temp;
temp.num=(unsigned int)(CCAP0H<<8)+CCAP0L+0x2400; //0X1200=0.500112S, 0X11FF=0.500003S,
CCAP0L=temp.Result.Lo; // 取计算结果的低8位
CCAP0H=temp.Result.Hi; // 取计算结果的高8位
CCF0=0; // 清 PCA 模块0 中断标志
Count--; // 修改中断计数
if(Count==0)
{
Count=200; // 恢复中断计数初值 200*5mS = 1S
LED_1s =!LED_1s; // 在P0.0输出脉冲宽度为1秒钟的方波(周期2S)
TR0=0;TR1=0; // 关闭计数器0与1 ,防止读数错误
CR=0; // 关闭16位PCA计数器(CH,CL)
Read_HT0=HT0;Read_TH0=TH0;Read_TL0=TL0; // 读取计数值
Read_HT1=HT1;Read_TH1=TH1;Read_TL1=TL1; // 读取计数值
HT0=0;TH0=0;TL0=0; // 清空计数器
HT1=0;TH1=0;TL1=0;
TR0=1;TR1=1; // 开启计数器0与1 ,防止读数错误
CR=1; // 开启16位PCA计数器(CH,CL)
flag=1; // 需要主程序处理数据
}
}
void Timer0(void) interrupt 1 // 定时器T0 中断函数
{
HT0++; // 超过16位计数值变量一次变量加1
LED_T0_Over=!LED_T0_Over;
}
void Timer1(void) interrupt 3 // 定时器T1 中断函数
{
HT1++; // 超过16位计数值变量一次变量加1
LED_T1_Over=!LED_T1_Over;
}
void SendBuf()
{
unsigned long tmp;
tmp= Read_HT0*65536+Read_TH0*256+Read_TL0;
printf("F1: %ldHz ",tmp);
tmp= Read_HT1*65536+Read_TH1*256+Read_TL1;
printf("F2: %ldHz\n",tmp);
}
void main()
{
Uart_Init(); // 串口初始化
JiShuQ_Init(); // 计数器初始化
DingSQ_Iint_5mS(); // PCA定时器5mS初始化
while(1)
{
if (flag==1) // 需要通过串口向电脑发送数据的标志
{
SendBuf();
flag=0;
}
}
}
复制代码