按键控制数码管0-99显示,十位不跳,用定时器T0中断

本文介绍如何利用51单片机通过按键控制数码管显示0-99,并采用定时器T0溢出中断的方式解决数码管十位闪烁问题。文中提供详细代码实现及说明。

如果直接在主函数中写按键控制数码管0-99显示,不管怎么延时数码管十位上的数都会闪,原因就是单片机的机器周器太快,人的按键速度是ms级的,所以等你人操作完了,单片机早就执行了不知道多少遍。

解决方法就是用中断,这里采用定时器T0溢出中断,工作方式1, 2ms中断显示一次,这样的话既不影响按键操作,又不影响显示,一举两得。


以下程序是适用于德飞莱51单片机开发板


#include <reg52.h>


#define uint unsigned int
#define uchar unsigned char
#define DataPort P0 


sbit Seg_Latch = P2^2;    //段锁存
sbit Bit_Latch = P2^3;    //位锁存


sbit key_up = P1^0;      //数字增加按键
sbit key_down = P1^1;    //数字减少按键


uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; //数码管显示0-9


uchar code tab[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};    //数码管位选


uchar temp[2];   //存放num十位和个位


void Display(unsigned char FirstBit,unsigned char Num);  //显示函数


void delay(uchar t)  //延时
{
while(--t);
}


void DelayMs(uchar z) //ms级延时
{
while(z--)
{
delay(245);
delay(245);
}
}


void Time0_init()    //定时器T0溢出中断初始化
{
TMOD |= 0x01;      //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
EA = 1;
ET0 = 1;
TR0 = 1;
}


char num = 0;         //0-99数字
uchar key_num = 0;    //按键计数


void main()
{
Time0_init();     //T0中断初始化
key_up = 1;       //使用前先拉高
key_down = 1;
while(1)
{
if(!key_up)
{
DelayMs(10);
if(!key_up)
{
while(!key_up)
{
key_num++;
DelayMs(10);    //10x100 = 1s 按了1s
if(key_num == 100)
{
key_num = 0;    //清零
while(!key_up)
{
if(num < 99)
{
num++;
}
temp[0] = table[num / 10];//及时赋值
temp[1] = table[num % 10];
DelayMs(50);   //数字跳动快慢
}
}
}
key_num = 0;   //防止累加造成错误识别
if(num < 99)
{
num++;
}
}
}

if(!key_down)    //减操作
{
DelayMs(10);
if(!key_down)
{
while(!key_down)
{
key_num++;
DelayMs(10);
if(key_num == 100)
{
key_num = 0;
while(!key_down)
{
if(num > 0)
{
num--;
}
temp[0] = table[num / 10];
temp[1] = table[num % 10];
DelayMs(50);
}
}
}
key_num = 0;
if(num > 0 )
{
num--;
}
}
}
temp[0] = table[num / 10];   //用完赋值
temp[1] = table[num % 10];
}
}


void Display(unsigned char FirstBit,unsigned char Num)    //显示
{
  static unsigned char i = 0;  //静态局部变量,用完后不释放
   DataPort  = 0;   
   Seg_Latch = 1;     
   Seg_Latch = 0;


   DataPort = tab[i+FirstBit]; 
   Bit_Latch=1;     
   Bit_Latch=0;


   DataPort = temp[i]; 
   Seg_Latch=1;     
   Seg_Latch=0;

i++;
if(i == Num)
{
i = 0;
}
}


void Time0_isr() interrupt 1
{
TH0 = (65536 - 2000) / 256;   //取高八位 2ms
TL0 = (65536 - 2000) % 256;   //取低八位
Display(0,2);
}
这是一个基于单片机STC89C52RC而编写的程序而实现的心率仪的项目 我将给你一段代码 但完整 你需要帮我实现以下功能 可以实现自动测心率 即把手指放到传感器上时 按键也可自动测心率 时间在30s内完成 以下是代码: //-----------------------------------------------------------------------------// //---------------心率仪C51程序框架---by tjx------------------------------------// //---------------------2022.12-------------------------------------------------// //------------------crystal=6MHz-----------------------------------------------// //-----------------------------------------------------------------------------// //-----------------------------------------------------------------------------// //包含头文件、定义各个接口-----------------------------------------------------// //-----------------------------------------------------------------------------// #include <AT89X52.H> #define uint unsigned int //定义一下方便编程 #define uchar unsigned char //定义一下方便编程 #define keystart P1_0 //定义心率测量启动按键输入口------按输入为1电平,按下输入为0电平 #define ledtest P3_4 //定义测量指示灯控制------------输出1电平灯亮,输出0电平灯亮 #define signal P2_0 //定义心信号输入口--------------根据心信号电平高低变化 #define keymodel P1_3 //定义测量模式设置按键输入口------按下输入0电平,松开输入1电平 #define ledmodle P1_7 //定义工作模式指示灯控制--------输出1电平灯亮,输出0电平灯亮,用来指示测量模式 #define baiwei P2_1 //定义百位驱动口------------------百位数码管输出控制端,输出0电平对应的百位点亮,输出1电平对应的百位亮 #define shiwei P2_4 //定义十位驱动口------------------十位数码管输出控制端,输出0电平对应的十位点亮,输出1电平对应的十位亮 #define gewei P2_7 //定义个位驱动口------------------个位数码管输出控制端,输出0电平对应的个位点亮,输出1电平对应的个位亮 code uchar datab[10]={0xA0,0xAF,}; //定义共阳极七段译码值,对应0-9的10个数字,请补全10个数字的码值。也可以自己编制特别字符 //用code关键字是为了把数组定义在程序存储区 uint heartrate=0; //定义心率值存储变量 uchar ge,shi,bai; //定义心率计数三个位的显示值 uint i=0; //定义全局变量,用于定时计数 bit flag=0; //定义时间标志位变量 uchar display_period=5; //一个显示周期的时间长度,单位为ms,5ms=5000us,与实习报告所测得的一致 //-----------------------------------------------------------------------------// //函数声明---------------------------------------------------------------------// //-----------------------------------------------------------------------------// void mcuint(void); //单片机初始化函数 void delay1ms(uint count); //毫秒级延时函数 void measure_slow(void); //心率测量函数 快速测量心率的函数自行考虑 //-----------------------------------------------------------------------------// //主函数,开机初始化单片机,并显示2s的888,用于检测笔画是否接正确--------------// //-----------------------------------------------------------------------------// void main(void) { mcuint(); //heartrate=888; //delay1ms(800); heartrate=321; while(1) { measure_slow(); } } //-----------------------------------------------------------------------------// //单片机初始化函数-------------------------------------------------------------// //-----------------------------------------------------------------------------// void mcuint(void) { P0=0xFF; //使单片机上电后P0口都输出1 P1=0xFF; //使单片机上电后P1口都输出1 P2=0xFF; //使单片机上电后P2口都输出1 P3=0xFF; //使单片机上电后P3口都输出1 TMOD=0x11; //设定定时器T0、T1的工作模式为16位定时器 TL0=(65536-display_period*500)%256; //设定定时器T0的低8位初值---T0用于刷新数码管显示 TH0=(65536-display_period*500)/256; //设定定时器T0的高8位初值---T0用于刷新数码管显示 TL1=(65536-100*500)%256; //设定定时器T1的低8位初值---100为100毫秒,1次计时100毫秒,600次就是1分钟 TH1=(65536-100*500)/256; //设定定时器T1的高8位初值 IE=0x8A; //开总中断定时器T0中断定时器T1中断 IP=0x08; //设定中断优先级,定时器T1中断优先 TR0=1; //开启定时器T0数码管开始定时刷新显示 } //-----------------------------------------------------------------------------// //延时1ms的函数----------------------------------------------------------------// //-----------------------------------------------------------------------------// void delay1ms(uint count) { int m,n; for(m=0;m<count;m++) for(n=0;n<59;n++) ; } //-----------------------------------------------------------------------------// //T0中断服务函数,作用是每5ms扫描一次数码管------------------------------------// //-----------------------------------------------------------------------------// void timer0() interrupt 1 { TL0=0x3C; TH0=0xF6; //假设每分钟135次 ,heartrate=321 bai=heartrate/100; //计算百位数值 shi=(heartrate/10)%10; //计算十位数值 ge=heartrate%10; //计算个位数值 //以下三个语句为显示个位的数值 P0=datab[ge]; //把各位显示数值的码值取出来给P0 gewei=0; //P2_7=0; 相当于开启个位的电源 delay1ms(1); gewei=1; //P2_7=1; 相当于关闭个位的电源 //请补全后面的显示十位、百位的语句 } //-----------------------------------------------------------------------------// //T1中断函数,作用是1分钟计时,时间到置标志位为1------------------------------// //-----------------------------------------------------------------------------// void timer1() interrupt 3 { TL1=0xB0; TH1=0x3C; i++; if(i==600) //600次计时到,则1分钟时间到 { i=0; //计数变量归0 flag=1; //时间到标志位置1 } } //-----------------------------------------------------------------------------// //慢速测量心率函数-------------------------------------------------------------// //-----------------------------------------------------------------------------// void measure_slow(void) { if(keystart==0) { TR1=1; //开启定时器,开始60秒计时 ledtest=0; //点亮测量指示灯 //剩下的自己思考后补全 } }
最新发布
09-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值