数字秒表+普中51单片机+江科大自化协

发布者:心想的45号最新更新时间:2024-08-08 来源: cnblogs关键字:数字秒表 手机看文章 扫描二维码
随时随地手机看文章

1 系统框图

 

2 实验现象

   

 一上电,数码管显示时间为00-00-00,即分钟-秒钟-Mini秒,范围为00-00-00——59-59-99,计时精度为0.01秒,能正确地进行计时,同时能记录一次时间,并在下一次计时后对上一次计时时间进行查询。当按键Key1按下时,秒表开始运行,再按下时,秒表停止;每按下一次,状态翻转一次;当按键Key2按下时,数码管显示时间清0;当按键Key3按下时,单片机将数码管显示的数值保存在AT24C02中,掉电不丢失;当按键Key4被按下时,单片机从AT24C02中读取数据,并显示在数码管上。


3 参考程序


3.1 主程序

#include

#include 'timer0.h'

#include 'key.h'

#include 'Nixie.h'

#include 'delayms.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)            //K1按键按下

        {

            RunFlag=!RunFlag;    //启动标识位翻转

        }    

        if(KeyNum==2)            //K2按键按下

        {

            Min=0;                //时间清0

            Sec=0;

            MiniSec=0;

        }    

        if(KeyNum==3)            //K3按键按下

        {

            AT24C02_WriteByte(0,Min);    //将分写入AT24C02的地址0

            delayms(5);

            AT24C02_WriteByte(1,Sec);    //将秒写入AT24C02的地址1

            delayms(5);

            AT24C02_WriteByte(2,MiniSec);//将Mini秒写入AT24C02的地址2

            delayms(5);

        }

        if(KeyNum==4)            //K3按键按下

        {

            Min=AT24C02_ReadByte(0);    //读出AT24C02数据

            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);

    }

}


/**

  * @brief  秒表驱动函数,时间运行,在中断中调用

  * @param  无,MiniSec:0-99, Sec:0-59, Min:0-59

  * @retval 无

  */

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=0x66;        //设置定时初始值,1ms,@11.0592MHz

    TH0=0xFC;        //设置定时初始值,1ms,@11.0592MHz

    T0Count1++;

    if(T0Count1>=20)

    {

        T0Count1=0;

        key_loop();        //20ms调用一次按键驱动函数

    }

    

    T0Count2++;

    if(T0Count2>=2)

    {

        T0Count2=0;

        Nixie_Loop();    //2ms调用一次数码管驱动函数

    }

    T0Count3++;

    if(T0Count3>=10)

    {

        T0Count3=0;

        Sec_Loop();        //10ms调用一次数秒表驱动函数

    }

}


3.2 按键扫描函数(定时器扫描按键,20ms一次,不断扫描)


#include

#include 'delayms.h'


sbit key1 = P3^1;

sbit key2 = P3^0;

sbit key3 = P3^2;

sbit key4 = P3^3;


unsigned char Key_Num;


/**

  * @brief  获取按键键码

  * @param  无

  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下

  */

unsigned char key(void)

{

    unsigned char Temp=0;

    Temp=Key_Num;

    Key_Num=0;

    return Temp;

}


/**

  * @brief  获取独立按键键码

  * @param  无

  * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0

  */

unsigned char key_getstate()

{

    unsigned char KeyNumber = 0;

    if(key1==0){KeyNumber=1;}

    if(key2==0){KeyNumber=2;}

    if(key3==0){KeyNumber=3;}

    if(key4==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_Num=1;

    }

    if(LastState==2 && NowState==0)

    {

        Key_Num=2;

    }

    if(LastState==3 && NowState==0)

    {

        Key_Num=3;

    }

    if(LastState==4 && NowState==0)

    {

        Key_Num=4;

    }

}


#ifndef _key_h_

#define _key_h_


unsigned char key();

void key_loop(void);


#endif


3.3 数码管驱动函数(定时器扫描数码管,2ms不断扫描)


#include

#include 'delayms.h'    


//数码管显示缓存区,其中10为不显示,对应Nixietable[10]=0x00

unsigned char Nixie_Buf[9]={0,10,10,10,10,10,10,10,10};    


//数码管段码表,0-9,不显示,-

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;}

}


#ifndef __NIXIE_H__

#define __NIXIE_H__


void Nixie_SetBuf(unsigned char Location,Number);

void Nixie_Scan(unsigned char Location,Number);

void Nixie_Loop(void);


#endif


3.4 定时器函数(T0)


#include


/**

  * @brief  定时器0初始化,1毫秒@11.0592MHz

  * @param  无

  * @retval 无

  */

void timer0_init(void)        //1毫秒@11.0592MHz

{

    TMOD &= 0xF0;    //设置定时器模式,1111_0000,&,高四位保留,低四位清零

    TMOD |= 0x01;    //设置定时器模式,0000_0001,|,高四位保留,设置模式为T0

    TL0 = 0x66;        //设置定时初始值,1ms,@11.0592MHz

    TH0 = 0xFC;        //设置定时初始值,1ms,@11.0592MHz

    TF0 = 0;        //清除TF0标志

    TR0 = 1;        //定时器0开始计时

    ET0=1;            //打开定时器T0中断开关

    EA=1;            //打开中断系统总开关

    PT0=0;            //设置T0中断优先级,低

}


#ifndef _timer0_h_

#define _timer0_h_


    void timer0_init(void);

    

#endif


3.5 I2C驱动函数


#include


sbit I2C_SCL=P2^1;

sbit I2C_SDA=P2^0;


/**

  * @brief  I2C通信开始

  * @param  无

  * @retval 无

  */

void I2C_Start(void)

{

    I2C_SCL=1;    //空闲状态

    I2C_SDA=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主机向从机发送一个字节,SCL为同步信号,低电平写数据

  * @param  Byte 要发送的字节

  * @retval 无

  */

void I2C_SendByte(unsigned char Byte)

{

    unsigned char i;

    for(i=0;i<8;i++)            //一个字节,8bit

    {

        I2C_SDA=Byte&(0x80>>i);    //SCL为低电平,主机为发送器,写数据

        I2C_SCL=1;                //SCL为高电平,从机为接收器,读数据

[1] [2]
关键字:数字秒表 引用地址:数字秒表+普中51单片机+江科大自化协

上一篇:呼吸灯(PWM)+普中51单片机+江科大自化协
下一篇:AT24C02数据存储+普中51单片机+江科大自化协

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved