2019-11-30 16:10:59 qq_37631068 阅读数 30
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏
  1. 实验目的和任务

目的:利用“模块化单片机教学实验平台”,加深对单片机与矩阵键盘的接口电路设计以及程序设计的理解。

任务:1、学习独立式按键的查询识别方法。

2、非编码矩阵键盘的行反转法识别方法。

3、掌握键盘接口的基本特点,了解独立键盘和矩阵键盘的应用方法。

4、掌握键盘接口的硬件设计方法,软件程序设计和贴士排错能力。

5、掌握利用Keil51软件对程序进行编译。

6、会根据实际功能,正确选择单片机功能接线,编制正确程序。对实验结果

  1. 实验原理

1、MCS51系列单片机的P0~P3口作为输入端口使用时必须先向端口写入“1”。

2、用查询方式检测按键时,要加入延时(通常采用软件延时10~20mS)以消除抖动。

3、识别键的闭合,通常采用行扫描法和行反转法。行扫描法是使键盘上某一行线为低电平,而其余行接高电平,然后读取列值,如读列值中某位为低电平,表明有键按下,否则扫描下一行,直到扫完所有行。

行反转法识别闭合键时,要将行线接一并行口,先让它工作在输出方式,将列线也接到一个并行口,先让它工作于输入方式,程序使CPU通过输出端口在各行线上全部送低电平,然后读入列线值,如此时有某键被按下,则必定会使某一列线值为0。然后,程序对两个并行端口进行方式设置,使行线工作于输入方式,列线工作于输出方式,并将刚才读得的列线值从列线所接的并行端口输出,再读取行线上输入值,那么,在闭合键所在行线上的值必定为0。这样,当一个键被接下时,必定可以读得一对唯一的行线值和列线值。由于51单片机的并口能够动态地改变输入输出方式,因此,矩阵键盘采用行反转法识别最为简便。

行反转法识别按键的过程是:首先,将4个行线作为输出,将其全部置0,4个列线作为输入,将其全部置1,也就是向P1口写入0xF0;假如此时没有人按键,从P1口读出的值应仍为0xF0;假如此时1、4、7、0四个键中有一个键被按下,则P1.6被拉低,从P1口读出的值为0xB0;为了确定是这四个键中哪一个被按下,可将刚才从P1口读出的数的低四位置1后再写入P1口,即将0xBF写入P1口,使P1.6为低,其余均为高,若此时被按下的键是“4”,则P1.1被拉低,从P1口读出的值为0xBE;这样,当只有一个键被按下时,每一个键只有唯一的反转码,事先为12个键的反转码建一个表,通过查表就可知道是哪个键被按下了。

  1. 实验内容

使用扫描法通过矩阵键盘(2行4列,一共八个按键)控制8个LED灯的点亮。按下第一行第一列的按键使LED1点亮,其他LED熄灭;按下第一行第二列的按键使LED2点亮,其他LED熄灭;按下第一行第三列的按键使LED3点亮,其他LED熄灭;按下第一行第四列的按键使LED4点亮,其他LED熄灭;按下第二行第一列的按键使LED5点亮,其他LED熄灭;按下第二行第二列的按键使LED6点亮,其他LED熄灭;按下第二行第三列的按键使LED7点亮,其他LED熄灭;按下第二行第四列的按键使LED8点亮,其他LED熄灭。

图1 LED电路图

图2 按键电路图

注:把拨码开关(DIP)拨到断开的一侧。该矩阵键盘只用到前两行,即2*4的矩阵键盘。

表1 硬件连线表

CPU_CORE_51

MAIN_BOARD

P2:P1.0-P1.7

J14:LINE0-COLUM3

P3:P2.0-P2.7

J48:LED1-LED8

注意:实验箱的AT89S52单片机的晶振频率为11.0592MHz!

  1. 实验过程和结果

①关掉实验电源。将CPU 板插接在JK1、JK2 上,注意CPU 板的插接方向。按照前面连接关系表将硬件连接好。

②将AT89S52 芯片插在CPU 板的CPU 插座上(注意不要插反)。母板上电。

③运行Keil 开发环境,按照“模块化单片机教学实验平台配套的实验指导书1.2.3 节”介绍的方法建立工程exp11.uV2,CPU 为AT89S52,不包含启动文件STARTUP.A51。

④编写汇编语言源程序exp11.asm 完成基本实验的功能。把源程序exp11.asm加入到工程exp11.uV2,并设置工程exp11.uV2 属性,将其晶振频率设置为11.0592MHz,选择输出可执行文件。

⑤构造(Build)工程exp11.uV2。

⑥通过PROGISP 烧写软件,利用ISP 下载线(见“模块化单片机教学实验平台配套的实验指导书1.3 节”)把HEX 文件下载到单片机中。

⑦下载成功后,通过按下不同按键,观察LED1~7 的亮灭。

图3 实验结果图

  1. 实验心得

本次实验需要先判别整个键盘有无按键按下,从第0列开始逐列检测检测,可以检测出哪个按键被按下。然后用到去除按键的抖动。该实验难度较高,相比以往实验更考验综合能力。如何使用扫线法判断所在行是实验的难点所在。实验中因为对扫线法的理解不深入,在实验中没能完成实验。试验后仔细阅读书上的解释和题本提供的案例程序,我知道了自己实验失败的原因所在,并重新设计了程序和实验。通过学习后,对扫描键盘的程序更加了解,将理论上的结果和自己实验做的结果相印证,对书本上知识掌握的更加牢固,对代码程序有更加深刻的理解。在实验中,对模板的使用更加熟练,对电路的连接更加熟练。我对于矩阵键盘的工作方式有了更进一步的认识,也对扫描法查询矩阵键号的方法编写有了更进一步的掌握。单片机提高重在实践,想要学好单片机,软件编程必不可少。

  1. 附录(代码)

(1)基本实验

ORG 0000H

LJMP MAIN

MAIN:MOV P1,#11110000B;给p1口送数11110000

MOV A,P1       ;获取P1口的电平

XRL A,#11110000B

;将P1口电平与11110000异或运算

;若有按键按下,A不为0

JZ MAIN        ;无按键按键则返回

LCALL TIME_    ;跳转到延时程序

MOV P1,#11110000B

MOV A,P1

XRL A,#11110000B   ;该部分操作与上述操作相同

MOV R3,A       ;保存此时A的值

JZ MAIN          ;确认有按键按下

MOV R0,#11110111B;扫描法判断

MOV R1,#0      ;R1存储列的权值

I:    MOV P1,R0      ;将R0值传递给P1

MOV A,P1       ;读取P1的值

AAA0:JNB ACC.4,AAA1

;如果ACC的第四位(即第一列)不为零

MOV R1,#0      ;r1存0

LJMP OK     ;跳转到计算环节

AAA1: JNB ACC.5,AAA2 ;同上,判断第二列

MOV R1,#01

LJMP OK

AAA2:JNB ACC.6,AAA3  ;同上,判断第三列

MOV R1,#02

LJMP OK

AAA3: JNB ACC.7,AAA4 ;同上,判断第四列

MOV R1,#03

LJMP OK

AAA4:MOV A,R0

JNB ACC.2,MAIN ;判断是否结束

RR A        ;环移

MOV R0,A

MOV A,R1

MOV R1,A   

LJMP I

TIME_:MOV R0,#05

TT:   MOV R1,#250

DJNZ R1,$

DJNZ R0,TT

RET

OK:     ;判断所在行并送数

MOV A,R1

ADD A,R0

MOV R0,A

MOV A,#1

INC R0

AAA:CJNE R0,#0,BBB

RL A

INC A

LJMP AAA

BBB:MOV P2,A

LJMP MAIN

END

(2)扩展实验

ORG 0000H

LJMP MAIN

MAIN:MOV P1,#11110000B;送数11110000

MOV A,P1    ;取当前P1的值

XRL A,#11110000B;与11110000与或运算

JZ MAIN     ;如果为0则跳转回

LCALL TIME_ ;延迟子系统

MOV P1,#11110000B

MOV A,P1

XRL A,#11110000B

JZ MAIN     ;再次判断确定非误触

MOV R3,A    ;存储当前A信息

MOV P1,#00001111B  ;判断所在列

MOV A,P1

XRL A,#00001111B

MOV R4,A    ;存至R4

MOV A,R3

JNB ACC.1,NEXT1

MOV R3,#4;若为第二行则若R3存4,否则存0

LJMP NEXT2

NEXT1: MOV R3,#0;判断行,依次为0,1,2,3

NEXT2:MOV A,R4

JNB ACC.4,NEXT3

MOV R4,#0

LJMP NEXT7

NEXT3:JNB ACC.5,NEXT4

MOV R4,#1

LJMP NEXT7

NEXT4:JNB ACC.6,NEXT5

MOV R4,#2

LJMP NEXT7

NEXT5:MOV R4,#3

NEXT7:MOV A,R3

ADD A,R4      ;将两个权值相加

MOV P2,A      ;送至P2

LJMP MAIN

TIME_:MOV R0,#05

TT:   MOV R1,#250

DJNZ R1,$

DJNZ R0,TT

RET

END

2014-04-21 22:30:26 xiaofeige567 阅读数 6915
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏

      设计一个4X4的矩阵键盘,键盘的号码0~15,要求编写出一个键盘输入扫描程序,要求单片机能根据键盘排列顺序,能将按下去键盘号正确识别出来,并采用两个数码管分别键盘号码的个位和十位。

实验参考电路图如下:


参考代码:

#include<reg51.h>   //包含51单片机寄存器定义的头文件
sbit P14=P1^4;      
sbit P15=P1^5;     
sbit P16=P1^6;      
sbit P17=P1^7;      
unsigned char code Tab[ ]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};    //数字0~9的段码
unsigned char keyval;  
 
/**************************************************************
函数功能:数码管动态扫描延时
**************************************************************/
void led_delay(void)     
 {
   unsigned char j;
for(j=0;j<200;j++)
;
  }


/**************************************************************
函数功能:按键值的数码管显示子程序
**************************************************************/
 void display(unsigned char k)
{
   P2=0xbf;            
   P0=Tab[k/10];       
   led_delay();       
   P2=0x7f;            
   P0=Tab[k%10];      
led_delay();         
 }


/**************************************************************
函数功能:软件延时子程序
**************************************************************/
 void delay20ms(void)   
{
   unsigned char i,j;
for(i=0;i<100;i++)
for(j=0;j<60;j++)
           ;
 }




/**************************************************************
函数功能:主函数
**************************************************************/ 
 void main(void)
 {
   EA=1;                  
ET0=1;                          
TMOD=0x01;            
TH0=(65536-500)/256;  
TL0=(65536-500)%256;  
TR0=1;                
keyval=0x00;         
  
while(1)               
{
 display(keyval);  
}


}


/**************************************************************
函数功能:定时器0的中断服务子程序,进行键盘扫描,判断键位
**************************************************************/ 
  void time0_interserve(void) interrupt 1 using 1   
  {
     TR0=0;                 
     P1=0xf0;                
 if((P1&0xf0)!=0xf0)      
    delay20ms();           
 if((P1&0xf0)!=0xf0)      
   {
      P1=0xfe;            
      if(P14==0)       
             keyval=1;           
           if(P15==0)            
             keyval=2;           
           if(P16==0)             
             keyval=3;          
           if(P17==0)           
             keyval=4;           


           P1=0xfd;             
     if(P14==0)       
             keyval=5;         
           if(P15==0)         
             keyval=6;       
           if(P16==0)     
             keyval=7;        
           if(P17==0)    
             keyval=8;  

           P1=0xfb;      
   if(P14==0)     
             keyval=9;   
           if(P15==0)      
             keyval=10;    
           if(P16==0)    
             keyval=11;       
           if(P17==0)        
             keyval=12;   
    
           P1=0xf7;     
   if(P14==0)         
             keyval=13;          
           if(P15==0)           
             keyval=14;         
           if(P16==0)         
             keyval=15;        
           if(P17==0)          
             keyval=16;        
       }
     TR0=1;                   
     TH0=(65536-500)/256;  
TL0=(65536-500)%256;   
 }

修改实验电路图和实验程序和设计电路,改成静态显示


调试后的程序代码:

#include<reg51.h>   //包含51单片机寄存器定义的头文件
sbit P14=P1^4;      
sbit P15=P1^5;     
sbit P16=P1^6;      
sbit P17=P1^7;      
unsigned char code Tab[ ]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};    //数字0~9的段码
unsigned char keyval;  
 
/**************************************************************
函数功能:数码管动态扫描延时
**************************************************************/
void led_delay(void)     
 {
   unsigned char j;
for(j=0;j<200;j++)
;
  }


/**************************************************************
函数功能:按键值的数码管显示子程序
**************************************************************/
 void display(unsigned char k)
{
        
        
   //P2=0x3f;         ///////////////   
P0=Tab[k/10];  
     P3=Tab[k%10];      
    led_delay();         
 }




/**************************************************************
函数功能:软件延时子程序
**************************************************************/
 void delay20ms(void)   
{
   unsigned char i,j;
for(i=0;i<100;i++)
for(j=0;j<60;j++)
           ;
 }




/**************************************************************
函数功能:主函数
**************************************************************/ 
 void main(void)
 {
   EA=1;                  
ET0=1;                          
TMOD=0x01;            
TH0=(65536-500)/256;  
TL0=(65536-500)%256;  
TR0=1;                
keyval=0x00;         
  
while(1)               
{
 display(keyval);  
}


}




/**************************************************************
函数功能:定时器0的中断服务子程序,进行键盘扫描,判断键位
**************************************************************/ 


  void time0_interserve(void) interrupt 1 using 1   
  {
     TR0=0;                 
     P1=0xf0;                
 if((P1&0xf0)!=0xf0)      
    delay20ms();           
 if((P1&0xf0)!=0xf0)      
   {
      P1=0xfe;            
      if(P14==0)       
             keyval=1;           
           if(P15==0)            
             keyval=2;           
           if(P16==0)             
             keyval=3;          
           if(P17==0)           
             keyval=4;           


           P1=0xfd;             
     if(P14==0)       
             keyval=5;         
           if(P15==0)         
             keyval=6;       
           if(P16==0)     
             keyval=7;        
           if(P17==0)    
             keyval=8;  

           P1=0xfb;      
   if(P14==0)     
             keyval=9;   
           if(P15==0)      
             keyval=10;    
           if(P16==0)    
             keyval=11;       
           if(P17==0)        
             keyval=12;       
           P1=0xf7;     
   if(P14==0)         
             keyval=13;          
           if(P15==0)           
             keyval=14;         
           if(P16==0)         
             keyval=15;        
           if(P17==0)          
             keyval=16;        
       }
     TR0=1;                   
     TH0=(65536-500)/256;  
 TL0=(65536-500)%256;   
 }


2007-12-01 10:38:00 xianjiangao 阅读数 1146
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏

实 验 报 告

                                            

专业___软件学院___  班级__4__  学号__123012005158__  

实验日期:     2007    11    12       报告退发 (订正 重做)             

课程       单片机程序设计         实验名称      编码键盘实验             

一、实验目的

掌握编码键盘的原理和使用方法

 

二、实验环境

    PC,51,KC

 

三、实验内容、步骤和结果分析

  编写键盘扫描程序,按下KEY1的时候LED显示1, 按下KEY2的时候LED显示2,……….

程序如下:

       org 0000h

       ajmp main

       org 0013h

       ajmp intr1

main:      mov a,#0ffh

       mov p1,a

       mov ie,#84h

       setb it1

       setb tr0        

        setb et0        

        setb ea

       mov p0,#00h

       mov p1,#0ffh

       ;mov p1,#0fh

       sjmp $

 

intr1:       mov p1,#0fh

       mov a,p1 ;取出p1

       anl a,#0fh       ;屏蔽高四位

       jnb acc.0,k0    ;判断p1.0~p1.4中哪个键被按下

       jnb acc.1,k1

       jnb acc.2,k2

       jnb acc.3,k3

 

 

 

exit: ;setb ea

       reti

k0:   ;ajmp KEY0

       mov r3,#00h   ;0按下

       ajmp setrow    ;跳转到计算行号

k1:   mov r3,#01h   ;1

       ajmp setrow

k2:   mov r3,#02h   ;2

       ajmp setrow

k3:   mov r3,#03h   ;3

       ajmp setrow

 

setrow:   mov p1,#0f0h ;p1重新复制

       mov a,p1

       anl a,#0f0h     ;屏蔽低4

       jnb acc.4,row0       ;计算行号

       jnb acc.5,row1

       jnb acc.6,row2

       jnb acc.7,row3

      

row0:      mov r4,#00h   ;0

       ajmp getr

row1:      mov r4,#01h   ;1

       ajmp getr

row2:      mov r4,#02h

       ajmp getr

row3:      mov r4,#03h

       ajmp getr

 

getr: mov a,#00h    ;计算键值

       mov a,r4

       rl a          ;4倍数计算

       rl a

       add a,r3   ;4*R4+R3

       mov r5,a

       cjne r5,#00h,key1;判断键值

       mov a,#02h    ;0,显示,下同

         mov p2,a

       mov a,#3fh

       mov p0,a

       ajmp exit

key1:      cjne r5,#01h,key2

       mov a,#02h

         mov p2,a

       mov a,#06h

       mov p0,a

       ajmp exit

key2:      cjne r5,#02h,key3

       mov a,#02h

         mov p2,a

       mov a,#5bh

       mov p0,a

       ajmp exit       

key3:      cjne r5,#03h,key4

       mov a,#02h

         mov p2,a

       mov a,#4fh

       mov p0,a

       ajmp exit

key4:      cjne r5,#04h,key5

       mov a,#02h

         mov p2,a

       mov a,#66h

       mov p0,a

       ajmp exit

key5:      cjne r5,#05h,key6

       mov a,#02h

         mov p2,a

       mov a,#6dh

       mov p0,a

       ajmp exit

key6:      cjne r5,#06h,key7

       mov a,#02h

         mov p2,a

       mov a,#7dh

       mov p0,a

       ajmp exit

key7:      cjne r5,#07h,key8

       mov a,#02h

         mov p2,a

       mov a,#07h

       mov p0,a

       ajmp exit

key8:      cjne r5,#08h,key9

       mov a,#02h

         mov p2,a

       mov a,#7fh

       mov p0,a

       ajmp exit

key9:      cjne r5,#09h,key10

       mov a,#02h

         mov p2,a

       mov a,#6fh

       mov p0,a

       ajmp exit

key10:     cjne r5,#0ah,key11

       mov a,#02h

         mov p2,a

       mov a,#77h

       mov p0,a

       ajmp exit

key11:     cjne r5,#0bh,key12

       mov a,#02h

         mov p2,a

       mov a,#7ch

       mov p0,a

       ajmp exit

key12:     cjne r5,#0ch,key13

       mov a,#02h

         mov p2,a

       mov a,#39h

       mov p0,a

       ajmp exit

key13:     cjne r5,#0dh,key14

       mov a,#02h

         mov p2,a

       mov a,#5eh

       mov p0,a

       ajmp exit

key14:     cjne r5,#0eh,key15

       mov a,#02h

         mov p2,a

       mov a,#79h

       mov p0,a

       ajmp exit

key15:    

       mov a,#02h

         mov p2,a

       mov a,#71h

       mov p0,a

       ajmp exit

       end

 

    实验成功,能在51板上通过按键让电子数码管进行显示相应的数字

四、讨论

本次实验主要了解了在51板上的工作原理,在对其电路图进行了一定的了解之后使程序编写显得比较明了.起先实现了每一列可以按键,但是不懂如何进行移位来判断,这个问题思考了很久,后来通过对p0端口赋不同的值,取出各自的数字并进行计算才得以实现.

本实验完成,了解了键盘的外部中断的工作原理.

 

 

 

 

 
2019-03-11 17:17:17 ohVerLord 阅读数 328
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏

基于普中科技的单片机开发实验仪编写的数字表

1、项目简单说明

一、显示日期,对ds1302芯片进行计时所得的日期用数码管进行显示;

二、显示温度,对18B20芯片测量所得的温度用数码管进行显示;

三、进行计时,从零开始进行计时,用定时器中断对秒进行加一操作,数码管显示计时时间;

四、进行倒计时,运用矩阵键盘进行倒计时时间的设置,用定时器中断对秒进行减一操作,数码管显示倒计时时间,时间为零时蜂鸣器响起,响起后需按下相关按键结束;

五、对时间进行设置,运用矩阵键盘进行当前时间的设置,数码管显示设置时间,设置完成后ds1302芯片会从设置时间开始重新计时;

六、对日期进行设置,即对当前日期进行设置。

使用此数字表时,应先对日期进行设置,再对时间进行设置,这样才能得到当前的正确时间。

基本框图如下:
​​在这里插入图片描述
​​​​​​

2、代码编写

main函数
#include<reg52.h>
#include"type.h"
#include"temperature.h"
#include"digital.h"
#include"count.h"
#include"ds1302.h"
#include"key.h"
#include"ring.h"

void main(){

 init_ds1302();          //初始化ds1302
 init_counter();         //初始化定时器1
 
 digital_flag = close;
 EA= 1;                

 while(1){
   if(digital_flag == open){
     function();                    //功能显示
     if(count_up_flag == close)
       main_key_check();            //独立按键检测
    }

   if(ring_flag == open)
     player();                      //蜂鸣器唱歌
   switch_check();                 //数码管显示开关
  }
  
}
1、type
type.h
#ifndef _TYPE_H
#define _TYPE_H

typedef unsigned char uchar;
typedef unsigned int  uint;

#define open  1
#define close 0

void Delay1ms(uint x);         //延时x ms
void delay(uint x);            //延时

#endif
type.c
#include"type.h"

void Delay1ms(uint x){
 uint i, j;
 for(; x > 0; x--)
   for(i = 199; i > 0; i--)
     for(j = 1; j > 0; j--) ;
}

void delay(uint x){
 uint i, j;
 for(i = x; i > 0; --i)
   for(j = 110; j > 0; --j) ;
}
2、temperature
temperature.h
#ifndef _TEMPERATURE_H
#define _TEMPERATURE_H
#include<reg52.h>
#include"type.h"

extern uint temperature;
sbit temp = P3^7;                      //数据发收位

void init_temp();                      //初始化温感芯片
uchar read_temp();                     //读取芯片数据
void write_temp(uchar temp_data);      //对芯片写入命令
void temp2digital();                   //将读取的数据转换为十进制

#endif
temperature.c
#include"temperature.h"
#include"digital.h"

uint temperature = 10;

void init_temp(){      //初始化芯片
 temp = 0;
 delay(1);
 
 temp = 1;
 show_temp();
}

uchar read_temp(){     //读取数据
 uchar temp_byte, temp_bit;
 uint i, j;

 for(i = 0; i < 8; ++i){
   temp = 0;
   j++;
   
   temp = 1;
   j++; j++;

   temp_bit = temp;
   temp_byte = (temp_byte >> 1) | (temp_bit << 7);

   j = 4;
   while(j--);
  }

 return temp_byte;
}

void write_temp(uchar temp_data){     //写入数据
 uint i, j;
 
 for(i = 0; i < 8; ++i){
   temp = 0;
    j++;

   temp = temp_data & 0x01;
   
    j= 6;
   while(j--);
   
   temp = 1;
   temp_data >>= 1;
 } 
 
}

void temp2digital(){               //将获取的温度转化为可用数码管显示的数据
 uchar tempL, tempH;
 uint i = 10;

 init_temp();
 delay(1);

 write_temp(0xcc);
 write_temp(0x44);
 while(i--) show_temp();

 init_temp();
 delay(1);

 write_temp(0xcc);
 write_temp(0xbe);
 
 tempL = read_temp();
 tempH = read_temp();
 
  //将温度的高8位与低8位组合乘以0.0625即为温度值,后面乘以100是为了保留两位小数位, 加上0.5四舍五入
 temperature = ((tempH * 256) + tempL) * 0.0625 * 100 + 0.5;

}
3、digital
digital.h
#ifndef _DIGITAL_H
#define _DIGITAL_H

#include<reg52.h>
#include"type.h"

#define SMG7 P0

sbit LS_A = P2^2;          //数码管位选
sbit LS_B = P2^3;
sbit LS_C = P2^4;

sbit digital_flag = P1^0;  //数码管显示标志

extern uchar time_show[];  //时间显示数组
extern uchar temp_show[];  //温度显示数组
extern uchar time_temp;    //时间暂存
extern bit flash_flag;     //闪烁标志

void get_time_now(uint hour, uint min, uintsec);    //获取当前时间
void get_time_count(uint hour, uint min,uint sec);  //获取计时时间
void get_temp(uint temp);                        //获取显示温度
void flash(uint flash_bit);                      //选定位闪烁

void show_time();                                //显示时间
void show_temp();                                //显示温度
void show_func(uchar show);                      //显示功能序号

#endif
digital.c
#include"digital.h"
#include"count.h"

uchar digital_show[] = {0x3f, 0x06, 0x5b,0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x40, 0x00, 0x39};
                     //  0     1     2     3    4     5     6    7     8     9     -          C

uchar time_show[] = {0, 0, 10, 0, 0, 10, 0,0};    //数码管显示时间数组
uchar temp_show[] = {11, 11, 11, 0, 0, 0,0, 12};  //数码管显示温度数组

bit flash_flag = open;
uchar time_temp = 0;

void get_time_now(uint hour, uint min, uintsec){             //获取现在的时间
 time_show[0] = hour / 16;
 time_show[1] = hour % 16;
 time_show[3] = min / 16;
 time_show[4] = min % 16;
 time_show[6] = sec / 16;
 time_show[7] = sec % 16;
}

void get_time_count(uint hour, uint min,uint sec){           //获取计时的时间
 time_show[0] = hour / 10;
 time_show[1] = hour % 10;
 time_show[3] = min / 10;
 time_show[4] = min % 10;
 time_show[6] = sec / 10;
 time_show[7] = sec % 10;
}

void get_temp(uint temp){                                     //获取温度
 temp_show[3] = temp % 10000 / 1000;
 temp_show[4] = temp % 1000 / 100;
 temp_show[5] = temp % 100 / 10;
 temp_show[6] = temp % 10;
}

void show_time(){                                             //显示时间
 LS_A = 0; LS_B = 0; LS_C = 0;
 SMG7 = digital_show[time_show[7]]; delay(1);

  LS_A= 1; LS_B = 0; LS_C = 0;
 SMG7 = digital_show[time_show[6]]; delay(1);

 LS_A = 0; LS_B = 1; LS_C = 0;
 SMG7 = digital_show[time_show[5]]; delay(1);

 LS_A = 1; LS_B = 1; LS_C = 0;
 SMG7 = digital_show[time_show[4]]; delay(1);

 LS_A = 0; LS_B = 0; LS_C = 1;
 SMG7 = digital_show[time_show[3]]; delay(1);

 LS_A = 1; LS_B = 0; LS_C = 1;
 SMG7 = digital_show[time_show[2]]; delay(1);

 LS_A = 0; LS_B = 1; LS_C = 1;
 SMG7 = digital_show[time_show[1]]; delay(1);

 LS_A = 1; LS_B = 1; LS_C = 1;
 SMG7 = digital_show[time_show[0]]; delay(1);   
}

void show_temp(){                                              //显示温度
 LS_A = 0; LS_B = 0; LS_C = 0;
 SMG7 = digital_show[temp_show[7]]; delay(1);

 LS_A = 1; LS_B = 0; LS_C = 0;
 SMG7 = digital_show[temp_show[6]]; delay(1);

 LS_A = 0; LS_B = 1; LS_C = 0;
 SMG7 = digital_show[temp_show[5]]; delay(1);

 LS_A = 1; LS_B = 1; LS_C = 0;
 SMG7 = digital_show[temp_show[4]] | 0x80; delay(1);

 LS_A = 0; LS_B = 0; LS_C = 1;
 SMG7 = digital_show[temp_show[3]]; delay(1);

 LS_A = 1; LS_B = 0; LS_C = 1;
 SMG7 = digital_show[temp_show[2]]; delay(1);

 LS_A = 0; LS_B = 1; LS_C = 1;
 SMG7 = digital_show[temp_show[1]]; delay(1);

 LS_A = 1; LS_B = 1; LS_C = 1;
 SMG7 = digital_show[temp_show[0]]; delay(1);
}

void show_func(uchar show){                                  //显示功能序号
 LS_A = 0; LS_B = 0; LS_C = 0;
 SMG7 = digital_show[show]; delay(1);
}

void flash(uint flash_bit){                                  //选中位闪烁
 if(flash_flag)
   time_show[flash_bit] = 11;
 else
   time_show[flash_bit] = time_temp;
}
4、count
count.h
#ifndef _COUNT_H
#define _COUNT_H

#include<reg52.h>
#include"type.h"

extern uint hour_now;      //当前时间
extern uint min_now;
extern uint sec_now;

extern uint year_now;
extern uint mon_now;
extern uint day_now;

extern uint hour_count;    //计时时间
extern uint min_count;
extern uint sec_count;

extern bit count_up_flag;           //计时标志
extern bit count_down_flag;         //倒计时标志
extern bit reset_time_flag;

void init_time_now();               //初始化当前时间
void init_day_now();                //初始化当前日期
void init_time_count();             //初始计时时间

void set_time_now(uchar choose_bit, uchartype);      //设置当前时间
void set_day_now(uchar choose_bit, uchartype);       //设置日期
void set_time_count(uchar choose_bit, uchartype);    //设置倒计时时间

void ten2bcd(bit flag);                     //将十进制的时间转换为BCD码

void count_up();     //计时
void count_down();   //倒计时
void init_counter();      //初始化化计时器1

#endif
count.c
#include"count.h"
#include"digital.h"
#include"ring.h"
#include"ds1302.h"

uint hour_now = 0;      //当前时间
uint min_now  = 0;
uint sec_now  = 0;
uint year_now = 0;
uint mon_now  = 0;
uint day_now  = 0;

uint hour_count = 0;    //计时时间
uint min_count  = 0;
uint sec_count  = 0;

uint t1 = 0;
uint t2 = 0;

bit count_up_flag = close;           //计时标志
bit count_down_flag = close;         //倒计时标志
bit reset_time_flag = close;

void init_time_now(){
 hour_now = 0;
 min_now  = 0;
 sec_now  = 0;
}

void init_day_now(){                //初始化当前日期
 year_now = 0;
 mon_now  = 0;
 day_now  = 0;
}

void init_time_count(){
 hour_count = 0;
 min_count  = 0;
 sec_count  = 0;
}

void set_time_now(uchar choose_bit, uchartype){      //设置当前时间
 if(type == '+')
   switch(choose_bit){                    //将数据的个位与十位分离进行操作
     case 0 : hour_now = (hour_now / 10 + 1) % 10 * 10 + hour_now % 10;break;
     case 1 : hour_now = (hour_now % 10 + 1) % 10 + hour_now / 10 * 10;break;
     case 3 : min_now = (min_now / 10 + 1) % 6 * 10 + min_now % 10; break;
     case 4 : min_now = (min_now % 10 + 1) % 10 + min_now / 10 * 10; break;
     case 6 : sec_now = (sec_now / 10 + 1) % 6 * 10 + sec_now % 10; break;
     case 7 : sec_now = (sec_now % 10 + 1) % 10 + sec_now / 10 * 10; break;
    }
 else if(type == '-'){
   if(choose_bit == 0){
     if(hour_now / 10 == 0)
       hour_now += 90;
     else
       hour_now = (hour_now / 10 - 1) * 10 + hour_now % 10;
    }
   else if(choose_bit == 1){
     if(hour_now % 10 == 0)
       hour_now += 9;
     else
       hour_now = (hour_now % 10 - 1) + hour_now / 10 * 10;
    }
   else if(choose_bit == 3){
     if(min_count / 10 == 0)
       min_now += 50;
     else
       min_now = (min_now / 10 - 1) * 10 + min_now % 10;
    }
   else if(choose_bit == 4){
     if(min_now % 10 == 0)
       min_now += 9;
     else
       min_now = (min_now % 10 - 1) + min_now / 10 * 10;
    }
  else if(choose_bit == 6){
     if(sec_now / 10 == 0)
       sec_now += 50;
     else
       sec_now = (sec_now / 10 - 1) * 10 + sec_now % 10;
    }
   else if(choose_bit == 7){
     if(sec_now % 10 == 0)
       sec_now += 9;
     else
       sec_now = (sec_now % 10 - 1) + sec_now / 10 * 10;
    }
  }
}

void set_day_now(uchar choose_bit, uchartype){       //设置日期
 if(type == '+')
   switch(choose_bit){
     case 0 : year_now = (year_now / 10 + 1) % 10 * 10 + year_now % 10;break;
     case 1 : year_now = (year_now % 10 + 1) % 10 + year_now / 10 * 10; break;
     case 3 : mon_now = (mon_now / 10 + 1) % 2 * 10 + mon_now % 10; break;
     case 4 : mon_now = (mon_now % 10 + 1) % 10 + mon_now / 10 * 10; break;
     case 6 : day_now = (day_now / 10 + 1) % 4 * 10 + day_now % 10; break;
     case 7 : day_now = (day_now % 10 + 1) % 10 + day_now / 10 * 10; break;
    }
 else if(type == '-'){
   if(choose_bit == 0){
     if(year_now / 10 == 0)
       year_now += 90;
     else
       year_now = (year_now / 10 - 1) * 10 + year_now % 10;
    }
   else if(choose_bit == 1){
     if(year_now % 10 == 0)
       year_now += 9;
     else
       year_now = (year_now % 10 - 1) + year_now / 10 * 10;
    }
   else if(choose_bit == 3){
     if(mon_now / 10 == 0)
       mon_now += 10;
     else
       mon_now = (mon_now / 10 - 1) * 10 + mon_now % 10;
    }
   else if(choose_bit == 4){
     if(mon_now % 10 == 0)
       mon_now += 9;
     else
       mon_now = (mon_now % 10 - 1) + mon_now / 10 * 10;
    }
   else if(choose_bit == 6){
     if(day_now / 10 == 0)
       day_now += 30;
     else
       day_now = (day_now / 10 - 1) * 10 + day_now % 10;
    }
   else if(choose_bit == 7){
     if(day_now % 10 == 0)
       day_now += 9;
     else
       day_now = (day_now % 10 - 1) + day_now / 10 * 10;
    }
 }  
}

void set_time_count(uchar choose_bit, uchartype){    //设置倒计时时间
 if(type == '+')
   switch(choose_bit){
     case 0 : hour_count = (hour_count / 10 + 1) % 10 * 10 + hour_count % 10;break;
     case 1 : hour_count = (hour_count % 10 + 1) % 10 + hour_count / 10 * 10;break;
     case 3 : min_count = (min_count / 10 + 1) % 6 * 10 + min_count % 10;break;
     case 4 : min_count = (min_count % 10 + 1) % 10 + min_count / 10 * 10;break;
     case 6 : sec_count = (sec_count / 10 + 1) % 6 * 10 + sec_count % 10;break;
     case 7 : sec_count = (sec_count % 10 + 1) % 10 + sec_count / 10 * 10;break;
    }
 else if(type == '-'){
   if(choose_bit == 0){
     if(hour_count / 10 == 0)
       hour_count += 90;
     else
       hour_count = (hour_count / 10 - 1) * 10 + hour_count % 10;
    }
   else if(choose_bit == 1){
     if(hour_count % 10 == 0)
       hour_count += 9;
     else
       hour_count = (hour_count % 10 - 1) + hour_count / 10 * 10;
    }
   else if(choose_bit == 3){
     if(min_count / 10 == 0)
       min_count += 50;
     else
       min_count = (min_count / 10 - 1) * 10 + min_count % 10;
    }
   else if(choose_bit == 4){
     if(min_count % 10 == 0)
       min_count += 9;
     else
       min_count = (min_count % 10 - 1) + min_count / 10 * 10;
    }
   else if(choose_bit == 6){
     if(sec_count / 10 == 0)
       sec_count += 50;
     else
       sec_count = (sec_count / 10 - 1) * 10 + sec_count % 10;
    }
   else if(choose_bit == 7){
     if(sec_count % 10 == 0)
       sec_count += 9;
     else
        sec_count = (sec_count % 10 - 1) +sec_count / 10 * 10;
    }
  }
}

void ten2bcd(bit flag){                     //将十进制的时间转换为BCD码
 if(flag == 1){
   time[0] = sec_now / 10 * 16 + sec_now % 10;
   time[1] = min_now / 10 * 16 + min_now % 10;
   time[2] = hour_now / 10 * 16 + hour_now % 10;
  }
  
 if(flag == 0){
   time[3] = day_now / 10 * 16 + day_now % 10;
   time[4] = mon_now / 10 * 16 + mon_now % 10;
   time[6] = year_now / 10 * 16 + year_now % 10;
  }
}

void count_up(){                     //计时
 if(count_up_flag == open){
    if(sec_count < 60)
       sec_count++;
    else{
       if(min_count < 60)
         min_count++;
       else{
         if(hour_count < 24)
           hour_count++;
         else
           hour_count = 0;
         min_count = 0;
       }
       sec_count = 0;
    }
  }
}

void count_down(){                   //倒计时
 if(count_down_flag == open){
   if(sec_count == 0){
     if(min_count == 0){
       if(hour_count == 0){
         ring_flag = open;             //倒计时结束,蜂鸣器响
       }  
       else{
         hour_count--;
         min_count = 59;
       } 
     }
     else{
       min_count--;
       sec_count = 59;
     }
    }
   else
     sec_count--;
  }
}

void init_counter(){              //初始化定时器1
 TMOD &= 0xf0;
 TMOD |= 0x01;
 
  TH0= 0xd8;
  TL0= 0xf0;
  
  TR0= 1;
  TF0= 0;
}

void ISR_time0() interrupt 1
{
  TH0= 0xd8;
  TL0= 0xf0;

 t1++;
 t2++;

 if(t1 == 40){
   t1 = 0;
   
   if(count_down_flag == close && count_up_flag == close &&reset_time_flag == close)
     flash_flag = ~flash_flag;
  }

 if(t2 == 100){
   t2 = 0;
   
   if(count_down_flag == open){
     count_down();

     get_time_count(hour_count, min_count, sec_count);
    }

   if(count_up_flag == open){
     count_up();

     get_time_count(hour_count, min_count, sec_count);
    }
  }
}
5、ds1302
ds1302.h
#ifndef _DS1302_H
#define _DS1302_H

#include<reg52.h>
#include"type.h"

extern uchar time[];

sbit DSIO = P3^4;                    //数据发收位
sbit RST = P3^5;                    //CE位
sbit SCLK = P3^6;                    //时钟位

void init_ds1302();                  //初始化ds1302

void write_ds1302(uchar temp);       //写入一个数据
void write_data(uchar address, uchardat);   //对ds1302进行写操作
uchar read_data(uchar address);              //对ds1302进行读操作
void read_time();                    //读取当前时间

#endif
ds1302.c
#include"ds1302.h"
#include<intrins.h>

uchar write_address[] = {0x80, 0x82, 0x84,0x86, 0x88, 0x8a, 0x8c};
uchar read_address[]  = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
uchar time[] = {0x00, 0x00, 0x00, 0x03,0x01, 0x01, 0x17};

void init_ds1302(){
 uchar i;
 
 write_data(0x8e, 0x00);
 for(i = 0; i < 7; i++)
   write_data(write_address[i], time[i]);
   
 write_data(0x8e, 0x80);
}

void write_ds1302(uchar temp){
 uchar i;

 for(i = 0; i < 8; i++){         //将8位数据一位一位的传输
   DSIO = temp & 0x01;
   temp >>= 1;
   
   SCLK = 1;
   _nop_();
   
   SCLK = 0;
   _nop_();
  }
}

void write_data(uchar address, uchar dat){
  RST= 0;
 _nop_();

 SCLK = 0;
 _nop_();

  RST= 1;
 _nop_();

 write_ds1302(address);
 write_ds1302(dat);

  RST= 0;
 _nop_();
}

uchar read_data(uchar address){
 uchar i, time, temp;

  RST= 0;
 _nop_();

 SCLK = 0;
 _nop_();

  RST= 1;
 _nop_();

 write_ds1302(address);
 _nop_();

 for(i = 0; i < 8; i++){              //将8位数据一位一位的接收
   temp = DSIO;
   time = (time >> 1) | (temp << 7);
   
   SCLK = 1;
   _nop_();

   SCLK = 0;
   _nop_();
  }

  RST= 0;
 _nop_();

 SCLK = 1;
 _nop_();

 DSIO = 0;
 _nop_();

 DSIO = 1;
 _nop_();

 return time;
}

void read_time(){
 uchar i;
 
 for(i = 0; i < 7; i++)
   time[i] = read_data(read_address[i]);
}
6、key
key.h
#ifndef _KEY_H
#define _KEY_H

#include<reg52.h>
#include"type.h"

extern uchar choose_bit;         //闪烁位
extern uchar choose_func;        //选择功能序号
extern bit func_flag;            //进入选择功能的标志
extern bit choose_func_flag;     //确认选择功能的标志

sbit hang1 = P1^7;            //部分矩阵键盘
sbit hang2 = P1^6;

sbit lie1 = P1^3;
sbit lie2 = P1^2;
sbit lie3 = P1^1;

sbit K1 = P3^1;               //独立按键
sbit K2 = P3^0;
sbit K3 = P3^2;
sbit K4 = P3^3;

void main_key_check();     //主要键盘检测

void function();      //功能

void function0();     //显示时间
void function1();     //显示日期
void function2();     //显示温度

void function3();     //计时
void function4();     //倒计时

void function5();     //设置时间
void function6();     //设置日期

void assi_key_check();     //辅助键盘检测

void move_left();     //左移
void move_right();    //右移

void add_bit();       //加
void dec_bit();       //减

void one_key_check();      //蜂鸣器关闭按键检测
void switch_check();       //开关检测

#endif
key.c
#include"key.h"
#include"temperature.h"
#include"digital.h"
#include"count.h"
#include"ds1302.h"
#include"ring.h"

uchar choose_bit = 0;
uchar choose_func = 1;

bit func_flag = close;
bit choose_func_flag = close;
bit init_flag = close;

void main_key_check(){     //主要键盘检测
 if(!K2){
   Delay1ms(1);
   if(!K2){
     while(!K2)  function();
     
     if(choose_func_flag == close){
       if(func_flag == close)
         func_flag = open;
       else
         func_flag = close;
     }
    }
  }

 if(!K3){
   Delay1ms(1);
   if(!K3){
     while(!K3)  function();
     
     if(func_flag == open && choose_func_flag == close){
       choose_func++;
       if(choose_func > 6)
         choose_func = 1;
     }     
    }
  }

 if(!K4){
   Delay1ms(1);
   if(!K4){
     while(!K4)  function();
     
     if(func_flag == open){
       if(choose_func_flag == close){
         choose_func_flag = open;
       }
       else{
         choose_func_flag = close;
         init_flag = close;
         reset_time_flag = close;

         time_temp = time_show[choose_bit];
         
         choose_bit = 0;
         ET0 = 0;
       }
      }
    }
  }
}

void function(){                 //功能
 if(func_flag == close)
   function0();

 if(func_flag == open){
   if(choose_func_flag == close)
     show_func(choose_func);
     
   if(choose_func_flag == open)
     switch(choose_func){
       case 1 : function1(); break;
       case 2 : function2(); break;
       case 3 : function3(); break;
       case 4 : function4(); break;
       case 5 : function5(); break;
       case 6 : function6(); break;
     }
  }
}

void function0(){     //显示时间
 read_time();
 get_time_now(time[2], time[1], time[0]);
 show_time();
}

void function1(){     //显示日期
 read_time();
 get_time_now(time[6], time[4], time[3]);
 show_time();
}

void function2(){     //显示温度
 RST= 1;
 
 temp2digital();
 get_temp(temperature);
 show_temp();
}

void function3(){     //计时
 if(init_flag == close){
   init_time_count();
   get_time_count(hour_count, min_count, sec_count);
   init_flag = open;
  }

 assi_key_check();
 show_time();
}

void function4(){     //倒计时
 if(init_flag == close){
   init_time_count();
   get_time_count(hour_count, min_count, sec_count);
   init_flag = open;
  }

 if(count_down_flag == close)
   flash(choose_bit);

 if(ring_flag == close){
   assi_key_check();
   show_time();
  }
}

void function5(){     //设置时间
 if(init_flag == close){
   init_time_count();
   get_time_count(hour_count, min_count, sec_count);
   init_flag = open;
  }

 if(count_down_flag == close)
   flash(choose_bit);

 assi_key_check();
 show_time();
}

void function6(){     //设置日期
 if(init_flag == close){
   init_time_count();
   get_time_count(hour_count, min_count, sec_count);
   init_flag = open;
  }

 if(count_down_flag == close)
   flash(choose_bit);

 assi_key_check();
 show_time();
}

void assi_key_check(){     //辅助键盘检测
 if(choose_func == 3){
   hang1 = 0;

   if(hang1 == 0 && count_up_flag == close)
     if(!lie3){
       delay(1);
       if(!lie3){
         while(!lie3)  show_time();
         count_up_flag = open;
         
         ET0 = 1;
         get_time_count(hour_count, min_count, sec_count);      
       }
     }

   hang1 = 1;
   hang2 = 0;

   if(hang2 == 0 && count_up_flag == open){
     if(!lie3){
       delay(1);
       if(!lie3){
         while(!lie3)  show_time();
         count_up_flag = close;

         ET0 = 0;           
       }
     }
    }
   hang2 = 1;
  }

 if(choose_func == 4){
   ET0 = 1;
   hang1 = 0;

   if(hang1 == 0 && count_down_flag == close){
     if(!lie1){
       delay(1);
       if(!lie1){
         while(!lie1)  show_time();
         move_left(); 
       }
     }

     if(!lie2){
       delay(1);
       if(!lie2){
         while(!lie2)  show_time();
         move_right();
       }
     }

     if(!lie3){
       delay(1);
       if(!lie3){
         while(!lie3)  show_time();
         count_down_flag = open;
         get_time_count(hour_count, min_count, sec_count);

         ET0 = 0;
         ET0 = 1;       
       }
     }
    }

   hang1 = 1;
   hang2 = 0;

   if(hang2 == 0){
     if(!lie1 && count_down_flag == close){
       delay(1);
       if(!lie1){
         while(!lie1)  show_time();
         add_bit(); 
       }
     }

     if(!lie2 && count_down_flag == close){
       delay(1);
       if(!lie2){
         while(!lie2)  show_time();
         dec_bit();
       }
     }

     if(!lie3 && count_down_flag == open){
       delay(1);
       if(!lie3){
         while(!lie3)  show_time();
         
         count_down_flag = close;
         get_time_count(hour_count, min_count,sec_count);
         time_temp = time_show[choose_bit];

         ET0 = 0;           
       }
     }
    }
   hang2 = 1;
  }

 if(choose_func == 5 || choose_func == 6){
   ET0 = 1;
   hang1 = 0;

   if(hang1 == 0){
     if(!lie1){
       delay(1);
       if(!lie1){
         while(!lie1)  show_time();
         move_left(); 
       }
     }

     if(!lie2){
       delay(1);
       if(!lie2){
         while(!lie2)  show_time();
         move_right();
       }
     }

     if(!lie3){
       delay(1);
       if(!lie3){
         while(!lie3)  show_time();
         if(choose_func == 5)
           ten2bcd(1);
         else
           ten2bcd(0);

         init_ds1302();
         reset_time_flag = open;

         ET0 = 0;       
       }
     }
    }

   hang1 = 1;
   hang2 = 0;

   if(hang2 == 0){
     if(!lie1){
       delay(1);
       if(!lie1){
         while(!lie1)  show_time();
         add_bit(); 
       }
     }

     if(!lie2){
       delay(1);
       if(!lie2){
         while(!lie2)  show_time();
         dec_bit();
       }
     }

     if(!lie3){
       delay(1);
       if(!lie3){
         while(!lie3)  show_time();
         if(choose_func == 5){
           init_time_now();
           get_time_count(hour_now, min_now, sec_now);
         }
         else{
           init_day_now();
           get_time_count(year_now, mon_now, day_now);
         }
         time_temp = time_show[choose_bit];
         reset_time_flag = close;

         ET0 = 1;          
       }
     }
    }
   hang2 = 1;
 } 
}

void move_left(){     //左移
 time_show[choose_bit] = time_temp;
 
 if(choose_bit == 0)
   choose_bit = 7;
 else{
   choose_bit--;
   if(choose_bit == 2 || choose_bit == 5)
     choose_bit--;
  }
 time_temp = time_show[choose_bit];
}

void move_right(){    //右移
 time_show[choose_bit] = time_temp;

 choose_bit++;
 if(choose_bit > 7)
   choose_bit = 0;
   
 if(choose_bit == 2 || choose_bit == 5)
   choose_bit++;
   
 time_temp = time_show[choose_bit];
}

void add_bit(){       //加
 if(choose_func == 4){
   set_time_count(choose_bit, '+');
   get_time_count(hour_count, min_count, sec_count);
  }

 if(choose_func == 5){
   set_time_now(choose_bit, '+');
   get_time_count(hour_now, min_now, sec_now);
  }

 if(choose_func == 6){
   set_day_now(choose_bit, '+');
   get_time_count(year_now, mon_now, day_now);
  }
 time_temp = time_show[choose_bit];
}

void dec_bit(){       //减
 if(choose_func == 4){
   set_time_count(choose_bit, '-');
   get_time_count(hour_count, min_count, sec_count);
  }

 if(choose_func == 5){
   set_time_now(choose_bit, '-');
   get_time_count(hour_now, min_now, sec_now);
  }

 if(choose_func == 6){
   set_day_now(choose_bit, '-');
   get_time_count(year_now,mon_now, day_now);
  }
 time_temp = time_show[choose_bit];
}

void one_key_check(){      //检测一个按键
 hang2 = 0;

 if(!lie3){
   delay(1);
   if(!lie3){
      while(!lie3) ;
      ring_flag = close;
    }
  }
}

void switch_check(){          //数码管显示开关
 if(!K1){
 Delay1ms(1);

 if(!K1){
   while(!K1)  function();
   if(digital_flag == close)
     digital_flag = open;
   else
     digital_flag = close;
    }
  }
}
7、ring
ring.h
#ifndef _RING_H
#define _RING_H

#include<reg52.h>
#include"type.h"

sbit beep = P1^5;
extern bit ring_flag;     //蜂鸣器标志

void init_player();      //初始化定时器2
void player();           //播放音乐

#endif
ring.c
#include"ring.h"
#include"count.h"
#include"digital.h"
#include"key.h"

uchar code music[] = {0xfe, 0x2a, 0x7f,0xfe, 0x2a, 0x7f, 0xfe, 0x2a, 0xff,
                      0xfd, 0x81, 0xff, 0xfe,0x84, 0x7f, 0xfe, 0x84, 0x7f,
                      0xfe, 0x84, 0xff, 0xfe,0x2a, 0xff, 0xfe, 0x2a, 0x7f,
                      0xfe, 0x84, 0x7f, 0xfe,0xc0, 0xff, 0xfe, 0xc0, 0xff,
                      0xfe, 0x99, 0x7f, 0xfe,0x84, 0x7f, 0xfe, 0x55, 0xff,
                      0xff, 0xff, 0xff, 0xfe,0x55, 0x7f, 0xfe, 0x84, 0x7f,
                      0xfe, 0x99, 0xff, 0xfe,0x99, 0xff, 0xfe, 0x84, 0x7f,
                      0xfe, 0x55, 0x7f, 0xfe, 0x84, 0xff,0xfe, 0x2a, 0xff,
                      0xfe, 0x84, 0x7f, 0xfe,0x84, 0x7f, 0xfe, 0x55, 0xff,
                      0xfd, 0x81, 0xff, 0xfe,0x05, 0x7f, 0xfe, 0x55, 0x7f,
                      0xfe, 0x2a, 0xff, 0xff,0xff, 0xff, 0x00};       //新年好

uchar high, low;
bit ring_flag = close;

void init_player(){      //初始化定时器2
 TMOD &= 0x0f;
 TMOD |= 0x10;
 
  TH1= high;
  TL1= low;

  TF1= 0;
  ET1= 1;
}

void player(){           //播放音乐
 uchar time, i = 0;

 init_player();

 while(count_down_flag == open && ring_flag == open){
   digital_flag = close;
   if(music[i] != 0xff && music[i] != 0x00){
     TR1 = 0;
     beep = 1;
     Delay1ms(5);
     
     TR1 = 1;
     high = music[i];
     low  = music[i + 1];
     
     time = music[i + 2];
     Delay1ms(time - 10);
     
     i += 3;
    }
   else if(music[i] == 0xff){
     time = music[i + 2];
     Delay1ms(time - 10);
     
     i += 3;
    }
   else if(music[i] == 0x00){
     TR1 = 0;
     beep = 1;
     Delay1ms(150);

     i = 0;
    }
   one_key_check();
  }
 digital_flag = open;
 count_down_flag = close;
 time_temp = 0;
 
  ET1= 0;
}

void ISR_time1() interrupt 3
{
  TH1= high;
  TL1= low;

 beep = ~beep;
}

因为调用了多个模块,所以编写了一段时间,从一个一个模块出发,一块一块进行编写、调试,最后结合起来调试运行,总体运行良好,各模块都正常运行。编写过程虽有遇到一些难题,但通过部分注释进行调试找到了问题的根源,解决了问题,受益颇丰。

2018-02-21 10:01:34 plm199513100 阅读数 906
  • 51单片机综合小项目-第2季第4部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第2季第4个课程,也是51单片机学完之后的一个综合小项目,该项目运用了开发板上大多数外设设备,并将之结合起来实现了一个时间、温度显示以及报警功能、时间调整功能等单片机控制常见的功能,有一定代码量,需要一定调试技巧和编程能力来完成,对大家是个很好的总结和锻炼,并且能拓展项目经验。

    3415 人正在学习 去看看 朱有鹏

/*
名称:51单片机之按键实验
说明:键盘是计算机最基础、最重要的输入设备之一。对于键盘来说,其工作任务大体可以分为以下三项:
(1)、按键识别。即判断有无按键按下。
(2)、求键值。判断哪个键被按下。
(3)、执行相应的操作。
在这里,实验所用到的键盘为独立键盘和矩阵键盘。

对于独立键盘,它的每个按键需要占用一个IO口。一般来说,按键一端接地,另一端接IO口。当按键按下时,线路被导通,IO口被拉低,即状态为‘0’。所以在使用是我们一般把对应IO口置成高电平,然后不断检测此IO口是否被拉低,从而判断按键是否按下。
对于矩阵键盘来说,它用较少的IO口完成较多个按键的功能。但软件设计的复杂度相应增加些。一般来说,矩阵键盘是由多个行线和列线交叉在一起组成,每个单独的键盘仍是独立键盘。由于每个按键的两段都不接地,所以使用时需要人为的将对应的IO口置低。具体来说,是使用扫描的方式,先固定一行或者一列的按键公共端为低,然后在按列检测每一个按键的另一端。如此往复,直到完成整个键盘的扫描。

The last but not least, 对于按键实验来说,消抖一般来说是避免不了的。对于机械按键,在一次按下按键的过程中,会产生前沿抖动(按下)和后沿抖动(释放)。在具体使用时,一般有两种方式可以消抖,一个是硬件电路进行消抖,另一个则是使用软件消抖。在本实验中使用的软件消抖的方式。

软件消抖:说白了就是延时一段时间(一般为5-10ms),看是否确实还是原来的电平。一般来说,没有经过硬件消抖的情况下,最好都进行软件消抖。(虽然对于某些具体应用来说,不进行软件消抖也能达到相同的效果,如本实验中矩阵键盘实验,不涉及到对同一个数字的连续操作,所以不消抖也是可以的。但是独立按键实验则必须要进行消抖,否则num会变化的不稳定)。

哦,还有一点,对于51单片机IO口来说,复位之后IO默认输出的都是高电平。举个P0的例子说明问题,P0在复位之后输出的是FF。如果在程序中不进行主动赋值(即P0不出现在=的左边),那么P0口将一直保持高电平。即使在过程中被某些电路拉成低电平,之后P0也会被自动拉回高电平。这就解释了独立按键实验中,后沿消抖用的是while(keyboard1 != 0xFF) ; 对于具体的原因,我也不是很清楚,大概和IO口内部的逻辑电路有关。当然,如果在程序中把对应端口进行人为的赋值了,那么那将保持赋值后的电平了。

*/

#include <reg52.h>


#define keyboard P0
#define digitaltube P2      
#define keyboard1  P1

#define uchar unsigned char


//共阳极段码(a在低位,dp在高位)
uchar code _data1[16] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,
                                                0x83,0xC6,0xA1,0x86,0x8E
                                                };                                              

//延时函数
void delay_ms(unsigned int n)
{
    unsigned int i=0,j=0;
    for(i=0;i<n;i++)
        for(j=0;j<123;j++);
}


//一位数码管显示数字
void DisplayNum(char num)
{

        digitaltube = _data1[num];
}


//消除抖动,判断按键是否按下
int Debounce()
{
    uchar temp = keyboard1;
    int res = -1;                       //初始化

    delay_ms(10);                       //延时10ms
    if(temp == keyboard1)
        res = 0;

    return res;                 //返回结果
}


//独立按键实验:通过两个独立按键实现数字加1减1,然后用数码管显示
void IndButton()
{
    char num = 0;
    while(1)
    {
        if(Debounce() >= 0)                 //通过软件消抖判断是否按下按键
        {
                switch(keyboard1)
                {
                    case 0xFE:          //+1按键
                            ++num;
                        if(10 == num)
                            num = 0;


                    break;
                    case 0xEF:          //-1按键

                            --num;
                        if(-1 == num)
                            num = 9;

                    break;
                }


                while(keyboard1 != 0xFF)    ;               //等待按键释放

        }


        DisplayNum(num);        //数码管显示数字
    }
}



//矩阵键盘扫描
int KeyScan()
{
    uchar i = 0,temp = 0,temp1 = 0;
    uchar res = 0;              //返回最终的结果

    for(i = 0;i < 4;++i)
    {   
        //选定行,即对应行输出低电平
        if(0 == i)
            temp = 0x80;                        
            //temp = 0x40;
        else
            temp = temp>>1;


        temp1 = (~temp)&0x0F;      //保留低四位,用作判断列  

        keyboard = ~temp;        //选中第i行  


        if(temp1 !=(keyboard & 0x0F))       //判断是否按下按键,比较判断列
        {
            delay_ms(10);                       //消除前沿抖动

            if(temp1 != keyboard & 0x0F)
            {
                //判断是哪一列
                    switch(keyboard & 0x0F)
                    {
                        case 0x07:
                            res = i*4+0;                    //计算返回结果,i行0列

                        while(temp1 != 0x0F)            //消除后沿抖动
                        {
                            temp1 = keyboard & 0x0F;
                        }

                            break;
                        case 0x0B:
                            res = i*4+1;

                        while(temp1 != 0x0F)            //消除后沿抖动
                        {
                            temp1 = keyboard & 0x0F;
                        }

                            break;
                        case 0x0D:
                            res = i*4+2;

                        while(temp1 != 0x0F)            //消除后沿抖动
                        {
                            temp1 = keyboard & 0x0F;
                        }

                            break;
                        case 0x0E:
                            res = i*4+3;

                        while(temp1 != 0x0F)            //消除后沿抖动
                        {
                            temp1 = keyboard & 0x0F;
                        }

                            break;      


                    }

                    return res;

            }

        }

    }

    return res;

}

//矩阵键盘实验:4*4的矩阵,数码管显示所按的按键键值
void MatrixButton()
{

    uchar res = 0;
    while(1)
    {

        res = KeyScan();
        DisplayNum(res);

    }


}

int main()
{

//      IndButton();

//      MatrixButton();

        while(1)
        {
            P0 = keyboard1;
        }



    return 0;
}

单片机实验8

阅读数 294

没有更多推荐了,返回首页