急!单片机频率计c语言程序,3位8段数码管显示,显示范围从0.01~9.99,数据每0.5s~1s更新
常用51单片机频率计有两种方法,一种方法,定时计脉冲个数,如定时100ms,计数器计值是55,则频率为55×10=550hz,另外一种方法,计单个脉冲的周期,可用外部中断,也可不用外部中断,下降沿到来时开定时器,上升沿或另外一个下降沿到来时关闭定时器,读出定时器的值,若脉冲宽度太宽,定时器可能会溢出, 也可以让定时器中断,定时器计时加上中断溢出次数的时间,就是总时间=周期,显然你用的是第二种方法
程序基本没问题,但你的显示程序应该是包括while(1) {while(pulse==0);.....}
这个大偱环内的,不要另起一个偱环,还是真正的死偱环,跳不出来,结果是复位一次,只能测量一次
这种方法测低频比较准,但也有一个缺点,测低频时,更新很慢,测1HZ脉冲,必须要2秒,1S测量计时,另外几ms处理并显示,剩下的近1S空等
测0.5HZ脉冲,理论上要4秒,所以要求0.5-1S更新一次和测量的频率下限是矛盾的
既然用了中断TF1会自动清0,TF1=0是多余的
还有,你若是液晶屏显示还可以,数码管测低频还存在着刷新问题,长时间的等待,数码管会只亮一个,如果把数码管刷新程序放在等待空闲内的话,测高频时会错过脉冲上升和下降沿,测低频也会,只不过几率小些,所以用数码管的话,也只能用静态显示
或者间断显示也可以,即将显示子程序偱环50-100次(持续1.5-3s),然后再次测量,把while(1) {ledxianshi();}死偱环改成FOR偱环
也可以用第一种方法测,若测试低频的话,就要把定时时间设得很长,测0.1HZ信号,你不定时大于10s,测出来就是0
51单片机用定时器计数器测量频率
定时器1对外部脉冲计数时TMOD高4位设置应该是5
因此TMOD=0x51;
以下我的频率计程序:
#include reg52.h//因没用到STC12C5410专有特殊功能寄存器,此处用52或51的头文件均可
#define unit unsigned int
#define uchar unsigned char
//定义以I/O口的功能
sbit beiguang=P3^2;//液晶屏背光
sbit rs=P1^3;//液晶屏写选择,0命令 1数据
sbit rw=P1^4;//液晶屏读写选择
sbit lcden=P1^5;//液晶屏使能
sbit fm=P1^7;//蜂鸣器
#define db P2 //定义P2为数据输出口,写数据时用db代替P2,增加液晶屏程序的通用性
//更改硬件接线时,只更改此处,而不必去更改液晶屏读写子程序
uchar aa,bb,cc;//变量声明
unit dd,ee;
void Delay1ms(unsigned int i) //1ms延时程序
{
unsigned int j;
for(;i0;i–)
{
for(j=0;j125;j++)
{;}
}
}
void init()//初始化设置
{
TMOD=0x15;//定时器0作为计数器,定时器1作为定时器用
TH0=0;//计数器清0
TL0=0;
EA=1;//开总中断
ET1=1;//允许定时器1中断
TH1=0x4c;
TL1=0x5c;
TR0=1;//启动计数器
TR1=1;//启动定时器
aa=0;
}
void write_com(uchar com)//向液晶屏写命令
{
db=com;
rs=0;
rw = 0;
lcden=0;
Delay1ms(10*12);
lcden=1;
Delay1ms(10*12);
lcden=0;
}
void write_date(uchar date)//向液晶屏写数据
{
db=date;
rs=1;
rw = 0;
lcden=0;
Delay1ms(10*12);
lcden=1;
Delay1ms(10*12);
lcden=0;
}
void init2()//液晶屏初始化
{
beiguang=0;
rw=0;
write_com(0x38);
Delay1ms(10*12);
write_com(0x0f);
Delay1ms(10*12);
write_com(0x06);
Delay1ms(10*12);
write_com(0x01);
Delay1ms(10*12);
}
void display4(unsigned int number) //单行多位显示程序
{
uchar A1,A2,A3,A4,A5;
init2();//液晶屏初始化
A1=number/10000%10;//分离出万,千,百,十,个,对于int型数据,最大不超过65535
A2=number/1000%10;
A3=number/100%10;
A4=number/10%10;
A5=number%10;
write_com(0x80);//第1个数据的位置设定,第1行第1列
Delay1ms(10);
write_date(0x30+A1);//写数据
Delay1ms(10);
write_date(0x30+A2);
Delay1ms(10);
write_date(0x30+A3);
Delay1ms(10);
write_date(0x30+A4);
Delay1ms(10);
write_date(0x30+A5);
Delay1ms(10);
write_com(0x87);//第6个数据’H’的位置,中间空85和86 二格
write_date(‘H’);
Delay1ms(10);
write_date(‘z’);
Delay1ms(10);
}
void main()//主程序很简单
{
init();//初始化
while(1)//循环程序
{
dd=bb*256+cc;//0.5S的计数值
ee=2*dd;//换算为1秒钟的计数值
if(aa==1)
{
if(TH012)//预判断,50ms内TH012,1s内计数值将超过可计数的最大值65535
fm=0;//报警
}
display4(ee);//显示
fm=1;//报警停止
}
}
void timer1()interrupt 3//注意:定时器1的中断序号为3
{
aa++;
TH1=0x4c;//11.0592Mhz
TL1=0x5c;
if(aa==10)//中断10次,共0.5S
{
TR0=0;//暂停计数
aa=0;
bb=TH0;//读出计数器数据
cc=TL0;
TL0=0;//计数器清0
TH0=0;
TR0=1;//重新启动
}
}
51单片机的数字频率计
该系统由定时器0中断子函数、定时器1中断子函数、延时子函数、按键消抖子函数、闸门控制子函数、主函数和数据定义这几部分组成。
闸门时间由定时器1控制,初始为2s,可以通过按键加减,范围为2s到7秒。闸门时间就是采样时间,闸门时间越长,测量精度越准确。
由P3.4输入信号,低电平有效,触发T0外部中断。当T0触发中断的时候执行的程序。这里只进行了一个操作,t0++。所以,t0的值表示触发了几次中断,也就表示接受到的脉冲几次从0到65536。所以会有t0*65536。 另外,由于计时的机制是THO++、TL0++,所以,THOTL0就表示当前的计数值。THOTLO- 初值就可以确定没有触发中断定时多少。TH0*256==TH0*2^8,实质就是左移8位,就是拼接TH0跟TL0的处理。
所以频率的核心算法为
daimao=(t0*65536+TH0*256+TL0)/n
程序框图

总源程序
#include “reg52.h”
#define uchar unsigned char
typedef unsigned int uint;
sbit w1=P2^0;
sbit w2=P2^1;
sbit w3=P2^2;
sbit w4=P2^3;
sbit w5=P2^4;
sbit w6=P2^5;
sbit jia=P1^6;
sbit jian=P1^7;
sbit s=P3^7;//启动
bit flag;//标签
uchar s1,s2,s3,s4,s5,s6, shu=1;//控制数组取值
uchar t0,t1,t2,a;
unsigned long m=5,n;//m为闸门时间
int y;
unsigned long daimao;//频率
unsigned char code table1[]={0xc0,0xf9,0xa4,0xb0, //闸门时间数组0-f
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
0xc6,0xa1,0x86,0x8e};
unsigned char code table2[]={0xc0,0xf9,0xa4,0xb0, //频率数组0-f
0x99,0x92,0x82,0xf8,
0x80,0x90,0x88,0x83,
帮忙用C语言写一段51单片机的程序,晶振12M。
#include reg52.h
/*
本程序功能,输出方波,频率1-25ms
单片机@12MHz /12T
*/
sbit Pulse=P1^1; //—方波
sbit Add=P3^2; //—频率加
sbit Dec=P3^3; //—频率减
sbit Start = P1^3; //—开关键
sbit Display_Ten_Bit = P2^0;
sbit Display_Bit_Bit = P2^1;
code unsigned char TH0_Reload[21] = {
0x00,0x0B,0x0B,0x26,0x0B,0x3C,0x5D,
0x74,0x0B,0x26,0x3C,0x4E,0x5D,0x69,
0x74,0x7D,0x85,0x8D,0x93,0x99,0x9E
};
code unsigned char TL0_Reload[21] = {
0x00,0xDC,0xDC,0xFC,0xDC,0xB0,0x3D,
0x7D,0xDC,0xFC,0xB0,0x71,0x3D,0xC2,
0x7E,0xCB,0xEE,0x1C,0x7E,0x34,0x58
};
code unsigned char Pre_Freq[21] = {255,8,4,3,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1};
#define TH1_RELOAD 0xF4//—定时器1初始值,定时3ms
#define TL1_RELOAD 0x48//—定时器1初始值,定时3ms
data unsigned char Freq = 20; //—频率值
data unsigned char Fre_Cnt = 0; //—计数值
bit Display_Bits = 0;
//—-共阳数码管———————————————————————–
code unsigned char Seg_Table[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
//—-用于按键去抖动的延时——————-
void Key_Delay(void)
{
unsigned short i = 60000;
while(i++);
}
void main()
{
//—-定时器1,定时3ms,用于动态显示———–
TH1 = TH1_RELOAD;
TL1 = TL1_RELOAD;
//—-用于输出脉冲波——–
TH0 = TH0_Reload[0];
TL0 = TL0_Reload[0];
//—-两定时器都工作于方式1,且都开中断——–
TMOD = 0x11;
ET0 = 1;
ET1 = 1;
EA = 1;
//—-开启定时器1,即显示———————-
TR1 = 1;
while(1)
{
if(Add == 0) //—如果”频率+”键 按下
{
Key_Delay(); //—按键去抖
if(Add == 0)
{
if(Freq20) Freq++; //—-如果频率值小于20,则加1
while(Add == 0); //—等待按键送开
}
}
if(Dec == 0) //—如果”频率-“键 按下
{
Key_Delay();
if(Dec == 0)
{
if(Freq1) Freq–; //—-如果频率值大于1,则减1
while(Dec == 0); //—等待按键送开
}
}
if(Start == 0)//—如果”启动/暂停”键 按下
{
Key_Delay(); //—按键去抖
if(Start == 0)TR0 = 1; //—启动定时器0,输出方波
}
else
{
TR0 = 0; //—关闭定时器0,暂停输出
}
}
}
void ISR_Timer0_Pulse () interrupt 1
{
//—-定时器0重载———————————–
TH0 = TH0_Reload[Freq];
TL0 = TL0_Reload[Freq];
//—-计数值自加————————————
Fre_Cnt++;
//—-如果计数值不小于频率值,翻转一次—————
if(Fre_Cnt = Pre_Freq[Freq])
{
Pulse = ~Pulse;
Fre_Cnt = 0; //—清零计数值——————–
}
}
void ISR_Timer0_Display() interrupt 3
{
//—-定时器1重载———————————–
TH1 = TH1_RELOAD;
TL1 = TL1_RELOAD;
//—-决定显示十位还是个位————————–
Display_Bits = ~Display_Bits;
//—-数码管驱动————————————
if(Display_Bits) //—-显示十位
{
Display_Bit_Bit = 1; //—关闭个位的位选
P0 = Seg_Table[Freq/10]; //—送十位的段码
Display_Ten_Bit = 0; //—打开十位位选
}
else //—-显示个位
{
Display_Ten_Bit = 1; //—关闭十位的位选
P0 = Seg_Table[Freq%10]; //—送个位的段码
Display_Bit_Bit = 0; //—打开个位的位选
}
}
有不明白的欢迎追问