【【51单片机 --秒表--定时器扫描按键数码管】】

轻松做秒表,谁用谁知道

【【51单片机 --秒表--定时器扫描按键数码管】】_第1张图片
我们在Key 和Nixie 内部都写一个函数这个是main 中中断函数的调用
因为中断是有优先级的,假设有多个中断,那么总是优先级高的在进行,如果我们安排多个中断的话,整体设计就会变得很麻烦
我们放在一个中断里,设置相应的时间,时间到了中断去调用这些操作
中断这个东西就是我们定时器一旦启动就不会停下来,在完成我们定时器指定的周期之后进入中断时间

我们按键被按下之后其实会有一个抖动 所以我们有两种方法
第一种就是当系统读取到第一个下降沿然后延迟 进入while循环 但是这样做太浪费了
第二种我们在按钮按下之后不管直接延迟直接读取
是不是第二种更加方便好用

优化完成之后的key.c

#include 
#include"Delay.h"
//获取独立按键键码
//无参数
//返回值为按下的那个按键

unsigned char Key_KeyNumber;


unsigned char Key(void)
{
    //在这个我们需要返回之后清零的操作
    unsigned char Temp=0;
    Temp=Key_KeyNumber;
    Key_Number=0;
    return Temp;
}


unsigned char key_GetState()
{
    unsigned char keynumber=0;
      if(P3_1==0) { keynumber=1;}
        if(P3_0==0) { keynumber=2;}
        if(P3_2==0) { keynumber=3;}
        if(P3_3==0) { keynumber=4;}
    
    return keynumber;
}


void Key_Loop(void)
{
    static unsigned char NowState,LastState;
    LastState=NowState;
    NowState=Key_GetState();
    if(LastState==1 && NowState==0)
        //因为我们是在定时器用 定时器每隔固定的时间循环读取我们的值
    //我们上面的Key_Getstate就是判断状态一瞬间是否按下 然后再这里去处理
    {
        Key_KeyNumber=1;    
    }
    if(LastState==2 && NowState==0)
    {
        Key_KeyNumber=2;
    }
    if(LastState==3 && NowState==0)
    {
        Key_KeyNumber=3;
    }
    if(LastState==4 && NowState==0)
    {
        Key_KeyNumber=4;
    }
    
}

Nixie 的实现

#include 
#include "Delay.h"    //包含Delay头文件


//显示缓存区
unsigned char Nixie_Buf[9]={0,10,10,10,10,10,10,10,10};
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};





void Nixie_SetBuf(unsigned char Location,Number)
{
    Nixie_Buf[Location]=Number;
    
}




//数码管段码表


//数码管显示子函数
void Nixie_Scan(unsigned char Location,Number)
{
    P0=0x00;                //段码清0,消影
    
    switch(Location)        //位码输出
    {
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        case 3:P2_4=1;P2_3=0;P2_2=1;break;
        case 4:P2_4=1;P2_3=0;P2_2=0;break;
        case 5:P2_4=0;P2_3=1;P2_2=1;break;
        case 6:P2_4=0;P2_3=1;P2_2=0;break;
        case 7:P2_4=0;P2_3=0;P2_2=1;break;
        case 8:P2_4=0;P2_3=0;P2_2=0;break;
    }
    P0=NixieTable[Number];    //段码输出
    ///为什么这样 ,因为我们自己外部选择这个的时候自带了delay
    //每次进入前先清零 然后位选段选
    
}




    
    
void Nixie_Loop(void)
{
    static unsigned char i=1;
    Nixie_Scan(i,Nixie_Buf[i]);
    i++;
    if(i>=9){i=1;}
}
    

//现在还是处理秒表的使用
现在实现的main.c
#include 
#include"Timer0.h"
#include"Key.h"
#include"Nixie.h"
#include"delay.h"

unsigned char KeyNum;
unsigned char Min,Sec,MiniSec;
unsigned char RunFlag;

void main()
{
    Timer0_Init();
    while(1)
    {
        
        KeyNum=Key();
        if(KeyNum==1)
        {
            RunFlag=!RunFlag;
        }    
        if(KeyNum==2)
        {
            Min=0;
            Sec=0;
            MiniSec=0;
        }
        
        
        
        
        Nixie_SetBuf(1,Min/10);
            Nixie_SetBuf(2,Min%10);
            Nixie_SetBuf(3,11);
            Nixie_SetBuf(4,Sec/10);
            Nixie_SetBuf(5,Sec%10);
            Nixie_SetBuf(6,11);
            Nixie_SetBuf(7,MiniSec/10);
            Nixie_SetBuf(8,MiniSec%10);
        
        
    }    
    
}
void Sec_Loop(void)
{
    if(RunFlag)
    {
        
    MiniSec++;
    if(MiniSec>=100)
    {
        MiniSec=0;
        Sec++;
        if(Sec>=60)
        {
            Sec=0;
            Min++;
             if(Min>=60)
             {
                Min=0; 
                 
                 
             }
            
            
        }
        
        
        
    }
    
    
}
    
    
    
    
}










void Timer0_Routine() interrupt 1
{
    static unsigned int T0Count1,T0Count2,T0Count3;
    TL0 = 0x18;        //设置定时初值
    TH0 = 0xFC;        //设置定时初值
    T0Count1++;
    if(T0Count1>=20)
    {
        T0Count1=0;
        Key_Loop();
    }
    
    T0Count2++;
    if(T0Count2>=2)
    {
        T0Count2=0;
        Nixie_Loop();
    }
    
    T0Count3++;
    if(T0Count3>=10)
    {
        T0Count3=0;
        Sec_Loop();
    }
    
    
    
    
}

//现在我们加入AT24C02和I2C
把信息存进去

下面更新全部代码

main.c

#include 
#include"Timer0.h"
#include"Key.h"
#include"Nixie.h"
#include"delay.h"
#include"AT24C02.h"



unsigned char KeyNum;
unsigned char Min,Sec,MiniSec;
unsigned char RunFlag;

void main()
{
	Timer0_Init();
	while(1)
	{
		
		KeyNum=Key();
		if(KeyNum==1)
		{
			RunFlag=!RunFlag;
		}	
		if(KeyNum==2)
		{
			Min=0;
			Sec=0;
			MiniSec=0;
		}
		
		//加入AT24C02用来存储数据
		if(KeyNum==3)
		{
			AT24C02_WriteByte(0,Min);
			Delay(5);
			AT24C02_WriteByte(1,Sec);
			Delay(5);
			AT24C02_WriteByte(2,MiniSec);
			Delay(5);
		}
		
		if(KeyNum==4)
		{
			Min=AT24C02_ReadByte(0);
			Sec=AT24C02_ReadByte(1);
			MiniSec=AT24C02_ReadByte(2);	
		}
		Nixie_SetBuf(1,Min/10);
			Nixie_SetBuf(2,Min%10);
			Nixie_SetBuf(3,11);
			Nixie_SetBuf(4,Sec/10);
			Nixie_SetBuf(5,Sec%10);
			Nixie_SetBuf(6,11);
			Nixie_SetBuf(7,MiniSec/10);
			Nixie_SetBuf(8,MiniSec%10);
		
		
	}	
	
}
void Sec_Loop(void)
{
	if(RunFlag)
	{
		
	MiniSec++;
	if(MiniSec>=100)
	{
		MiniSec=0;
		Sec++;
		if(Sec>=60)
		{
			Sec=0;
			Min++;
			 if(Min>=60)
			 {
				Min=0; 
				 
				 
			 }
			
			
		}
		
		
		
	}
	
	
}

}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count1,T0Count2,T0Count3;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count1++;
	if(T0Count1>=20)
	{
		T0Count1=0;
		Key_Loop();
	}
	
	T0Count2++;
	if(T0Count2>=2)
	{
		T0Count2=0;
		Nixie_Loop();
	}
	
	T0Count3++;
	if(T0Count3>=10)
	{
		T0Count3=0;
		Sec_Loop();
	}
	
	
	
	
}

delay.c

void Delay(unsigned int xms)		//@12.000MHz
{
	while(xms)
	{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	xms--;
}
}

key.c

#include 
#include "Delay.h"

unsigned char Key_KeyNumber;

/**
  * @brief  获取按键键码
  * @param  无
  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
  */
unsigned char Key(void)
{
	unsigned char Temp=0;
	Temp=Key_KeyNumber;
	Key_KeyNumber=0;
	return Temp;
}

/**
  * @brief  获取当前按键的状态,无消抖及松手检测
  * @param  无
  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
  */
unsigned char Key_GetState()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){KeyNumber=1;}
	if(P3_0==0){KeyNumber=2;}
	if(P3_2==0){KeyNumber=3;}
	if(P3_3==0){KeyNumber=4;}
	
	return KeyNumber;
}

/**
  * @brief  按键驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Key_Loop(void)
{
	static unsigned char NowState,LastState;
	LastState=NowState;				//按键状态更新
	NowState=Key_GetState();		//获取当前按键状态
	//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测
	if(LastState==1 && NowState==0)
	{
		Key_KeyNumber=1;
	}
	if(LastState==2 && NowState==0)
	{
		Key_KeyNumber=2;
	}
	if(LastState==3 && NowState==0)
	{
		Key_KeyNumber=3;
	}
	if(LastState==4 && NowState==0)
	{
		Key_KeyNumber=4;
	}
}

Nixie.c

#include 
#include "Delay.h"

//数码管显示缓存区
unsigned char Nixie_Buf[9]={0,10,10,10,10,10,10,10,10};

//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};

/**
  * @brief  设置显示缓存区
  * @param  Location 要设置的位置,范围:1~8
  * @param  Number 要设置的数字,范围:段码表索引范围
  * @retval 无
  */
void Nixie_SetBuf(unsigned char Location,Number)
{
	Nixie_Buf[Location]=Number;
}

/**
  * @brief  数码管扫描显示
  * @param  Location 要显示的位置,范围:1~8
  * @param  Number 要显示的数字,范围:段码表索引范围
  * @retval 无
  */
void Nixie_Scan(unsigned char Location,Number)
{
	P0=0x00;				//段码清0,消影
	switch(Location)		//位码输出
	{
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		case 3:P2_4=1;P2_3=0;P2_2=1;break;
		case 4:P2_4=1;P2_3=0;P2_2=0;break;
		case 5:P2_4=0;P2_3=1;P2_2=1;break;
		case 6:P2_4=0;P2_3=1;P2_2=0;break;
		case 7:P2_4=0;P2_3=0;P2_2=1;break;
		case 8:P2_4=0;P2_3=0;P2_2=0;break;
	}
	P0=NixieTable[Number];	//段码输出
}

/**
  * @brief  数码管驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Nixie_Loop(void)
{
	static unsigned char i=1;
	Nixie_Scan(i,Nixie_Buf[i]);
	i++;
	if(i>=9){i=1;}
}

Timer0.c

#include 

/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0_Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		
	}
}
*/

delay.h

#ifndef _DELAY_H__
#define _DELAY_H__
void Delay(unsigned int xms);
 
 #endif

key.h

#ifndef __KEY_H_
#define __KEY_H_

unsigned char Key(void);
void Key_Loop(void);

#endif

Nixie.h

#ifndef __NIXIE_H__
#define __NIXIE_H__

void Nixie_Scan(unsigned char Location,Number);
void Nixie_Loop(void);
void Nixie_SetBuf(unsigned char Location,Number);
#endif

Timer0.h

#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0_Init(void);

#endif

AT24C02.c

#include 
#include "I2C.h"

#define AT24C02_ADDRESS		0xA0

/**
  * @brief  AT24C02写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(Data);
	I2C_ReceiveAck();
	I2C_Stop();
}

/**
  * @brief  AT24C02读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
	unsigned char Data;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);
	I2C_ReceiveAck();
	Data=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return Data;
}

I2C.c

#include 

sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void I2C_Start(void)
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void I2C_Stop(void)
{
	I2C_SDA=0;
	I2C_SCL=1;
	I2C_SDA=1;
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		I2C_SDA=Byte&(0x80>>i);
		I2C_SCL=1;
		I2C_SCL=0;
	}
}

/**
  * @brief  I2C接收一个字节
  * @param  无
  * @retval 接收到的一个字节数据
  */
unsigned char I2C_ReceiveByte(void)
{
	unsigned char i,Byte=0x00;
	I2C_SDA=1;
	for(i=0;i<8;i++)
	{
		I2C_SCL=1;
		if(I2C_SDA){Byte|=(0x80>>i);}
		I2C_SCL=0;
	}
	return Byte;
}

/**
  * @brief  I2C发送应答
  * @param  AckBit 应答位,0为应答,1为非应答
  * @retval 无
  */
void I2C_SendAck(unsigned char AckBit)
{
	I2C_SDA=AckBit;
	I2C_SCL=1;
	I2C_SCL=0;
}

/**
  * @brief  I2C接收应答位
  * @param  无
  * @retval 接收到的应答位,0为应答,1为非应答
  */
unsigned char I2C_ReceiveAck(void)
{
	unsigned char AckBit;
	I2C_SDA=1;
	I2C_SCL=1;
	AckBit=I2C_SDA;
	I2C_SCL=0;
	return AckBit;
}

AT24C02.h

#ifndef __AT24C02_H__
#define __AT24C02_H__

void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);


#endif

I2C.h

#ifndef __I2C_H_
#define __I2C_H_


void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void);




#endif

你可能感兴趣的:(51单片机微型设计,51单片机,嵌入式硬件,单片机)