OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 6514|回复: 17

开启我的51单片机学习之路,基于51单片机数码管显示电子时钟

[复制链接]

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
发表于 2019-7-21 07:53:35 | 显示全部楼层 |阅读模式
1 、此款电子时钟,时间可以设置,有4个按键,一个功能按键,一个加,一个减,一个确定按键。
2、按下功能按键一下,时钟走时停止,时两位数码管闪烁,代表此时再调时状态,这个时候加减按键就可以调整时钟,再次按下功能按键,就可以调整分钟,再按一下功能按键就可以设置秒。设置好时间后我们按确定按键,时钟开始走时。
3、这个程序将很好的教会我们怎么让数码管闪烁显示。
#include <REG51.H>
typedef unsigned int UINT;
typedef unsigned char UCHAR ;
sbit key1=P3^3;
sbit key2=P3^4;
sbit key3=P3^5;
sbit key6=P3^6;
sbit LE1 = P3^1;  //定义位控口   
sbit LE2 = P3^2;  //定义段控口
UCHAR MODE ;
UCHAR page ;
signed char  HH = 0;  //小时初始值
signed char  MM = 0;  //分钟初始值
signed char SS = 0;  //秒初始值
UINT u1_10ms  = 0; //10ms计数
UINT u2_10ms  = 0;
bit T_CYCLE = 0;
extern void T0_Init(void); //初始化定时器,函数定义在timer.c
UCHAR code NUM[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};

void delay(UINT t) //延时t时钟周期
{
while (t--) ;
}

void H_Increase(void) //小时增1
{
IF(HH<23) HH++;
else
{
  HH = 0;
}
}

void M_Increase(void)  //分钟增1
{
if(MM<59) MM++;
else
{
  MM = 0;

}
}

void S_Increase(void)  //秒增1
{
if(SS<59) SS++;
else
{
  SS = 0;

}
}
void H(void) //小时增1
{
if(HH>0) HH--;
else
{
  HH =23;
}
}

void M(void)  //分钟增1
{
if(MM>0) MM--;
else
{
  MM = 59;

}
}

void S(void)  //秒增1
{
if(SS>0) SS--;
else
{
  SS = 59;

}
}
void display(UCHAR SEG,UCHAR Digi) //显示一位数码管,SEG = 0-9数字,Digi = 第0-6位
{
LE2 = 1;
P0 = (0x01<<Digi) ;
LE2 = 0;
P0 = 0x00;
LE1 = 1;
P0 = NUM[SEG];
if (Digi==1||Digi==4) P1&= 0x7f ;  //显示分隔符
delay(50);
P0 = 0xff;
LE1 = 0;
}
void key()
{

if(key1==0)
{
  delay(2);
  if(key1==0)
  {
   while(!key1);
        TR0=0;
  
       if(MODE == 3) MODE = 1;
   else MODE ++;
   
  
     }
  }
   
  if(key2==0)
{
  delay(2);
  if(key2==0)
  {
   while(!key2);
  
     if(MODE == 1) H_Increase() ;
    if(MODE == 2) M_Increase() ;
     if(MODE == 3) S_Increase() ;
     
     }
  }
if(key3==0)
{
  delay(2);
  if(key3==0)
  {
   while(!key3);
  
           if(MODE == 1) H() ;
    if(MODE == 2) M() ;
     if(MODE == 3) S() ;
     
           }
  
  
   
  }

   if(key6==0)
{
  delay(2);
  if(key6==0)
  {
   while(!key6);
         TR0=1;
   MODE=0;
     }
  }
}
void main(void)
{
    P1 = 0xff;
    LE1 = 0;
    LE2 = 0;
T0_Init();
    while(1)
{
     key();
  if(MODE != 1 || T_CYCLE)
  {
   display(HH/10,0);  //显示小时十位数
   display(HH%10,1);  //显示小时个位数
      display(10,2);  
  }
  if(MODE != 2  || T_CYCLE)
  {
   display(MM/10,3);  //显示分钟十位数
   display(MM%10,4);  //显示分钟个位数
   display(10,5);  //显示小时个位数
  }
   if(MODE != 3  || T_CYCLE)
  {
  display(SS/10,6);  //显示秒十位数
  display(SS%10,7);  //显示秒个位数
  }
}
}
extern void key_Process(void);
extern void S_Increase(void);

void T0_Init(void)
{
TMOD = 0x11;
//定时器赋初始值,定时时间为10ms。
TH0 = 0xd8;
TL0 = 0xf0;
TH1 = 0xd8;
TL1= 0xf0;
ET0=1;
ET1=1;
TR0=1;
TR1=1;
EA=1;
}

void T0_INTSrv(void) interrupt 1
{
//定时器重新开始计时
TH0 = 0xd8;
TL0 = 0xf0;
u1_10ms ++;
if (u1_10ms>99) // 1000 ms = 1 second
{
  u1_10ms = 0;
  SS++;
  if(SS==60)
  {
   SS=0;
   MM++;
   if(MM==60)
   {
    MM=0;
    HH++;
    if(HH==24)
    HH=0;
   }
  }
}
}
void T1_INTSrv(void) interrupt 3
{
//定时器重新开始计时。
TH0 = 0xd8;
TL0 = 0xf0;
u2_10ms ++;
if (u2_10ms%10==0) // 100 ms
{
  T_CYCLE = ! T_CYCLE; //闪烁循环
}
}



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-8-15 08:33:48 | 显示全部楼层
好多天没来了,今天我给大家讲下在我们单片机系统中,对一个连续的脉冲波频率进行测量的一些方法,在单片机中主要是利用定时/计数器来完成的,测量的方法有以下两种,第一:测频法,就是在限定的时间内,如一秒检测脉冲的个数。第二:测周期法:测试限定的脉冲个数之间的时间。
回复 支持 1 反对 0

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-8-3 22:13:06 | 显示全部楼层
总结:一个电子时钟系统完美的做出来,也可以说单片机你入门了,这个电子时钟系统我门还是可以完善的,比如说,可以实现按键的连按,在设置状态下,超过多少秒没有在操作,就返到正常显示界面。总之,按键的处理过程要精益求精,尽量做到人性化的设计,我门应该明白,产品的使用者并不是专业人员,绝对可能胡乱按键,在这种情况下,要依靠程序来保证正常运行。
回复 支持 1 反对 0

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-7-30 19:03:52 | 显示全部楼层
技术在于交流,希望大家把自己项目上面的积累的经验能来出来和大家分享!我在坚持着……
回复 支持 1 反对 0

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-7-21 09:56:47 | 显示全部楼层
这个手把手教你学51单片机资料比较好,推得学习!

手把手教你学51单片机-C语言版.pdf

12.41 MB, 下载次数: 170

回复 支持 1 反对 0

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-7-25 07:44:49 | 显示全部楼层
这个小项目虽然很简单,这里面也有一个知识点,就是怎么样位调时间的时候数码管闪烁,我们开启了一个定时器,定时100MS,并做一个标志位,但我按键按下的,我们让数码管每隔100MS,给数码管送显示的段码,在隔100MS给数码管送不显示的段码,这样数码管就可以成功的闪烁了。这个知识点也适合我们后来学习的1602,12864,2.6寸,3.2寸液晶,这些上面让字符显示闪烁的原理是一样。
回复 支持 反对

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-7-25 20:15:43 | 显示全部楼层
1通过红外对管模块实时检测车位是否占用,车位分为1车位,2车位,3车位。
2液晶实时显示车位是否被占用、车位被占用数、空车位数,红外对管有检测遮挡距离近,
表示停有车辆。
3车位处是否停车并有状态指示灯指示。
4每个车位车位被占用5秒内免费,超过5秒收费2元,并在液晶LCD1602上显示出来,
红外对管传感器上电开始检测,液晶开始显示计价,除非再次按下复位按键或者断电,
则金额清零,否则不清零。
回复 支持 反对

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-7-25 20:16:15 | 显示全部楼层
#include<reg52.h>
#include"delay.h"
#include"lcd602.h"
/************************端口定义**************************/
sbit led1 = P1^3; //车位1指示灯
sbit led2 = P1^4; //车位2指示灯
sbit led3 = P1^5; //车位3指示灯
sbit hongwai1 = P1^0; //红外1
sbit hongwai2 = P1^1; //红外2
sbit hongwai3 = P1^2; //红外3

/*******************变量定义********************/
uchar flag1 = 0; //车位1状态标志
uchar flag2 = 0; //车位2状态标志
uchar flag3 = 0; //车位3状态标志
uchar flag_1 = 0; //车位1计费状态标志
uchar flag_2 = 0; //车位2计费状态标志
uchar flag_3 = 0; //车位3计费状态标志
uchar temp1 = 0; //定时器0定时1S变量
long int sec1 = 0; //车位1时间计时变量
uchar temp2 = 0; //定时器1定时1S变量
long int sec2 = 0; //车位2时间计时变量
uchar temp3 = 0; //定时器2定时1S变量
long int sec3 = 0; //车位3时间计时变量
/*******************定时器T0初始化********************/
void T0_init()
{
          TMOD = TMOD | 0x01; //设T0为方式1
          TH0 = (65535-50000)/256; //计数50000个
          TL0 = (65535-50000)%256;
          EA = 1; //开启总中断         
          ET0 = 1; //允许T0中断
          //TR0 = 1; //启动
}

/*******************定时器T1初始化********************/
void T1_init()
{
          TMOD = TMOD | 0x10; //设T1为方式1
          TH1 = (65535-50000)/256; //计数50000个
          TL1 = (65535-50000)%256;
          EA = 1; //开启总中断         
          ET1 = 1; //允许T1中断
          //TR1 = 1; //启动
}
///*******************T2-初始化********************/
void init_t2()
{
        T2CON = 0x00; //工作模式

        RCAP2H = (65535-50000)/256;  //自动装载初值
        RCAP2L = (65535-50000)%256;  //
        TH2 = RCAP2H;
    TL2 = RCAP2L;
        EA = 1; //开总中断
        ET2 = 1; //T2中断
        //TR2 = 1; //启动
}
/*******************主函数********************/
void main()
{
   chushihua(); //LCD1602初始化

   T0_init();
   T1_init();
   init_t2();
   while(1)
        {       
                  /*检测车位的状态*/
                  if(hongwai1==1) //车位1没有占用
                  {
                     flag1 = 0;
             led1 = 1;
                         write_zifu(1,0,'1');
                         write_zifu(1,1,':');
                         write_zifu(2,1,'N');
                         flag_1 = 0;
                         sec1 = 0;
                  }
                  else //车位1占用
                  {
                     flag1 = 1;
                         led1 = 0;
                                  write_zifu(1,0,'1');
                         write_zifu(1,1,':');
                         write_zifu(2,1,'Y');
                         TR0 = 1; //启动
                  }
                  if(hongwai2==1) //车位2没有占用
                  {
                     flag2 = 0;
             led2 = 1;
                         write_zifu(1,4,'2');
                         write_zifu(1,5,':');

                         write_zifu(2,4,'N');
                         flag_2 = 0;
                         sec2 = 0;
                  }
                  else //车位2占用
                  {
                     flag2 = 1;
                         led2 = 0;
                         write_zifu(1,4,'2');
                         write_zifu(1,5,':');

                         write_zifu(2,4,'Y');
                         TR1 = 1; //启动
                  }               
                  if(hongwai3==1) //车位3没有占用
                  {
                     flag3 = 0;
             led3 = 1;
                         write_zifu(1,8,'3');
                         write_zifu(1,9,':');
                         write_zifu(2,8,'N');
                         flag_3 = 0;
                         sec3 = 0;
                  }
                  else //车位3占用
                  {
                     flag3 = 1;
                         led3 = 0;
                                  write_zifu(1,8,'3');
                         write_zifu(1,9,':');
                         write_zifu(2,8,'Y');
                         TR2 = 1; //启动
                  }       
                  /*计算空车位和占用的车位*/
                  write_zifu(1,13,'P'); //显示占用的车位
                  write_num1(2,13,flag3+flag2+flag1); //显示占用的车位
                   write_zifu(1,15,'N'); //显示占用的车位
                  write_num1(2,15,3-flag3-flag2-flag1); //显示空车位       
                  /*显示占用车位的费用*/
                  if(flag_1==0) write_num1(1,2,0); //显示占用的车位1费用
                  else write_num1(1,2,2); //显示占用的车位1费用
                  if(flag_2==0) write_num1(1,6,0); //显示占用的车位2费用
                  else write_num1(1,6,2); //显示占用的车位2费用
                  if(flag_3==0) write_num1(1,10,0); //显示占用的车位3费用
                  else write_num1(1,10,2); //显示占用的车位3费用                             
        }
}
/**************************定时器T0中断服务函数************************************/
void T0_time() interrupt 1   
{
     TH0 = (65535-50000)/256; //计数50000个
         TL0 = (65535-50000)%256;
         temp1 += 1;
         if(temp1>=20)
         {
            temp1 = 0;
                sec1 += 1;
                if(sec1>=5)
                {
                   flag_1 = 1;
                }
         }
}
/**************************定时器T1中断服务函数************************************/
void T1_time() interrupt 3   
{
     TH1 = (65535-50000)/256; //计数50000个
         TL1 = (65535-50000)%256;
         temp2 += 1;
         if(temp2>=20)
         {
            temp2 = 0;
                sec2 += 1;
                if(sec2>=5)
                {
                   flag_2 = 1;
                }
         }
}
/*******************T2中断函数函数********************/
void T2_time() interrupt 5
{
     TF2 = 0;
         temp3 += 1;
         if(temp3>=20)
         {
            temp3 = 0;
                sec3 += 1;
                if(sec3>=5)
                {
                   flag_3 = 1;
                }
         }
}
回复 支持 反对

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-7-29 14:55:28 | 显示全部楼层
用按键和数码管以及单片机定时器实现一个简易的可以调整的时钟,要求如下:
8位数码管显示,显示格式如下
时-分-秒
XX-XX-XX
要求:系统有三个按键,功能分别是调整,加,减。在第一次按下调整键时候,停止走时,显示秒的两位数码管以1 Hz 频率闪烁;如果第二次按下调整键,则分开始闪烁,秒恢复正常显示;如果第三次按下调整键,则时开始闪烁,分恢复正常显示;如果第四次按下调整键,时恢复正常显示,开始走时。在数码管闪烁的时候,按下加或者减键可以调整相应的显示内容。
/*****************************
作者:liyang
日期:2019年7月29日
目标MCU:STC89C51  晶振:11.0592M
******************************/
#include<reg51.h>
typedef unsigned char uint8;
typedef unsigned int uint16;
uint8 LedBitCnt; //LedBitCnt控制数码管的位选
uint8 flagm=0,flagf=0,flags=0;//时分秒闪烁的控制标志位
uint8 ms2_flag; //2ms数码管动态扫描时标消息
uint ms10_flag,ms500_flag;
uint8 ms2_cnt,ms10_cnt,count,s1num;
uint8 dis_buff[8]={0};
uint8 shi=12,fen=23,miao=56;
uint8 code SegTab[]={0x3f,0x06,0x5b,0x4f,
                                        0x66,0x6d,0x7d,0x07,
                                        0x7f,0x6f,0x40,0x00};
sbit ADDR0 = P2^0;//74hc138的输入控制端A
sbit ADDR1 = P2^1;//74hc138的输入控制端B
sbit ADDR2 = P2^2;//74hc138的输入控制端C
sbit adjust=P3^2;
sbit add=P3^3;
sbit sub=P3^4;
void delayms(uint8  z)
{
        uint8 i,j;
        for(i=z;i>0;i--)
                for(j=110;j>0;j--);
}

void disp()
{
        P0=SegTab[dis_buff[LedBitCnt]];
        switch(LedBitCnt)
        {
                case 0:
                ADDR0=0;ADDR1=0;ADDR2=0;
                break;
                case 1:
                ADDR0=1;ADDR1=0;ADDR2=0;
                break;
                case 2:
                ADDR0=0;ADDR1=1;ADDR2=0;
                break;
                case 3:
                ADDR0=1;ADDR1=1;ADDR2=0;
                break;
                case 4:
                ADDR0=0;ADDR1=0;ADDR2=1;
                break;
                case 5:
                ADDR0=1;ADDR1=0;ADDR2=1;
                break;
                case 6:
                ADDR0=0;ADDR1=1;ADDR2=1;
                break;
                case 7:
                ADDR0=1;ADDR1=1;ADDR2=1;
                break;
        }

}
void time_to_disbuff(void)
{
        if(flagm&(!ms500_flag))
        {   
                dis_buff[7]=11;
                dis_buff[6]=11;
          }
          else
        {
                dis_buff[7]=miao%10;
                dis_buff[6]=miao/10;
        }
        dis_buff[5]=10;
        if(flagf&(!ms500_flag))
        {   
                dis_buff[4]=11;
                dis_buff[3]=11;
          }
        else
        {
                dis_buff[4]=fen%10;
                dis_buff[3]=fen/10;
        }
        dis_buff[2]=10;
        if(flags&(!ms500_flag))
        {   
                dis_buff[1]=11;
                dis_buff[0]=11;
          }
        else
        {
                dis_buff[1]=shi%10;
                dis_buff[0]=shi/10;
          }
}
void init()
{
        TMOD=0x11;
        TH1=0xf8;
        TL1=0xcd;
        TH0=0x4c;
        TL0=0x00;
        TR0=1;
        ET0=1;
        TR1=1;
        ET1=1;                       
}
void keyscan()
{
        if(adjust==0)
                {
                        delayms(10);
                        if(adjust==0)
                                {
                                        s1num++;
                                        while(!adjust);
                                        if(s1num==1)
                                        {
                                                flagm=1;
                                                TR0=0;
                                        }
                                }
                }
               
                        if(s1num==2)
                {
                        flagm=0;
                        flagf=1;
                }

         if(s1num==3)
                {
                        flagm=0;
                        flagf=0;
                        flags=1;
                }
        if(s1num==4)
        {
                TR0=1;
                flags=0;
                s1num=0;
        }
        if(adjust!=0)
                {
                        if(add==0)
                        {
                                delayms(10);
                                if(add==0)
                                {
                                        while(!add);
                                        if(s1num==1)
                                        {
                                                miao++;
                                                if(miao==60)
                                                        miao=0;
                                       
                                               
                                               
                                        }
                                        if(s1num==2)
                                        {
                                                fen++;
                                                if(fen==60)
                                                        fen=0;
                                               
                                       
                                        }
                                        if(s1num==3)
                                        {
                                                shi++;
                                                if(shi==24)
                                                        shi=0;
                                               
                                        }
                                }
                        }
                        if(sub==0)
                        {
                                delayms(10);
                                if(sub==0)
                                {
                                        while(!sub);
                                        if(s1num==1)
                                        {
                                       
                                                miao--;
                                                if(miao==-1)
                                                        miao=59;
                                               
                                        }
                                        if(s1num==2)
                                        {
                                                fen--;
                                                if(fen==-1)
                                                        fen=59;
                                       
                                        }
                                        if(s1num==3)
                                        {
                                                shi--;
                                                if(shi==-1)
                                                        shi=23;
                                               
                                        }
                                }
                        }
                }
       
       
}
void main()
{
        init();
        EA=1;
        time_to_disbuff();
        P0=0x00;
        while(1)
        {               
                keyscan();
                if(ms2_flag)
                        {
                                ms2_flag=0;
                            LedBitCnt++;
                                if(LedBitCnt>7)
                                {
                                        LedBitCnt=0;
                                }
                                time_to_disbuff();
                                disp();
                       
                        }       
                if(ms10_flag)
                        {
                                ms10_flag=0;
                        }
       
        }
       
}
void timer0() interrupt 1
{
        TH0=0x4c;
        TL0=0x00;
        count++;
        if(count==20)
        {
                count=0;
                miao++;
                if(miao==60)
                {
                        miao=0;
                        fen++;
                        if(fen==60)
                        {
                                fen=0;
                                shi++;
                                if(shi==24)
                                {
                                        shi=0;
                                }
                        }
                }
        }

}
void timer1() interrupt 3  //定时1ms
{
        TH1=0xf8;
        TL1=0xcd;
        ms2_flag=1;   //用于数码管显示
        ms2_cnt++;
        if(ms2_cnt>=5)
        {
                ms2_cnt=0;  
                ms10_flag=1;//用于键扫描
                if(++ms10_cnt>=50)
                        {
                                ms10_cnt=0;
                                ms500_flag=~ms500_flag;
                        }
        }
}
总结:1 先开辟一个数码管显示的缓冲区,动态扫描函数函数负责从这个缓冲区中取出数据,并扫描显示。而其他函数则可以修改该缓冲区,从而改变显示的内容。
2 要学会标志位的灵活应用
3 按键程序存在不足,使用了延时函数delayms(10),让控制器在这白白等待了10ms的时间,啥也没干。这是不可取的。其次while(!adjust);更是程序设计的大忌(极少的特殊情况例外)。原本是等待按键释放,结果CPU就一直死死的盯住该按键,其他事情都不管了。
4 要处理好按键程序不足,就得学习按键状态机


回复 支持 反对

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-7-29 15:02:36 | 显示全部楼层
状态机的学习
有限状态机由有限的状态和相互之间的转移构成,在任何时候只
能处于给定数目的状态中的一个。当接收到一个输入事件时,状态机产生一个输出,同时也可能伴随着状态的转移。
#define key_input    PIND.7      // 按键输入口
#define key_state_0  0
#define key_state_1  1
#define key_state_2  2
char read_key(void)
{
static char key_state = 0;
char key_press, key_return = 0;
key_press = key_input;        // 读按键 I/O (状态机的输入)
switch (key_state)
{
case key_state_0:        // 按键初始态
        if (!key_press) key_state = key_state_1;  // 键被按下,状态转换到键确认态 , 确定下一次按键的状态值
break;
case key_state_1:        // 按键确认态
if (!key_press)
{
            key_return = 1;      // 按键仍按下,按键确认输出为“1”
            key_state = key_state_2;  // 状态转换到键释放态
}
else
            key_state = key_state_0;  // 按键已抬起,转换到 按键初始态
       break;
case key_state_2:
            if (key_press) key_state = key_state_0;  //按键已释放,转换到按键初始态
       break;
}  
     return key_return;
}
该简单按键接口函数 read_key()在整个系统程序中应每隔10ms
调用执行一次,每次执行时将先读取与按键连接的 I/O 的电平到变量 key_press 中,然后进入用 switch 结构构成的状态机。switch 结构中的 case 语句分别实现了 3 个不同状态的处理判别过程,在每个状态中将根据状态的不同,以及 key_press 的值(状态机的输入)确定输出值(key_return),和确定下一次按键的状态值(key_state) 。 函数 read_key()的返回参数提供上层程序使用。返回值为 0 时,表示按键无动作;而返回 1 表示有一次按键闭合动作,需要进入按键处理程序做相应的键处理。在函数 read_key()中定义了 3 个局部变量,其中 key_press和key_return为一般普通的局部变量,每次函数执行时,key_press 中保存着刚检测的按键值。key_return 为函数的返回值,总是先初始化为 0,只有在状态 1 中重新置 1,作为表示按键确认的标志返回。变量 key_state 非常重要,它保存着按键的状态值,该变量的值在函数调用结束后不能消失,
必须保留原值,因此在程序中定义为“局部静态变量” ,用static 声明。如果使用的语言环境不支持 static 类型的局部变量,应将 key_state 定义为全局变量(关于局部静态变量的特点请参考相关介绍 C 语言程序设计的书籍) 。
回复 支持 反对

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-7-30 16:54:27 | 显示全部楼层
强制转化的应用:
1 、 uint a,b,c,d;
       a=At24c02Read(0); b=At24c02Read(1); c=At24c02Read(2); d=At24c02Read(3); MAX=((a*1000)+b*100+c*10+d);
       AT24C02函数是返回一个无符号字符,上面是我以前的代码,这个程序浪费个程序内存空间,其实用一个强制转化就可以解决问 题。 MAX=(((uint)At24c02Read(0)*1000)+(uint)At24c02Read(0)*100+(uint)At24c02Read(0)*10+(uint)At24c02Read(0));这样就可以节省很多内存空间。
回复 支持 反对

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-8-3 21:45:27 | 显示全部楼层
/*********************************************************************************
* 【编写时间】: 2019年8月1日
* 【作    者】: 震撼科技
* 【版    本】: 1.0
* 【Q      Q】:  515580142@qq.com
* 【淘宝店铺】: https://shop104059509.taobao.com ... .d21.47ad41c96Churz
* 【实验平台】: 单片机开发板
* 【外部晶振】: 11.0592mhz       
* 【主控芯片】: STC89C52
* 【编译环境】: Keil μVisio4       
* 【程序功能】:                                                                                            
* 【使用说明】:
*  说明:免费开源,不提供源代码分析.
**********************************************************************************/
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula = P2^6;  //定义位控口                       
sbit wela = P2^7;  //定义段控口;
uchar code led_7[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                    0x07,0x7f,0x6f,0x40,0x00};//数码管段码0~9,-
char time[3];//时分秒计数单元
uchar  dis_buff[8];//显示缓冲区,存放要显示的8个字符的段码值
uchar flag_1s,flag_10ms;
bit flag_500ms;
unsigned char s1num= 0;
void display(void);
void Init(void);
void time_to_disbuff(void);
unsigned char KeyScan();
void KeyAction(unsigned char keycode);
void main(void)
{
                Init();
                time[2]=10;
                time[1]=58;
                time[0]=55;
                time_to_disbuff();
                while(1)
                {
                    time_to_disbuff();
                    if(flag_1s)
                        {
                                flag_1s=0;
                                time[0]++;
                                if(time[0]>=60)
                                {
                                        time[0]=0;
                                        time[1]++;
                                        if(time[1]>=60)
                                        {
                                                time[1]=0;
                                                time[2]++;
                                                if(time[2]>=24)
                                                        time[2]=0;
                                       
                                        }
                                }
                               
                        }
                        if(flag_10ms==1)
                        {
                                flag_10ms=0;
                                KeyAction(KeyScan());
                        }
         
                }               
}
void time_to_disbuff(void)
{
      if(s1num!=1)
          {
                  dis_buff[0]=time[2]/10;
                  dis_buff[1]=time[2]%10;
          }
          else
          {
                        if(flag_500ms)
                        {
                                dis_buff[0]=time[2]/10;
                                dis_buff[1]=time[2]%10;
                        }
                        else
                        {
                                dis_buff[0]=11;
                                dis_buff[1]=11;
                        }
          }
          dis_buff[2]=10;
          if(s1num!=2)
          {
                  dis_buff[3]=time[1]/10;
                  dis_buff[4]=time[1]%10;
          }
          else
          {
                        if(flag_500ms)
                        {
                                dis_buff[3]=time[1]/10;
                                dis_buff[4]=time[1]%10;
                        }
                        else
                        {
                                dis_buff[3]=11;
                                dis_buff[4]=11;
                        }
          }
          dis_buff[5]=10;
          if(s1num!=3)
          {
                  dis_buff[6]=time[0]/10;
                  dis_buff[7]=time[0]%10;
      }         
          else
          {
                        if(flag_500ms)
                        {
                                dis_buff[6]=time[0]/10;
                                dis_buff[7]=time[0]%10;
                        }
                        else
                        {
                                dis_buff[6]=11;
                                dis_buff[7]=11;
                        }
          }
}
void display(void)
{
        static uchar posit=0;
        P0 = 0x00; //消影
        dula=1;
        dula = 0;
       
        P0 = ~(0x01<<posit);
        wela = 1;
        wela = 0;
        P0 = led_7[dis_buff[posit]];
        dula=1;
        dula = 0;
        if(++posit>=8) posit=0;
}
void Init(void)
{
                TMOD = 0x11;
                TH0 = (65536-1000)/256;
                TL0 = (65536-1000)%256;
                TH1 = (65536-2000)/256;
                TL1=  (65536-2000)%256;
                ET0=1;
                ET1=1;
                TR0=1;
                TR1=1;
                EA=1;
}
/* 按键扫描函数,需在定时中断中调用,推荐调用间隔10ms */
unsigned char KeyScan()
{
           static uchar State_Cnt=0;//静态变量,用于改变状态过程
       unsigned char Key_State = 0;//用于存储键值码
       switch(State_Cnt)
       {

               case 0x00:
                           P3 = 0x1f;//先往P3(1到5独立按键)口送0001 1111
               if(P3 != 0x1f)//有无按键被按下
               {
                    State_Cnt = 0x01;//改变状态
                    break;                           

               }
               case 0x01:
               if(P3 != 0x1f)//经过定时器延时后,再次判断按键是否按下
               {
                     State_Cnt = 0x02;//改变状态
                     Key_State = P3;//把键值保存下来
                     P3 = 0x1f;//恢复P3,以便下次按下重新保存键值
                     break;

                }
                else
                {
                                        State_Cnt = 0x00;//改变状态
                    break;

                }
               case 0x02:
               if(P3 == 0x1f)//判断按键释放
               {
                     State_Cnt = 0x00;//改变状态
                                         break;
                           }
               default:break;

       }
       return Key_State;//返回键值

}
/* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */
void KeyAction(unsigned char keycode)
{
   // static unsigned char i = 0;
    if(keycode == 0x1e)  //功能按键
    {
        s1num++;
                TR0=0;
                if(s1num>3)
                {
                        s1num=0;
                        TR0=1;
                }  
    }
    else if (keycode == 0x1d)  //向上键
    {
        if(s1num==1)
                {
                        time[2]++;
                        if(time[2]>=24)
                                 time[2]=0;
                }
                if(s1num==2)
                {
                        time[1]++;
                        if(time[1]>=60)
                                 time[1]=0;
                }
                if(s1num==3)
                {
                        time[0]++;
                        if(time[0]>=60)
                                 time[0]=0;
                }
    }
    else if (keycode == 0x1b)  //向下键
    {
                 if(s1num==1)
                {
                        time[2]--;
                        if(time[2]<0)
                                 time[2]=23;
                }
                if(s1num==2)
                {
                        time[1]--;
                        if(time[1]<0)
                                 time[1]=59;
                }
                if(s1num==3)
                {
                        time[0]--;
                        if(time[0]<0)
                                 time[0]=59;
                }
    }
}
void InterruptTimer0(void) interrupt 1 //定时1MS
{
                static uint time_counter=0;
                //定时器重新开始计时。
            TH0 = (65536-1000)/256;
                TL0 = (65536-1000)%256;
                time_counter++;
                if(time_counter>=1000)
                {
                        time_counter=0;
                        flag_1s=1;
                }
               
}
void InterruptTimer1(void) interrupt 3 //定时器1,定时2MS,动态扫描数码管
{
                static uint count;
                static uint count1;
                //定时器重新开始计时。
                TH1 = (65536-2000)/256;
                TL1=  (65536-2000)%256;
                display();
                count++;
                count1++;
                if(count>=5)
                {
                        count=0;
                        flag_10ms=1;
                }
                if(count1>=250)
                {
                   count1=0;
                   flag_500ms=~flag_500ms;
                }
               
}
回复 支持 反对

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-8-3 21:46:25 | 显示全部楼层
/*********************************************************************************
* 【编写时间】: 2019年8月1日
* 【作    者】: 震撼科技
* 【版    本】: 1.0
* 【Q      Q】:  515580142@qq.com
* 【淘宝店铺】: https://shop104059509.taobao.com ... .d21.47ad41c96Churz
* 【实验平台】: 单片机开发板
* 【外部晶振】: 11.0592mhz       
* 【主控芯片】: STC89C52
* 【编译环境】: Keil μVisio4       
* 【程序功能】:                                                                                            
* 【使用说明】:
*  说明:免费开源,不提供源代码分析.
**********************************************************************************/
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula = P2^6;  //定义位控口                       
sbit wela = P2^7;  //定义段控口;
uchar code led_7[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
                    0x07,0x7f,0x6f,0x40,0x00};//数码管段码0~9,-
char time[3];//时分秒计数单元
uchar  dis_buff[8];//显示缓冲区,存放要显示的8个字符的段码值
uchar flag_1s,flag_10ms;
bit flag_500ms;
unsigned char s1num= 0;
void display(void);
void Init(void);
void time_to_disbuff(void);
unsigned char KeyScan();
void KeyAction(unsigned char keycode);
void main(void)
{
                Init();
                time[2]=10;
                time[1]=58;
                time[0]=55;
                time_to_disbuff();
                while(1)
                {
                    time_to_disbuff();
                    if(flag_1s)
                        {
                                flag_1s=0;
                                time[0]++;
                                if(time[0]>=60)
                                {
                                        time[0]=0;
                                        time[1]++;
                                        if(time[1]>=60)
                                        {
                                                time[1]=0;
                                                time[2]++;
                                                if(time[2]>=24)
                                                        time[2]=0;
                                       
                                        }
                                }
                               
                        }
                        if(flag_10ms==1)
                        {
                                flag_10ms=0;
                                KeyAction(KeyScan());
                        }
         
                }               
}
void time_to_disbuff(void)
{
      if(s1num!=1)
          {
                  dis_buff[0]=time[2]/10;
                  dis_buff[1]=time[2]%10;
          }
          else
          {
                        if(flag_500ms)
                        {
                                dis_buff[0]=time[2]/10;
                                dis_buff[1]=time[2]%10;
                        }
                        else
                        {
                                dis_buff[0]=11;
                                dis_buff[1]=11;
                        }
          }
          dis_buff[2]=10;
          if(s1num!=2)
          {
                  dis_buff[3]=time[1]/10;
                  dis_buff[4]=time[1]%10;
          }
          else
          {
                        if(flag_500ms)
                        {
                                dis_buff[3]=time[1]/10;
                                dis_buff[4]=time[1]%10;
                        }
                        else
                        {
                                dis_buff[3]=11;
                                dis_buff[4]=11;
                        }
          }
          dis_buff[5]=10;
          if(s1num!=3)
          {
                  dis_buff[6]=time[0]/10;
                  dis_buff[7]=time[0]%10;
      }         
          else
          {
                        if(flag_500ms)
                        {
                                dis_buff[6]=time[0]/10;
                                dis_buff[7]=time[0]%10;
                        }
                        else
                        {
                                dis_buff[6]=11;
                                dis_buff[7]=11;
                        }
          }
}
void display(void)
{
        static uchar posit=0;
        P0 = 0x00; //消影
        dula=1;
        dula = 0;
       
        P0 = ~(0x01<<posit);
        wela = 1;
        wela = 0;
        P0 = led_7[dis_buff[posit]];
        dula=1;
        dula = 0;
        if(++posit>=8) posit=0;
}
void Init(void)
{
                TMOD = 0x11;
                TH0 = (65536-1000)/256;
                TL0 = (65536-1000)%256;
                TH1 = (65536-2000)/256;
                TL1=  (65536-2000)%256;
                ET0=1;
                ET1=1;
                TR0=1;
                TR1=1;
                EA=1;
}
/* 按键扫描函数,需在定时中断中调用,推荐调用间隔10ms */
unsigned char KeyScan()
{
           static uchar State_Cnt=0;//静态变量,用于改变状态过程
       unsigned char Key_State = 0;//用于存储键值码
       switch(State_Cnt)
       {

               case 0x00:
                           P3 = 0x1f;//先往P3(1到5独立按键)口送0001 1111
               if(P3 != 0x1f)//有无按键被按下
               {
                    State_Cnt = 0x01;//改变状态
                    break;                           

               }
               case 0x01:
               if(P3 != 0x1f)//经过定时器延时后,再次判断按键是否按下
               {
                     State_Cnt = 0x02;//改变状态
                     Key_State = P3;//把键值保存下来
                     P3 = 0x1f;//恢复P3,以便下次按下重新保存键值
                     break;

                }
                else
                {
                                        State_Cnt = 0x00;//改变状态
                    break;

                }
               case 0x02:
               if(P3 == 0x1f)//判断按键释放
               {
                     State_Cnt = 0x00;//改变状态
                                         break;
                           }
               default:break;

       }
       return Key_State;//返回键值

}
/* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */
void KeyAction(unsigned char keycode)
{
   // static unsigned char i = 0;
    if(keycode == 0x1e)  //功能按键
    {
        s1num++;
                TR0=0;
                if(s1num>3)
                {
                        s1num=0;
                        TR0=1;
                }  
    }
    else if (keycode == 0x1d)  //向上键
    {
        if(s1num==1)
                {
                        time[2]++;
                        if(time[2]>=24)
                                 time[2]=0;
                }
                if(s1num==2)
                {
                        time[1]++;
                        if(time[1]>=60)
                                 time[1]=0;
                }
                if(s1num==3)
                {
                        time[0]++;
                        if(time[0]>=60)
                                 time[0]=0;
                }
    }
    else if (keycode == 0x1b)  //向下键
    {
                 if(s1num==1)
                {
                        time[2]--;
                        if(time[2]<0)
                                 time[2]=23;
                }
                if(s1num==2)
                {
                        time[1]--;
                        if(time[1]<0)
                                 time[1]=59;
                }
                if(s1num==3)
                {
                        time[0]--;
                        if(time[0]<0)
                                 time[0]=59;
                }
    }
}
void InterruptTimer0(void) interrupt 1 //定时1MS
{
                static uint time_counter=0;
                //定时器重新开始计时。
            TH0 = (65536-1000)/256;
                TL0 = (65536-1000)%256;
                time_counter++;
                if(time_counter>=1000)
                {
                        time_counter=0;
                        flag_1s=1;
                }
               
}
void InterruptTimer1(void) interrupt 3 //定时器1,定时2MS,动态扫描数码管
{
                static uint count;
                static uint count1;
                //定时器重新开始计时。
                TH1 = (65536-2000)/256;
                TL1=  (65536-2000)%256;
                display();
                count++;
                count1++;
                if(count>=5)
                {
                        count=0;
                        flag_10ms=1;
                }
                if(count1>=250)
                {
                   count1=0;
                   flag_500ms=~flag_500ms;
                }
               
}
回复 支持 反对

使用道具 举报

0

主题

131

帖子

0

精华

初级会员

Rank: 2

积分
175
金钱
175
注册时间
2019-7-1
在线时间
6 小时
发表于 2019-8-23 13:32:02 | 显示全部楼层
感谢分享
回复 支持 反对

使用道具 举报

23

主题

86

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2019-7-20
在线时间
108 小时
 楼主| 发表于 2019-9-8 19:48:41 | 显示全部楼层

51单片机如果采用11.0592MHZ的晶振,则一个机器周期等于12的震荡周期(晶振频率的倒数),即每个机器周期约是1.085us,其计算方法分析如下:
由于晶振是11.0592MHz,则一个机器周期等于(1S/11.0592MHZ)*12*106=1.085us
如果采用12MHZ的晶振,则一个机器周期等于(1S/12MHZ)*12*106=1us
以用采用11.0592MHZ的晶振,利用51单片机的定时器0产生2khz程序为例,分析如下:
2kHz是500us产生一个的方波(波峰250us,波谷250us)取半个周期记为t=250us
250us/1.09us需要计数229次,因而初值应装,TH0=(65536-229)/256  TL0=(65536-229)%256因为通过计算得到的初值产生的方波不一定十分准确(可能是由于晶振实际工作时的精度问题吧),所以通过用示波器实验测得,当初值t取221时,所得方波更接近2KHZ,约等于1.994KHZ,具体程序如下:
/* 产生标准2kHz频率的方波*/
#include
#define uchar unsigned char
#define uint unsigned int
sbit Waveout=P1^0; //P1.0口输出方波
void main()
{

//定时器0装初值



TH0=TH0=(65536-221)/256;



TL0=(65536-221)%256;



EA=1; //开总中断



ET0=1; //开定时器0中断



TR0=1; //启动定时器0



while(1);



}







//定时器0的中断服务函数



void T0_time() interrupt 1 //定时器0的中断序号为1



{



//进入中断重新装一次初值,确保每次的产生中断的时间相同



TH0=TH0=(65536-221)/256;



TL0=(65536-221)%256;



Waveout=!Waveout; //取反,产生2KHZ方波



}
回复 支持 反对

使用道具 举报

10

主题

560

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1770
金钱
1770
注册时间
2014-6-27
在线时间
961 小时
发表于 2019-9-10 14:48:34 | 显示全部楼层
本帖最后由 TinyBoy 于 2019-9-10 14:53 编辑

电子时钟的调整效果应该是:短按按键调整,立马调整一个数字,时分秒加或减一个数字,然后等待1S,1S后不释放按键,时分秒1S内加或减几个数字,快速调整,快到调整数字,立马释放,立马停止调整,然后短按,立马调整一个数字,释放,再短按,又调整一个数字,直到调到要调整的时分秒,你要做到这个调整效果才实用。所以你的按键这样扫描不实用,就是状态机扫描那个也没改善什么。
回复 支持 反对

使用道具 举报

14

主题

314

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1115
金钱
1115
注册时间
2011-10-19
在线时间
256 小时
发表于 2019-9-18 17:20:42 | 显示全部楼层
3个键就够了。
哥们的小店:http://shop103291259.taobao.com
回复 支持 反对

使用道具 举报

1

主题

3

帖子

0

精华

新手入门

积分
5
金钱
5
注册时间
2019-11-17
在线时间
1 小时
发表于 2019-11-19 13:44:09 | 显示全部楼层
bbxyliyang01 发表于 2019-7-30 19:03
技术在于交流,希望大家把自己项目上面的积累的经验能来出来和大家分享!我在坚持着……

一起加油,共勉。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-1 04:57

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表