接上一篇博客:
https://blog.csdn.net/Jinyindao243052/article/details/107821839
这是另外一种思路:
有两种测频模式,一个高频模式,一个低频模式
T0和T1都是计时器
单片机中断方案代码
#include <reg51.h>
#include <absacc.h>
#include <ctype.h>
sbit KEY2 = P2^0; //按键1 high mode
sbit KEY3 = P2^1; //按键2 low mode
sbit KEY4 = P2^2; //按键3 切换档位
sbit LED0=P0^0;
sbit LED1=P0^1;
sbit LED2=P0^2;
unsigned char flag;//阀门开否
unsigned char mode;//模式 :0低频 1:高频
unsigned char DispBuf[8];
unsigned char s[8];
unsigned char d;//档位
unsigned int t;//阀门长度/毫秒
unsigned long count;
unsigned long f;
unsigned long j;//循环变量
unsigned int wait;
unsigned int a=0;
//直接引用模块
void delay_l(unsigned int t){ //一个小改编,low mode使用的延时函数
do
{
TH0 = 0xFF;
TL0 = 0x69;
TR0 = 1;
while ( !TF0 );
TR0 = 0;
TF0 = 0;
} while ( --t != 0 );
}
void delay(unsigned int t){ //high mode使用的延时函数
do
{
TH0 = 0xFA;
TL0 = 0x24;
TR0 = 1;
while ( !TF0 );
TR0 = 0;
TF0 = 0;
} while ( --t != 0 );
}
unsigned char KeyScan(){ //按键检测
unsigned char k = '\0';
if ( KEY2 == 0 ) k = 'h';
if ( KEY3 == 0 ) k = 'l';
if ( KEY4 == 0 ) k = 'd';//切换阀门长度
return k;
}
void DispClear(){ //清空缓存
unsigned char i;
for ( i=0; i<8; i++ )
{
DispBuf[i] = 0x00;
}
}
void DispInit(){
DispClear();
EA = 0;
TMOD &= 0x0F;
TMOD |= 0x10;
TH1 = 0xFC;
TL1 = 0x66;
TR1 = 1;
ET1 = 1;
EA = 1;//EA=1 是打开总中断
}
void SysInit(){
TMOD &= 0xF0;
TMOD |= 0x01; //设置定时器T0为16位定时器
DispInit(); //数码管扫描显示初始化
IT0 = 1;//如果IT0设置为0,则外部中断0引脚被拉至低电平即可引发外部中断
}
void T1INTSVC() interrupt 3 //定时器1,定时器中断,负责扫描数码管
{
code unsigned char com[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
static unsigned char n = 0;
TR1 = 0;
TH1 = 0xFC;
TL1 = 0x66;
TR1 = 1;
XBYTE[0x7800] = 0xFF;
XBYTE[0x7801] = ~DispBuf[n];
XBYTE[0x7800] = ~com[n];
n++;
n &= 0x07;
}
//自己实现的实现函数
unsigned long HighMod(unsigned int t)//阀门长度t=100或1000,测频率法
{
count=0;
EX0=1;//EX0是外部中断0的使能控制位,如果EX0设置为0,则外部中断0失效
delay(t);
EX0=0;
return count;
}
unsigned long LowMod()//低频模式下测量脉冲宽度,测周期法
{
unsigned long wait = 0;
unsigned long th0 = 0;
unsigned long tl0 = 0;
unsigned long avg=0;
unsigned char i;
for(i=0;i<20;i++)//采用测周法
{count = 1;
EX0 = 1;
flag=0;
while(!flag){
delay_l(1);
wait++;
if(wait>=1000000) break;//等待了1000000下,待测脉冲没有跳动一下,退出不再等
}
while(flag){delay_l(1);count++;};//上升沿到来,flag置为1,开始计算脉冲宽度,下一个上升沿到来,flag再次为0,停止计时,时长储存在flag中
avg+=count;
EX0 = 0;
}
avg/=20;//20次测得的脉冲宽度求均值,作为实际脉冲宽度
return avg;
}
void time0() interrupt 0 T0,外部中断
{
if (mode==0)//低频模式
{
flag=1-flag;
}
if (mode==1)//高频模式
{
count=count+1;
a=a+1;
}
}
unsigned long freq_h(unsigned long count)//高频模式下计算频率值f
{
unsigned long temp=count;
if(t==100)//t是阀门长度
{
f=10*temp;
}
if(t==1000)
{
f=temp;
}
return f;
}
unsigned long freq_l(unsigned long count)//低频模式下计算频率值f
{
unsigned int temp=0;
temp=count;
f =(int)(100000/temp);
return f;
}
void display (unsigned long f)//刷新 DispBuf
{
code unsigned char Tab[] ={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //0-9的码字
unsigned char i;
for ( i=0; i<8; i++ ){
unsigned long int c;
c = f%10;
f = (f-c)/10;
DispBuf[i] = Tab[c];//DisBuf低位对应数值低位
}
if (mode==0)
{DispBuf[1] |= 0x80;}
}
void main()
{
unsigned char key = 'h'; //按键检测返值
mode=1;
t=1000;
SysInit();
display(0);
for(;;)
{
while(1)
{
delay(50);
key=KeyScan();
if (key!='\0')//如果有键按下,退出循环
{
break;
}
}
if (key=='h')
{
LED0=0;
LED1=1;
mode=1;
count=HighMod(t);
f=freq_h(count);
display(f);
}
if (key=='l')
{
LED0=1;
LED1=0;
mode=0;
count=LowMod();
f=freq_l(count);
display(f);
}
if (key=='d')
{
LED2=~LED2;//LED2翻转
if(t==100)
{t=1000;LED2=0;}//切换到1000阀门,LED2关闭
else
{t=100;LED2=1;}
LED0=0;//
LED1=1;
ET1=0;//停止刷新数码管,更新频率
mode=1;
count=HighMod(t);
f=freq_h(count);
display(f);
ET1=1;//更新完数码管,继续刷新频率
}
while(1)
{
delay(5);
key=KeyScan();
if(key=='\0')
{break;}
}
EA=1;
ET1=1;
TR1=1;
}
}
参考:
https://www.cnblogs.com/alantechnique/p/5453647.html
https://zhidao.baidu.com/question/1241874441618237339.html