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

发布时间:2024-08-08  

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为低电平,主机为发送器,写数据

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

相关文章

    的可能相对复杂,可能有ADC的采样,FPGA的数字时钟等,如何让ADC前端的数据不失真的被FPGA获取,时钟信号非常关键。本文引用地址: 在给大家带来时钟新产品之前,我给大家介绍两个关键参数,因为......
    准备 硬件准备: 1. 一块LED电子数字时钟屏 2. 一根microusb线(安卓线) 3. 一个下载器(ST-Link或者Jlink 等) 软件准备: 4. MDK5软件 5. RT-Thread的......
    . 一块LED电子数字时钟屏 2. 一根microusb线(安卓线) 3. 一个下载器(ST-Link或者Jlink 等) 软件准备: 4. MDK5软件 5. RT-Thread的ENV工具 6......
    基于AT89C4051数字时钟的设计;这是一个用AT89C405l单片机做的一个实时数字时钟。由于使用AT89C405l,所以这个数字时钟成本很低、体积很小,可以做成一个小模块,使用非常方便。 一......
    SRAM。 一个16 MHz片内振荡器产生系统时钟。 此时钟在内部进行分频,使处理器在较低频率下工作,以便省电。 该器件还内置一个低功耗32 kHz振荡器,可用于给以下四个定时器提供时钟: 两种......
    新思科技推出业内首款高性能仿真系统ZeBu Server 5,助力实现系统级芯片电子数字孪生;新思科技ZeBu Server 5硬件仿真系统首年销售容量超4000亿门,加速复杂SoC和多......
    . 添加硬件并命名PLC在“项目树” 下双击 “添加新设备”,在对话框中选择所使用的S7-1200 CPU添加到机架上,命名为PLC_1。 图2. 添加CPU 3. 组态系统时钟在CPU 属性中定义的时钟......
    四方维将亮相2024年慕尼黑华南电子展;作为西门子数字化工业软件旗下电子供应链管理业务,四方维将于10月14-16日亮相2024年慕尼黑华南电子展,并与华南展主办方在在深圳国际会展中心(宝安......
    四方维将亮相2024年慕尼黑华南电子展; 作为西门子数字化工业软件旗下电子供应链管理业务,四方维将于10月14-16日亮相2024年慕尼黑华南电子展,并与华南展主办方在在深圳国际会展中心(宝安......
    器件进行接口。输入和输出数据可以独立地与左右时钟边沿对齐,或者比左右时钟边沿延后一位。输入和输出数据也可以独立地与字时钟上升沿对齐,或者比字时钟上升沿延后一位。 AD1890/AD1891采用0.8 µm单多......

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>