小学期实训-智慧电子时钟

这篇具有很好参考价值的文章主要介绍了小学期实训-智慧电子时钟。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

摘 要

项目选题为智慧电子时钟,相对于传统时钟,该智慧时钟有实时时钟、实时日期、光照与温度显示、闹钟设置、闹钟关闭密码设置功能。同时,闹钟需要满足一定的条件才能开启,通过光照传感器来实现对闹钟的开启条件进行限制,需要光照条件到达一定值以上才会开启,防止夜间闹钟意外响铃,同时关闭闹钟时需要准确地输入设计好的八位密码,否则音乐会一直播放,以此更有效地实现闹钟的自动化、智能化。其次,电子时钟新增光照、温度显示的功能,帮助辨别冷暖,适当的增减衣物。

实现功能:

1)通过无源蜂鸣器实现闹钟响铃功能,并播放出一首音乐;

2)通过光照传感器限制闹钟开启功能;

3)通过输入密码实现闹钟关闭功能,其他方式无法关闭;

4)可以在数码管上显示实时时间、日期、温度、亮度、闹钟时间、密码设置、密码验证,通过K1、K2键进行显示切换;

5)通过导航键设置实时时间、日期、闹钟时间、密码、关闭闹钟时需要的密码。

关键词:电子时钟、智慧闹铃、密码控制

目录

一、 绪论... 1

(一)   主题和选题... 1

(二)   题目背景... 1

(三)   面临问题... 1

二、 课程设计... 2

(一)   总体方案设计... 2

1.设计目的... 2

2.设计思路图... 2

3.时间计划、内容... 3

(二)   各部分详细设计... 3

1.    STC-BSP头文件选择... 3

2.    设置事件回调函数... 3

3.    基本原理... 4

4.    函数设计... 11

(三)   硬件测试结果... 14

1.    编译结果... 14

2.    下载结果... 14

3.    实操测试... 15

4.    实现功能... 16

三、 总结... 17

(一)   问题及解决... 17

(二)   完成进度... 17

四、 心得体会... 18

五、 参考文献... 18

  • 绪论
    • 主题和选题

首先,确立项目选题为智慧电子时钟,相对于传统时钟,该智慧时钟有实时时钟、实时日期、光照与温度显示、闹钟设置、闹钟关闭密码设置功能。同时,闹钟需要满足一定的条件才能开启,通过光照传感器来实现对闹钟的开启条件进行限制,需要光照条件到达一定值以上才会开启,防止夜间闹钟意外响铃,同时关闭闹钟时需要准确地输入设计好的八位密码,否则音乐会一直播放,以此更有效地实现闹钟的自动化、智能化。其次,电子时钟新增光照、温度显示的功能,帮助辨别冷暖,适当的增减衣物。

    • 题目背景

随着社会发展和科技进步,人们对生活品质要求越来越高,而计算机时代的来临和物联网技术的发展,也给我们的生活带来巨大的变化。所以我想通过对电子时钟的创意设计,解决闹钟可以被随意关闭的问题,帮助人们快速起床并保持清醒,进而改善生活品质,有个美好的清晨。

    • 面临问题

1.如何将密码和其他信息同时存入非易失存储器,如何判断自己输入的密码是否与存储的密码正确匹配?

2.数码管如何正确显示多级界面以及如何根据当前状态进行按键判断?

3.如何通过导航按键来修改密码以及信息?

4.按键是否需要消抖,是否可以随意关闭闹钟?

5.由于使用了导航按键,K3按键的使用需要注意。

6.音乐播放这一线程是否会影响密码输入?

  • 课程设计
    • 总体方案设计

1.设计目的:

a) 学习STC-BSP的编程方式;

b) 非易失存储器M24C02芯片的操作使用;

c) 利用好STC学习板导航键;

d) 通过调用光照传感器、温度传感器等来丰富电子时钟。

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发
2.设计思路图:

3.时间计划、内容

a) 9月7日                 确定选题

b) 9月8日-9月12日      编写代码

c) 9月13日-9月15日    测试优化并完善设计报告

    • 各部分详细设计
        1. STC-BSP头文件选择

根据项目功能选择BSP包中所需的头文件:

#include "STC15F2K60S2.H" //必须

#include "sys.H"          //必须

#include "displayer.H"    //display(显示模块)

#include "key.h"          //key(按键模块)

#include "beep.h"         //beep(蜂鸣器模块)

#include "music.h"        //music(音乐播放)

#include "adc.h"          //adc(热敏、光敏、导航按键、扩展接口ADC功能)

#include "DS1302.h"       //DS1302实时时钟

#include "M24C02.h"       //24C02非易失性存储器

    并加载需要用的模块(由各模块提供加载函数):

Key_Init();         //按键模块加载函数

DisplayerInit();    //加载显示模块工作

BeepInit();         //蜂鸣器初始化

MusicPlayerInit();  //驱动music模块

AdcInit(ADCexpEXT); //ADC模块初始化,不含对扩展接口EXT设置ADC功能

DS1302Init(t);      //DS1302初始化

MySTC_Init();       //MySTC_OS初始化

        1. 设置事件回调函数

SetEventCallBack(enumEventKey, mykey_callback);        //K1K2按键

SetEventCallBack(enumEventSys100mS, my100mS_callback); //显示

SetEventCallBack(enumEventNav, myKN_callback);         //导航按键

SetEventCallBack(enumEventSys1S, my1S_callback);       //闹钟判断

在每一级数码管显示界面,都会检测按键和导航按键的使用,故需要K1K2按键和导航按键的回调函数,而数码管本身显示需要一个系统100mS事件回调函数,闹钟判断需要一个系统1S事件回调函数。

        1. 基本原理:
  1. 数码管与发光二极管

P0口的8位输出分别连接了8个发光二极管L0~L7的阳极, P2.3经过一个反相器连接到8个发光二极管L0~L7的阴极(共阴极):

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

P0口的8位输出分别控制1个LED数码管的7段和一个小数点:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

根据二极管的单向导通性(当阳极为高(对应P0口位为1)、阴极为低时,二极管导通,否则不导通),若P2.3输出信号为低电平“0”,则二极管的阴极都为高电平,二极管都不会导通,也就不会发光。因此想要发光二极管导通,必须先设置P2.3输出信号为“1”,再通过设置P0,点亮想要点亮的发光二极管。

而P2.3经反相器U4C控制74HC138的使能信号E3,结合P2.0、P2.1、P2.2这3个位选控制信号确定8个LED数码管中的哪个被点亮;电阻R15~R22为限流电阻。当段选为高、使能信号有效时,对应的LED管将会发光。通过以一定频率扫描位选信号,修改段选信号进行数码管点亮一段时间,从而给人视觉上几个数码管几乎同时显示的效果。

如果去掉DP小数点位就是七段。A在8位中的最低位,DP位为最高位。组合成的八位对应P0口的八位。数码管又分为共阴极和共阳极两种类型;其中共阴极就是将八个LED阴极连在一起,让其接地,这样给任何一个LED发光管另一端高电平,它便能点亮。而共阳极就是将八个LED的阳极连在一起。

  1. 非易失存储器24C02

非易失性存储器(nonvolatile memory)是掉电后数据能够保存的存储器,它不用定期地刷新存储器内容。这包括所有形式的只读存储器(ROM),像是可编程只读存储器(PROM)、可擦可编程只读存储器(EPROM)、电可擦除只读存储器(EEPROM)和闪存。在许多常见的应用中,微处理器要求非易失存储器来存放其可执行代码、变量和其他暂态数据(例如采集到的温度、光照等数据)。

24C02工作电路及其工作原理:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

管脚配置:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

管脚描述:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

寻址方式:

寻址信号由一个字节构成,高7位为地址位,最低位为方向位,用以表明主机与从器件的数据传送方向。方向位位0,表明主机接下来对从器件进行写操作;方向位位1,表明主机接下来对从器件进行读操作。

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

A0,A1和A2对应器件的管脚1,2和3;

a8,a9和a10对应存储阵列地址字地址;

读/写时序:

写一个字节时序

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

读一个字节时序

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

如图,写一个字节时序,第一个DEV SEL是器件选择信号,器件选择的范围为(000~111),总共可以选择8个24C02芯片器件。但是本实验只用到了1个24C02芯片,所以对应的器件管脚地址A2A1A0为000。第二个信号BYTEADDR是地址信号,表示要对哪一个地址进行操作,第三个DATA IN则是写入的数据。而读操作则是多了一步,DEV SEL和BYTE ADDR后,还有一个DEV SEL,但此信号的最后一位为高,表示是读操作,随后从机会把相应地址的数据发送给主机。

I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。I2C总线硬件结构图如下:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

SCL是时钟线,SDA是数据线

I2C总线信号包括有,启始信号,停止信号和应答信号,在程序用分别用函数void start()、void stop()、void respons()表示。24C02的存储空间为2K,每一次写和读操作都只能操作已选定的对应24C02芯片的地址数据。要切换操作的芯片,需要重新发送寻址信号,在void write_add(uchar addr,uchar date)函数中,第一个寻址信号writebyte(0xa0),已经固定了本程序只能在第0个芯片进行操作(注:0xa0化为二进制为1010000,其中,前4位1010是固定不能改变的,最后一位0代表写操作,1代表读操作,而中间三位则是代表不同芯片地址的编号),若要改变需要操作的芯片,则只需改变中间三位即可。

数据传输:SCL为高电平时,SDA线若保持稳定,那么SDA上是在传输数据bit;若SDA发生跳变,则用来表示一个会话的开始或结束

数据改变:SCL为低电平时,SDA线才能改变传输的bit

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。

结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据

  小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

主设备每发送完8bit数据后等待从设备的ACK。

即在第9个clock,从IC发ACK,SDA会被拉低。

若没有ACK,SDA会被置高,这会引起Master发生RESTART或STOP流程。

  1. 按键与导航按键

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

按键电路示意图(三个按键分别是K1、K2、K3)

当按键被按下的时候,电路导通接地,I/O口为低电平;当按键未被按下时,电路断开,I/O口保持高电平。

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发 LED灯以及数码管电路连接示意图

P0口的8位输出分别控制8个发光二极管L0~L7的阳极;而P2.3经反相器U4C控制8个发光管阴极E3;当阳极为高(对应P0口位为1)、阴极为低时,对应的二极管将会发光。

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

导航按键在上图的标注为MINI_KEY5,导航按键的每一个方向被按下,都会引起实际电压的改变,从而可以根据这个原理,与A/D转换器配合,可以判断哪个方位被按下,获取按下后A/D转换的结果。

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

   AD数据采集电路及采集步骤说明

ADC数据采集的步骤:

将ADC0~7的模拟量送到比较器中,用DAC(数/模转换器)转换的模拟量与输入的模拟量通过比较器进行比较。

转换结束后,将比较结果放入转换结果寄存器(ADC_RES和ADC_RESL)。

同时,需要将ADC_FLAG软件清零。

注意硬件会自动将ADC_START清零,如果需要进行下一次转换,则需要将ADC_START置位。

特别说明:

(1)数码管所显示的ADC转换结果并不是电压值,而是电压进行转换后所得的一个值。如果需要实际的电压值可以参照STC15F2K60S2数据手册的760页上面的公式进行计算得出。

(2)ADC转换结果是一个10位数据,若ADRJ=0,则ADC_RES存放高八位,ADC_RESL存放低两位。若ADRJ=1,则ADC_RESL存放高八位,ADC_RES存放低两位。本案例采用的是ADRJ=0,而且只取了高八位结果。

  1. 蜂鸣器

蜂鸣器分为有源蜂鸣器和无源蜂鸣器,这里的源特指振荡源;有源蜂鸣器直接加电就可以响起,无源蜂鸣器需要我们给提供振荡源。理想的振荡源为一定频率的方波。

本实验板采用的是无源蜂鸣器,相比与有源蜂鸣器,无源蜂鸣器的优点在于价格便宜,可以通过控制其振动频率来改变发出的声音,因此,无源蜂鸣器可以用于音乐的播放。而有源蜂鸣器的优点在于使用简单,不需要编写“乐谱”。本实验板使用的无源蜂鸣器是电磁式蜂鸣器,电磁式蜂鸣器由振荡器、电磁线圈、磁铁、振动膜片及外壳等组成。接通电源后,接收到的音频信号电流通过电磁线圈,使电磁线圈产生磁场。振动膜片在电磁线圈和磁铁的相互作用下,周期性地振动发声。

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

无源蜂鸣器电路原理图

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发       

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

按键控制电路

  1. 温度传感器与光照传感器

LED数码管电路:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

光敏和热敏电阻电路:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

工作原理:

热敏电阻随温度呈线性变化,光敏电阻电流随光强线性变化。通过AD采集光敏电阻和热敏电阻的输出值,输出对应的AD值,光照值直接为AD值,而采集的温度AD值,首先把10位转换成8位AD值,然后再通过查找对应的表来获取温度。

        1. 函数设计
  1. 各状态结构体设计

unsigned char funcmode; //定义显示、按键功能模式

enum funcname

{

    RTC_HMS = 1//实时时钟:时分秒

    RTC_YMD,     //实时时钟:年月日

    Rt_Rop,      //热敏光敏测量

    Alarm,       //闹钟

    Code,        //设置密码

    Code_test    //密码测试

};

  1. K1、K2按键回调函数设计

void dealwithmykey() //k1k2按键效果

{

    if (GetKeyAct(enumKey2) == enumKeyPress//按键2按下时切换显示和按键功能模式

    {

        if (funcmode == Code_test//闹钟状态下,K2键按下不会改变状态

        {

            funcmode == Code_test;

        }

        else

        {

            SetBeep(100010); //蜂鸣器鸣叫一声

            tempadj = 0;

            if (++funcmode > Code//状态合理切换

                funcmode = RTC_HMS;

            LedPrint(funcmode);

            M24C02_Write(0x00, funcmode);

        }

    }

    if (GetKeyAct(enumKey1) == enumKeyPress//K1按下时切换显示和按键功能模式

    {

        if (funcmode == Code_test//闹钟状态下,K1键按下不会改变状态

        {

            funcmode == Code_test;

        }

        else

        {

            SetBeep(100010); //蜂鸣器鸣叫一声

            tempadj = 0;

            if (--funcmode < RTC_HMS//状态合理切换

                funcmode = Code;

            LedPrint(funcmode);

            M24C02_Write(0x00, funcmode);

        }

    }

}

  1. 显示回调函数设计

void dealwithDisp()

{

    unsigned char d0, d1, d2, d3, d4, d5, d6, d7; //8位数码管显示定义

    static unsigned char ct100mS = 10;

    if (--ct100mS == 0)     //设置一个数码管闪烁的计时函数

        ct100mS = 10;

    switch (funcmode)

    {

    case RTC_YMD:

        if (tempadj == 0

            t = RTC_Read(); //非调时钟时, RTC

           .

.详见工程文件

    case RTC_HMS:

           .

.详见工程文件

    case Rt_Rop:

        ADCresult = GetADC();

        ADCresult.Rt = tempdata[ADCresult.Rt - 330]; //根据转换表进行读取的温度与实际温度转换

        d0 = ADCresult.Rop % 1000 / 100//取出数据的百位

        d1 = ADCresult.Rop % 100 / 10;   //取出数据的十位

        d2 = ADCresult.Rop % 10;         //取出数据的个位

           .

.详见工程文件

    case Alarm:

        if (tempadj == 0)

        {

            m.hour = NVM_Read(0x01);   //将闹钟的小时数存入DS1302中的0x01地址中

            m.minute = NVM_Read(0x02); //将闹钟的分钟数存入DS1302中的0x02地址中

            m.second = NVM_Read(0x03); //将闹钟的秒钟数存入DS1302中的0x03地址中

        }

        d0 = m.hour >> 4;  //8 bit数据中的高四位

        d1 = m.hour & 0xf//8 bit数据中的低四位

           .

.详见工程文件

    case Code:

        if (tempadj == 0)

        {

            c.a1 = NVM_Read(0x04); //8位闹钟密码分别存入DS1302中的0x04~0x11地址中

           .

.详见工程文件

    case Code_test:

        .

.详见工程文件

    }

if (funcmode == RTC_YMD || funcmode == RTC_HMS || funcmode == Alarm

//时间、日期、闹钟显示界面时数码管如何闪烁

    {

        if (ct100mS >= 8)

            switch (tempadj)

            {

               .

.详见工程文件

            }

    }

if (funcmode == Code || funcmode == Code_test

//设置密码、密码输入界面时数码管如何闪烁

    {

               .

.详见工程文件

    }

    Seg7Print(d0, d1, d2, d3, d4, d5, d6, d7); //8位数码管显示

}

  1. 导航按键回调函数设计

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

在时间、日期、闹钟状态下导航中键选择开始更改或者确认更改,导航左右键更改选择时、分、秒 或 年、月、日,上下键数字加减一。在设置密码状态下,按下导航中键更改密码,导航左右键更改选择密码位数,上下键数字加减一。在闹钟响起后输入密码状态下,上下键数字加减一,右键按下判断密码是否正确,其余键无法改变闹钟状态。

  1. 闹钟回调函数

void dealwithAlarm() //闹钟回调函数

{

if (m.hour == t.hour && m.minute == t.minute && m.second == t.second) 

//判断条件

    {

        ADCresult = GetADC();

        if (ADCresult.Rop >= 20)

        {

            funcmode = Code_test;

            SetMusic(Music_PM, Music_tone, &song, sizeof(song), 0xF0); 

//初始化音乐

            SetPlayerMode(enumModePlay); //播放音乐

        }

    }

}

    • 硬件测试结果
        1. 编译结果:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

        1. 下载结果:

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

实操测试:

        1. 小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发
          小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发 时钟显示界面                            日期显示界面

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发 亮度、温度显示界面                       闹钟显示界面

密码设置显示界面                              闹钟响起显示界面、                       

        1. 实现功能:

a)通过无源蜂鸣器实现闹钟响铃功能,并播放出一首音乐;

b)通过光照传感器限制闹钟开启功能;

c)通过输入密码实现闹钟关闭功能,其他方式无法关闭;

d)可以在数码管上显示实时时间、日期、温度、亮度、闹钟时间、密码设置、密码验证,通过K1、K2键进行显示切换;

e)通过导航键设置实时时间、日期、闹钟时间、密码、关闭闹钟时需要的密码。

  • 总结
    • 问题及解决

Q1:如何将密码和信息同时存入非易失存储器24C02,如何判断自己输入的密码是否与存储的密码正确匹配?

A1:将输入密码与储存密码设为同一结构体类型,输入信息(8字节)与对应的密码(8字节,读出24C02中0x04~0x11地址处的密码)做比较,若8个数据均相同则密码正确,否则密码错误。

Q2:数码管如何现实以及多级界面如何分配并且根据当前状态进行按键判断?

A2:设置一个变量funcmode来表示界面的状态,1代表实时时钟、2代表实时日期、3代表敏光敏测量、4代表闹钟、5代表设置密码、6代表密码检测等等,将各个状态变成各个数值;将界面的改变放在按键回调函数中,当按下按键时根据当前状态来进入下一界面并完成界面初始化。

Q3:如何通过导航按键来修改密码以及信息(精确到数码管上每一位数字所代表的四位bite的自由修改而不是一个字节的修改)?

A3:如在具体实现中所提到的,定义两个变量分别表示修改字节的步长和被修改的字节,根据flag2标志来设置步长与字节,flag%2=0的话表明修改的是flag/2这一字节的高四位,因此步长为0x10,否则修改低四位步长为0x10。

Q4:因为要使用导航按键进行数值的变化,那么最好是使用Key3的P1.7口作为虚拟AD口,但是我还是需要Key3的按键功能,那么该如何解决?

A4:学习导航按键与数字按键综合控制数码管工程中的使用方法,为Key3单门设置一个btkey3flag,按下key3时虽然不能直接使用Key3=P1.7的按键消抖方法来实现,但同样可以在导航按键模块返回ADC等于0x00(也就是表示key3被按下)时将标志置1,这样就可以知道什么时候按下key3以及有没有按下key进而使用这个按键。

    • 完成进度

至2021年9月16日,预期功能均已完成并通过测试。

  • 心得体会

整个项目设计历时两个星期,直到16号才终于画下句号,在此感慨良多。因为想法和工程函数是自己设计实现的,所以在编程与调试上的时间不短,也遇到过很多的bug,也解决了很多的难题。

单片机的学习尤其是编程确实非常的难,因为有太多的寄存器需要去学习如何赋值、都代表了什么,有时候看STC的数据手册上的寄存器功能都会感到一头雾水,大段的文字、非常多的图片往往让人感到困扰,想要完全理解这太难了。

但是有了徐成老师编写的STC-BSP的文件,一切问题迎刃而解,看STC-BSP提供的函数,并编程测试,读懂每个头文件函数的内容以及函数作用,调度起来就顺利了许多。同时,实例案件和各类讲座也同样在逐步解决我们学习中遇到的问题。

这次小学期的实训我感觉非常有意义,不仅学到了很多的新知识并将之运用到了实践上,而且了解到了这些简单的硬件的工作方式,真是受益匪浅。

  • 参考文献

[1] STC-B学习板原理图
[2] STC15F2K60S2数据手册
[3] 工程训练学习板原理
[4] 基于STCBSP的应用程序设计

【实验源码】

 

小学期实训-智慧电子时钟,数字电路,硬件工程,fpga开发

【main.c】

//******* 用户程序段1:用户程序包含文件 *************//
#include "main.H" //编写应用程序时,仅需改写 main.h 和 main.c文件
#include "song.c" //song.c中编写了音乐(同一首歌)编码
//******* 用户程序段2:用户自定义函数声明 *************//

//******* 用户程序段3:用户程序全局变量定义 *************//
struct_DS1302_RTC t = {0x30, 0, 9, 0x06, 9, 1, 0x21}; //实时时钟数据结构:秒、分、时、日、月、周、年。初值:2021年9月6日,周一,9:00:30
struct_RTA m = {0, 0x30, 0x12};
struct_Code c = {0, 0, 0, 0, 0, 0, 0, 0};
struct_Code s_code = {0, 0, 0, 0, 0, 0, 0, 0};
int code tempdata[]={239,197,175,160,150,142,135,129,124,120,116,113,109,107,104,101, 
								99, 97, 95, 93, 91, 90, 88, 86, 85, 84, 82, 81, 80, 78, 77, 76, 
								75, 74, 73, 72, 71, 70, 69, 68, 67, 67, 66, 65, 64, 63, 63, 62, 
								61, 61, 60, 59, 58, 58, 57, 57, 56, 55, 55, 54, 54, 53, 52, 52, 
								51, 51, 50, 50, 49, 49, 48, 48, 47, 47, 46, 46, 45, 45, 44, 44, 
								43, 43, 42, 42, 41, 41, 41, 40, 40, 39, 39, 38, 38, 38, 37, 37, 
								36, 36, 36, 35, 35, 34, 34, 34, 33, 33, 32, 32, 32, 31, 31, 31, 
								30, 30, 29, 29, 29, 28, 28, 28, 27, 27, 27, 26, 26, 26, 25, 25,
								24, 24, 24, 23, 23, 23, 22, 22, 22, 21, 21, 21, 20, 20, 20, 19, 
								19, 19, 18, 18, 18, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, 
								13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 10, 9, 9, 9, 8, 8, 8, 7, 
								7, 7, 6, 6,5, 5, 54,4, 3, 3,3, 2, 2, 1, 1, 1, 0, 0, -1, -1, -1, 
								-2, -2, -3, -3, -4, -4, -5, -5, -6, -6, -7, -7, -8, -8, -9, -9, 
								-10, -10, -11, -11, -12, -13, -13, -14, -14, -15, -16, -16, -17, 
								-18, -19, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 
								-30, -32, -33, -35, -36, -38, -40, -43, -46, -50, -55, -63, 361};
struct_SysPerF SysPer;				//系统性能数据结构:每秒主循环次数4字节、每秒轮询丢失次数1字节
struct_ADC ADCresult;				//热敏、光敏测量AD值
unsigned char Music_tone, Music_PM; //音乐播放音调、节凑(每分钟节拍数)

unsigned char funcmode; //定义显示、按键功能模式
enum funcname
{
	RTC_HMS = 1, //实时时钟:时分秒
	RTC_YMD,	 //实时时钟:年月日
	Rt_Rop,		 //热敏光敏测量
	Alarm,		 //闹钟
	Code,		 //设置密码
	Code_test	 //密码检测
};
unsigned char tempadj; //程序变量。调整时钟时用:=1 调年或时;=2 调月或分 =3 调日 或秒

//******* 用户程序段4:用户自定义函数原型 *************//
#include "function.c"
void my100mS_callback() //100mS事件回调函数
{
	dealwithDisp();
}
void myKN_callback() //导航按键事件回调函数
{
	dealwithmyKN();
}
void mykey_callback() // 按键(Key1、Key2)事件回调函数
{
	dealwithmykey();
}

void my1S_callback() // 闹铃回调函数
{
	dealwithAlarm();
}
//******* main()函数 *************//
void main()
{ //主函数 main() 开始

	//******* 用户程序段5:用户main()函数内部局部变量定义 *************//

	//******* 用户程序段6:用户main()函数(初始化类程序) *************//
	//1,加载需要用的模块(由各模块提供加载函数)
	Key_Init();			//按键模块加载函数
	DisplayerInit();	//加载显示模块工作
	BeepInit();			//蜂鸣器初始化
	MusicPlayerInit();	//驱动music模块
	AdcInit(ADCexpEXT); //ADC模块初始化,不含对扩展接口EXT设置ADC功能
	DS1302Init(t);		//DS1302初始化

	//2,设置事件回调函数(由sys提供设置函数SetEventCallBack())
	SetEventCallBack(enumEventKey, mykey_callback);		   //按键
	SetEventCallBack(enumEventSys100mS, my100mS_callback); //显示
	SetEventCallBack(enumEventNav, myKN_callback);		   //设置导航按键回调函数
	SetEventCallBack(enumEventSys1S, my1S_callback);	   //闹钟判断

	//3,用户程序状态初始化
	SetDisplayerArea(0, 7);

	//4,用户程序变量初始化
	funcmode = 1;
	Music_PM = 90;
	Music_tone = 0xFC;
	funcmode = M24C02_Read(0x00);
	LedPrint(funcmode);

	/*****************  MySTC_OS 初始化与加载开始  ********************************/
	MySTC_Init(); // MySTC_OS 初始化
	while (1)	  // 系统主循环
	{
		MySTC_OS(); // MySTC_OS 加载
		/*****************  MySTC_OS 初始化与加载结束  ********************************/
	} //主循环while(1)结束
} //主函数 main() 结束

【main.h】

/**********************************  Ver3.3 说明 ********************************************************************
  (1) 系统工作时钟频率可以在main.c中修改 SysClock赋值(单位Hz)。
      如:code long SysClock=11059200; 定义系统工作时钟频率为11059200Hz(也即11.0592MHz)		
      系统工作频率必须与实际工作频率(下载时选择的)一致,以免与定时相关的所有功能出现误差或错误。
	(2) 使用方法:
	        1,在工程中加载main.c文件和STC_BSP.lib库文件
					2,在main.c中选择包含以下头文件(如果要使用可选模块提供的函数和方法,就必须包含其头文件)	:
								#include "STC15F2K60S2.H"        //必须,"STC-B学习板"使用MCU指定的头文件
								#include "sys.H"                 //必须,sys(MySTC_OS调度程序)头文件
								#include "display.H"             //可选,display(显示模块)头文件         
								#include "key.H"                 //可选,key(按键模块)头文件。
								#include "hall.H"                //可选,hall(霍尔传感器模块)头文件。
								#include "Vib.h"	               //可选,Vib(振动传感器模块)头文件。								 
								#include "beep.H"                //可选,beep(蜂鸣器模块)头文件。					
								#include "music.h"               //可选,music(音乐播放)头文件。	
								#include "adc.h"                 //可选,adc(热敏、光敏、导航按键、扩展接口ADC功能)头文件。	
								#include "uart1.h"               //可选,uart1(串口1通信)头文件。
								#include "uart2.h"               //可选,uart2(串口2通信)头文件。
							  #include "stepmotor.h"           //可选,步进电机      
                #include "DS1302.h"              //可选,DS1302实时时钟
                #include "M24C02.h"              //可选,24C02非易失性存储器
                #include "FM_Radio.h"	           //可选,FM收音机
                #include "EXT.h"                 //可选,EXT扩展接口(电子秤、超声波测距、旋转编码器、PWM输出控制电机快慢和正反转)
                #include "IR.h"	                 //可选,38KHz红外通信
								
					3,MySTC_Init()是sys初始化函数,必须执行一次;
					   MySTC_OS()是sys调度函数,应置于while(1)循环中;
					4,各可选模块如果选用,必须在使用模块其它函数和方法前执行一次模块所提供的驱动函数(设置相关硬件、并在sys中加载其功能调度):
						    DisplayerInit();      //显示模块驱动 
								Key_Init();           //按键模块驱动
								BeepInit();	          //蜂鸣器模块驱动
								MusicPlayerInit();    //蜂鸣器播放音乐驱动
	              HallInit();           //霍尔传感器模块驱动                      
	              VibInit();            //振动传感器模块驱动          
	              AdcInit();            //模数转换ADC模块驱动(含温度、光照、导航按键与按键Key3、EXT扩展接口上的ADC)
	              StepMotorInit();      //步进电机模块驱动	                  
    	          DS1302Init();         //DS1302实时时钟驱动
	              FMRadioInit();	      //FM收音机驱动           
                EXTInit();            //扩展接口驱动(含电子秤、超声波测距、旋转编码器、PWM输出,但不含EXT上Uart2和与之相关应用)
	              Uart1Init();          //Uart1(串口1)驱动:USB上(与计算机通信)              
                Uart2Init();          //Uart2(串口2)驱动:485接口、或EXT扩展接口(多机通信、Uart方式模块如蓝牙模块) 
	              IrInit();             //38KHz红外通信模块驱动
								
							说明:有部分模块不需要驱动;驱动函数有些有参数。(具体见各模块头文件说明)
								
          5,sys和各模块共提供以下事件:
					      numEventSys1mS:              1mS事件                        ("1毫秒时间间隔到"事件)
					      enumEventSys10mS:            10mS事件                       ("10毫秒时间间隔到"事件)
				        enumEventSys100mS:           100mS事件                      ("100毫秒时间间隔到"事件)
								enumEventSys1S:              1S事件                         ("1秒时间间隔到"事件)
								enumEventKey:                按键事件                       (K1、K2、K3 三个按键有"按下"或"抬起"操作)
								enumEventHall:               霍尔传感器事件                 (霍尔传感器有"磁场接近"或"磁场离开"事件)
 								enumEventVib:                振动传感器事件                 (振动感器检测到"振动"事件)
								enumEventNav:                导航按键事件                   (导航按键5个方向、或按键K3 有"按下"或"抬起"操作)
								enumEventXADC:               扩展接口上完成一次ADC转换事件  (P1.0、P1.1采取到一组新数据)
								enumEventUart1Rxd:           Uart1收到了一个符合指定要求(数据包头匹配、数据包大小一致)的数据包
	              enumEventUart2Rxd:           Uart2收到了一个符合指定要求(数据包头匹配、数据包大小一致)的数据包   
	              enumEventIrRxd:              红外接收器Ir上收到一个数据包						
								
								对这些事件,应采用"回调函数"方法响应(即用sys提供的SetEventCallBack()设置用户回调函数),以提高系统性能。
								
					6,各可选模块提供的其它函数和具体使用方法请参见:
					      各模块头文件中的说明;
								main.c提供的推荐程序框架和部分示例;
								其它可能技术文档或应用示例
						
编写:徐成(电话18008400450)   2021年2月26日设计,2021年9月1日更新
**************************************************************************/
#include "STC15F2K60S2.H" //必须
#include "sys.H"		  //必须
#include "displayer.H"	  //display(显示模块)
#include "key.h"		  //key(按键模块)
#include "beep.h"		  //beep(蜂鸣器模块)
#include "music.h"		  //music(音乐播放)
#include "adc.h"		  //adc(热敏、光敏、导航按键、扩展接口ADC功能)
#include "DS1302.h"		  //DS1302实时时钟
#include "M24C02.h"		  //24C02非易失性存储器
typedef struct
{
	unsigned char second; //秒(BCD码,以下均为BCD码)
	unsigned char minute; //分
	unsigned char hour;	  //时
} struct_RTA;

typedef struct
{
	unsigned char a1;
	unsigned char a2;
	unsigned char a3;
	unsigned char a4;
	unsigned char a5;
	unsigned char a6;
	unsigned char a7;
	unsigned char a8;
} struct_Code;

code unsigned long SysClock = 11059200; //必须。定义系统工作时钟频率(Hz),用户必须修改成与实际工作频率(下载时选择的)一致
#ifdef _displayer_H_					//显示模块选用时必须。(数码管显示译码表,用戶可修改、增加等)
code char decode_table[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x00, 0x08, 0x40, 0x01, 0x41, 0x48,
							/* 序号:   0   1    2	   3    4	    5    6	  7   8	   9	 10	   11		12   13    14     15     */
							/* 显示:   0   1    2    3    4     5    6    7   8    9  (无)   下-  中-  上-  上中-  中下-   */
							0x3f | 0x80, 0x06 | 0x80, 0x5b | 0x80, 0x4f | 0x80, 0x66 | 0x80, 0x6d | 0x80, 0x7d | 0x80, 0x07 | 0x80, 0x7f | 0x80, 0x6f | 0x80};
/* 带小数点     0         1         2         3         4         5         6         7         8         9        */

#endif

【song.c】

/*     音乐编码规则: 1,常规音乐简谱发音编码(成对出现,不可分开,即中间不能插入其它编码和控制字)   
			                         音高(1字节),节拍数(1字节),音高,节拍,.......        // 音高: 00          :休止符
															                                                                      0x11 — 0x17 :对应低音 do、re、mi、fa、so、la、si
																																																	  0x21 — 0x27 :对应中音 do、re、mi、fa、so、la、si
                      															                                                0x31 — 0x37 :对应高音 do、re、mi、fa、so、la、si
																																														 节拍: 1-255(0x01-0xFF): 单位1/16拍
																																														        或十六进制中,高4位表示整拍数,低4位表示分拍数
																																																		    如:发音2拍:  0x20
																																																				    发音半拍: 0x08
																																																				    发音1拍半:0x18
											2,音乐编码中可以插入以下控制字,用于设定音乐播放参数等(前6个也可以通过函数,用程序设定和实现)
                                    Use_null           :  不用LED和Light
																		Use_LED            :  启用LED
																		Use_Light          :  启用Light
																		Use_LEDandLight    :  启用LED和Light
																		Set_beatsPM        :  设置节拍率, 后面再跟 节拍率(1字节)
																		Set_tone           :  设置音调,   后面再跟 音调(1字节):0xFA 或 0xFB 或 0xFC 或 0xFD 或 0xFE 或 0xFF 或 0xF9
																		Repeat_begin       :  设置音乐播放重复开始处。重复一次(暂不能多次),暂不能嵌套(嵌套无效或可能导致不可预期结果)
																		Repeat_end         :  设置音乐播放重复结束处
*/
code unsigned char song[]={         //《同一首歌》
0x00,0x10,
0x25,0x10,
0x31,0x10,
0x32,0x10,
0x33,0x30,
0x32,0x08,
0x31,0x08,
0x32,0x20,
0x31,0x10,
0x26,0x10,
0x31,0x40,  
0x31,0x08,
0x26,0x08,
0x25,0x08,
0x23,0x08,
0x21,0x08,
0x16,0x08,
0x15,0x08,
0x13,0x08,
enumMscRepeatBegin,            
0x15,0x20,
0x21,0x10,
0x22,0x10,
0x23,0x18,
0x24,0x08,
0x23,0x10,
0x21,0x10,
0x22,0x20,
0x21,0x10,
0x16,0x10,
0x21,0x40,  
0x15,0x20,
0x21,0x10,
0x22,0x10,

0x23,0x10,
0x23,0x08,
0x24,0x08,
0x25,0x10,
0x21,0x10,
0x24,0x18,
0x23,0x08,
0x25,0x10,
0x22,0x08,
0x23,0x08,
0x23,0x08,
0x22,0x08,
0x22,0x30,
0x23,0x20,
0x25,0x10,
0x31,0x10,

0x27,0x18,
0x26,0x08,
0x26,0x20,
0x25,0x10,
0x25,0x08,
0x26,0x08,
0x27,0x10,
0x26,0x08,
0x25,0x08,
0x23,0x40,
0x24,0x18,
0x24,0x08,
0x25,0x10,
0x26,0x10,

0x25,0x10,
0x24,0x08,
0x23,0x08,
0x22,0x20,
0x17,0x10,
0x17,0x08,
0x16,0x08,
0x15,0x10,
0x16,0x10,
0x21,0x80,

// enumMscDrvSeg7,                    //改变显示
enumMscSetTone, 0xFF,             //设置音调
enumMscSetBeatsPM,120,            //设置节拍?
enumMscRepeatEnd		              //设置重复结束
};

【function.c】文章来源地址https://www.toymoban.com/news/detail-701899.html

void dealwithmykey() //k1、k2按键效果
{
	if (GetKeyAct(enumKey2) == enumKeyPress) //按键2按下时切换显示和按键功能模式
	{
		if (funcmode == Code_test) //闹钟状态下,K2键按下不会改变状态
		{
			funcmode == Code_test;
		}
		else
		{
			SetBeep(1000, 10); //蜂鸣器鸣叫一声
			tempadj = 0;
			if (++funcmode > Code) //状态合理切换
				funcmode = RTC_HMS;
			LedPrint(funcmode);
			M24C02_Write(0x00, funcmode);
		}
	}
	if (GetKeyAct(enumKey1) == enumKeyPress) //K1按下时切换显示和按键功能模式
	{
		if (funcmode == Code_test) //闹钟状态下,K1键按下不会改变状态
		{
			funcmode == Code_test;
		}
		else
		{
			SetBeep(1000, 10); //蜂鸣器鸣叫一声
			tempadj = 0;
			if (--funcmode < RTC_HMS) //状态合理切换
				funcmode = Code;
			LedPrint(funcmode);
			M24C02_Write(0x00, funcmode);
		}
	}
}
void dealwithDisp()
{
	unsigned char d0, d1, d2, d3, d4, d5, d6, d7; //8位数码管显示定义
	static unsigned char ct100mS = 10;
	if (--ct100mS == 0)		//设置一个数码管闪烁的计时函数
		ct100mS = 10;
	switch (funcmode)
	{
	case RTC_YMD:
		if (tempadj == 0) 
			t = RTC_Read(); //非调时钟时, 读RTC
		d0 = t.year >> 4;
		d1 = t.year & 0x0f;
		d2 = 12;
		d3 = t.month >> 4;
		d4 = t.month & 0x0f;
		d5 = 12;
		d6 = t.day >> 4;
		d7 = t.day & 0x0f;
		break;
	case RTC_HMS:
		if (tempadj == 0)
			t = RTC_Read();
		d0 = t.hour >> 4;
		d1 = t.hour & 0x0f;
		d2 = 12;
		d3 = t.minute >> 4;
		d4 = t.minute & 0x0f;
		d5 = 12;
		d6 = t.second >> 4;
		d7 = t.second & 0x0f;
		break;
	case Rt_Rop:
		ADCresult = GetADC();
		ADCresult.Rt = tempdata[ADCresult.Rt - 330]; //根据转换表进行读取的温度与实际温度转换
		d0 = ADCresult.Rop % 1000 / 100; //取出数据的百位
		d1 = ADCresult.Rop % 100 / 10;   //取出数据的十位
		d2 = ADCresult.Rop % 10; 		 //取出数据的个位
		d3 = 10;
		d4 = 10;
		d5 = ADCresult.Rt % 1000 / 100; 
		d6 = ADCresult.Rt % 100 / 10;
		d7 = ADCresult.Rt % 10;
		break;
	case Alarm:
		if (tempadj == 0)
		{
			m.hour = NVM_Read(0x01);   //将闹钟的小时数存入DS1302中的0x01地址中
			m.minute = NVM_Read(0x02); //将闹钟的分钟数存入DS1302中的0x02地址中
			m.second = NVM_Read(0x03); //将闹钟的秒钟数存入DS1302中的0x03地址中
		}
		d0 = m.hour >> 4;  //取8 bit数据中的高四位
		d1 = m.hour & 0xf; //取8 bit数据中的低四位
		d2 = 12;
		d3 = m.minute >> 4;
		d4 = m.minute & 0xf;
		d5 = 12;
		d6 = m.second >> 4;
		d7 = m.second & 0xf;
		break;
	case Code:
		if (tempadj == 0)
		{
			c.a1 = NVM_Read(0x04); //将8位闹钟密码分别存入DS1302中的0x04~0x11地址中
			c.a2 = NVM_Read(0x05);
			c.a3 = NVM_Read(0x06);
			c.a4 = NVM_Read(0x07);
			c.a5 = NVM_Read(0x08);
			c.a6 = NVM_Read(0x09);
			c.a7 = NVM_Read(0x10);
			c.a8 = NVM_Read(0x11);
		}
		d0 = c.a1;
		d1 = c.a2;
		d2 = c.a3;
		d3 = c.a4;
		d4 = c.a5;
		d5 = c.a6;
		d6 = c.a7;
		d7 = c.a8;
		break;
	case Code_test:
		if (tempadj == 0)
		{
			tempadj = 1;
		}
		d0 = s_code.a1;
		d1 = s_code.a2;
		d2 = s_code.a3;
		d3 = s_code.a4;
		d4 = s_code.a5;
		d5 = s_code.a6;
		d6 = s_code.a7;
		d7 = s_code.a8;
		break;
	default:
		break;
	}
	if (funcmode == RTC_YMD || funcmode == RTC_HMS || funcmode == Alarm) //时间、日期、闹钟显示界面时数码管如何闪烁
	{
		if (ct100mS >= 8)
			switch (tempadj)
			{
			case 1:
				d0 = 10;
				d1 = 10;
				break;
			case 2:
				d3 = 10;
				d4 = 10;
				break;
			case 3:
				d6 = 10;
				d7 = 10;
				break;
			default:
				break;
			}
	}
	if (funcmode == Code || funcmode == Code_test) //设置密码、密码输入界面时数码管如何闪烁
	{
		if (ct100mS >= 8)
			switch (tempadj)
			{
			case 1:
				d0 = 12;
				break;
			case 2:
				d1 = 12;
				break;
			case 3:
				d2 = 12;
				break;
			case 4:
				d3 = 12;
				break;
			case 5:
				d4 = 12;
				break;
			case 6:
				d5 = 12;
				break;
			case 7:
				d6 = 12;
				break;
			case 8:
				d7 = 12;
				break;
			default:
				break;
			}
	}
	Seg7Print(d0, d1, d2, d3, d4, d5, d6, d7); //8位数码管显示
}
void dealwithmyKN() //导航按键效果
{
	unsigned char a;
	switch (funcmode)
	{
	case RTC_HMS:
		if (GetAdcNavAct(enumAdcNavKeyRight) == enumKeyPress)
		{
			if (tempadj)
				if (tempadj < 3)
				{
					tempadj++;
					SetBeep(1000, 10); //蜂鸣器鸣叫一声
				}
		}
		if (GetAdcNavAct(enumAdcNavKeyLeft) == enumKeyPress)
		{
			if (tempadj)
				if (tempadj > 1)
				{
					tempadj--;
					SetBeep(1000, 10); //蜂鸣器鸣叫一声
				}
		}
		if (GetAdcNavAct(enumAdcNavKeyUp) == enumKeyPress)
		{
			if (tempadj == 1)
			{
				a = t.hour / 16 * 10 + t.hour % 16;
				if ((++a) >= 24)
					a = 0;
				t.hour = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 2)
			{
				a = t.minute / 16 * 10 + t.minute % 16;
				if ((++a) >= 60)
					a = 0;
				t.minute = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 3)
			{
				a = t.second / 16 * 10 + t.second % 16;
				if ((++a) >= 60)
					a = 0;
				t.second = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyDown) == enumKeyPress)
		{
			if (tempadj == 1)
			{
				a = t.hour / 16 * 10 + t.hour % 16;
				if ((a--) == 0)
					a = 23;
				t.hour = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 2)
			{
				a = t.minute / 16 * 10 + t.minute % 16;
				if ((a--) == 0)
					a = 59;
				t.minute = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 3)
			{
				a = t.second / 16 * 10 + t.second % 16;
				if ((a--) == 0)
					a = 59;
				t.second = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyCenter) == enumKeyPress)
		{
			SetBeep(1000, 10); //蜂鸣器鸣叫一声
			if (tempadj == 0)
				tempadj = 3;
			else
			{
				tempadj = 0;
				RTC_Write(t);
			}
		}
		break;
	case RTC_YMD:
		if (GetAdcNavAct(enumAdcNavKeyRight) == enumKeyPress)
		{
			if (tempadj)
				if (tempadj < 3)
				{
					tempadj++;
					SetBeep(1000, 10); //蜂鸣器鸣叫一声
				}
		}
		if (GetAdcNavAct(enumAdcNavKeyLeft) == enumKeyPress)
		{
			if (tempadj)
				if (tempadj > 1)
				{
					tempadj--;
					SetBeep(1000, 10); //蜂鸣器鸣叫一声
				}
		}
		if (GetAdcNavAct(enumAdcNavKeyUp) == enumKeyPress)
		{
			if (tempadj == 1)
			{
				a = t.year / 16 * 10 + t.year % 16;
				if ((++a) >= 99)
					a = 0;
				t.year = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 2)
			{
				a = t.month / 16 * 10 + t.month % 16;
				if ((++a) >= 12)
					a = 1;
				t.month = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 3)
			{
				a = t.day / 16 * 10 + t.day % 16;
				if ((++a) >= 31)
					a = 1;
				t.day = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyDown) == enumKeyPress)
		{
			if (tempadj == 1)
			{
				a = t.year / 16 * 10 + t.year % 16;
				if ((a--) == 0)
					a = 99;
				t.year = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 2)
			{
				a = t.month / 16 * 10 + t.month % 16;
				if ((a--) == 1)
					a = 12;
				t.month = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 3)
			{
				a = t.day / 16 * 10 + t.day % 16;
				if ((a--) == 1)
					a = 31;
				t.day = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyCenter) == enumKeyPress)
		{
			SetBeep(1000, 10); //蜂鸣器鸣叫一声
			if (tempadj == 0)
				tempadj = 3;
			else
			{
				tempadj = 0;
				RTC_Write(t);
			}
		}
		break;
	case Alarm:
		if (GetAdcNavAct(enumAdcNavKeyRight) == enumKeyPress)
		{
			if (tempadj)
				if (tempadj < 3)
				{
					tempadj++;
					SetBeep(1000, 10); //蜂鸣器鸣叫一声
				}
		}
		if (GetAdcNavAct(enumAdcNavKeyLeft) == enumKeyPress)
		{
			if (tempadj)
				if (tempadj > 1)
				{
					tempadj--;
					SetBeep(1000, 10); //蜂鸣器鸣叫一声
				}
		}
		if (GetAdcNavAct(enumAdcNavKeyUp) == enumKeyPress)
		{
			if (tempadj == 1)
			{
				a = m.hour / 16 * 10 + m.hour % 16;
				if ((++a) >= 24)
					a = 0;
				m.hour = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 2)
			{
				a = m.minute / 16 * 10 + m.minute % 16;
				if ((++a) >= 60)
					a = 0;
				m.minute = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 3)
			{
				a = m.second / 16 * 10 + m.second % 16;
				if ((++a) >= 60)
					a = 0;
				m.second = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyDown) == enumKeyPress)
		{
			if (tempadj == 1)
			{
				a = m.hour / 16 * 10 + m.hour % 16;
				if ((a--) == 0)
					a = 23;
				m.hour = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 2)
			{
				a = m.minute / 16 * 10 + m.minute % 16;
				if ((a--) == 0)
					a = 59;
				m.minute = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
			if (tempadj == 3)
			{
				a = m.second / 16 * 10 + m.second % 16;
				if ((a--) == 0)
					a = 59;
				m.second = a / 10 * 16 + a % 10;
				SetBeep(1000, 10); //蜂鸣器鸣叫一声
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyCenter) == enumKeyPress)
		{
			SetBeep(1000, 10); //蜂鸣器鸣叫一声
			if (tempadj == 0)
				tempadj = 3;
			else
			{
				tempadj = 0;
				NVM_Write(0x01, m.hour);
				NVM_Write(0x02, m.minute);
				NVM_Write(0x03, m.second);
			}
		}
		break;
	case Code:
		if (GetAdcNavAct(enumAdcNavKeyRight) == enumKeyPress)
		{
			if (tempadj)
			{
				if (tempadj == 1)
				{
					NVM_Write(0x04, c.a1);
				}
				if (tempadj == 2)
				{
					NVM_Write(0x05, c.a2);
				}
				if (tempadj == 3)
				{
					NVM_Write(0x06, c.a3);
				}
				if (tempadj == 4)
				{
					NVM_Write(0x07, c.a4);
				}
				if (tempadj == 5)
				{
					NVM_Write(0x08, c.a5);
				}
				if (tempadj == 6)
				{
					NVM_Write(0x09, c.a6);
				}
				if (tempadj == 7)
				{
					NVM_Write(0x10, c.a7);
				}
				if (tempadj == 8)
				{
					NVM_Write(0x11, c.a8);
				}
				if (tempadj < 8)
				{
					tempadj++;
					SetBeep(1000, 10); //蜂鸣器鸣叫一声
				}
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyLeft) == enumKeyPress)
		{
			if (tempadj)
			{
				if (tempadj == 1)
				{
					NVM_Write(0x04, c.a1);
				}
				if (tempadj == 2)
				{
					NVM_Write(0x05, c.a2);
				}
				if (tempadj == 3)
				{
					NVM_Write(0x06, c.a3);
				}
				if (tempadj == 4)
				{
					NVM_Write(0x07, c.a4);
				}
				if (tempadj == 5)
				{
					NVM_Write(0x08, c.a5);
				}
				if (tempadj == 6)
				{
					NVM_Write(0x09, c.a6);
				}
				if (tempadj == 7)
				{
					NVM_Write(0x10, c.a7);
				}
				if (tempadj == 8)
				{
					NVM_Write(0x11, c.a8);
				}
				if (tempadj > 1)
				{
					tempadj--;
					SetBeep(1000, 10); //蜂鸣器鸣叫一声
				}
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyUp) == enumKeyPress)
		{
			SetBeep(1000, 10); //蜂鸣器鸣叫一声
			if (tempadj == 1)
			{
				c.a1++;
				if (c.a1 == 10)
					c.a1 = 0;
			}
			if (tempadj == 2)
			{
				c.a2++;
				if (c.a2 == 10)
					c.a2 = 0;
			}
			if (tempadj == 3)
			{
				c.a3++;
				if (c.a3 == 10)
					c.a3 = 0;
			}
			if (tempadj == 4)
			{
				c.a4++;
				if (c.a4 == 10)
					c.a4 = 0;
			}
			if (tempadj == 5)
			{
				c.a5++;
				if (c.a5 == 10)
					c.a5 = 0;
			}
			if (tempadj == 6)
			{
				c.a6++;
				if (c.a6 == 10)
					c.a6 = 0;
			}
			if (tempadj == 7)
			{
				c.a7++;
				if (c.a7 == 10)
					c.a7 = 0;
			}
			if (tempadj == 8)
			{
				c.a8++;
				if (c.a8 == 10)
					c.a8 = 0;
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyDown) == enumKeyPress)
		{
			SetBeep(1000, 10); //蜂鸣器鸣叫一声
			if (tempadj == 1)
			{
				c.a1--;
				if (c.a1 == -1)
					c.a1 = 9;
			}
			if (tempadj == 2)
			{
				c.a2--;
				if (c.a2 == -1)
					c.a2 = 9;
			}
			if (tempadj == 3)
			{
				c.a3--;
				if (c.a3 == -1)
					c.a3 = 9;
			}
			if (tempadj == 4)
			{
				c.a4--;
				if (c.a4 == -1)
					c.a4 = 9;
			}
			if (tempadj == 5)
			{
				c.a5--;
				if (c.a5 == -1)
					c.a5 = 9;
			}
			if (tempadj == 6)
			{
				c.a6--;
				if (c.a6 == -1)
					c.a6 = 9;
			}
			if (tempadj == 7)
			{
				c.a7--;
				if (c.a7 == -1)
					c.a7 = 9;
			}
			if (tempadj == 8)
			{
				c.a8--;
				if (c.a8 == -1)
					c.a8 = 9;
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyCenter) == enumKeyPress)
		{
			SetBeep(1000, 10); //蜂鸣器鸣叫一声
			if (tempadj == 0)
				tempadj = 8;
			else
			{
				if (tempadj == 1)
				{
					NVM_Write(0x04, c.a1);
				}
				if (tempadj == 2)
				{
					NVM_Write(0x05, c.a2);
				}
				if (tempadj == 3)
				{
					NVM_Write(0x06, c.a3);
				}
				if (tempadj == 4)
				{
					NVM_Write(0x07, c.a4);
				}
				if (tempadj == 5)
				{
					NVM_Write(0x08, c.a5);
				}
				if (tempadj == 6)
				{
					NVM_Write(0x09, c.a6);
				}
				if (tempadj == 7)
				{
					NVM_Write(0x10, c.a7);
				}
				if (tempadj == 8)
				{
					NVM_Write(0x11, c.a8);
				}
				tempadj = 0;
			}
		}
		break;
	case Code_test:
		if (GetAdcNavAct(enumAdcNavKeyRight) == enumKeyPress)
		{
			c.a1 = NVM_Read(0x04);
			c.a2 = NVM_Read(0x05);
			c.a3 = NVM_Read(0x06);
			c.a4 = NVM_Read(0x07);
			c.a5 = NVM_Read(0x08);
			c.a6 = NVM_Read(0x09);
			c.a7 = NVM_Read(0x10);
			c.a8 = NVM_Read(0x11);
			if (tempadj == 1)
			{
				if (s_code.a1 == c.a1)
					tempadj++;
				else
				{
					s_code.a1 = 0;
					s_code.a2 = 0;
					s_code.a3 = 0;
					s_code.a4 = 0;
					s_code.a5 = 0;
					s_code.a6 = 0;
					s_code.a7 = 0;
					s_code.a8 = 0;
					tempadj = 1;
				}
			}
			else if (tempadj == 2)
			{
				if (s_code.a2 == c.a2)
					tempadj++;
				else
				{
					s_code.a1 = 0;
					s_code.a2 = 0;
					s_code.a3 = 0;
					s_code.a4 = 0;
					s_code.a5 = 0;
					s_code.a6 = 0;
					s_code.a7 = 0;
					s_code.a8 = 0;
					tempadj = 1;
				}
			}
			else if (tempadj == 3)
			{
				if (s_code.a3 == c.a3)
					tempadj++;
				else
				{
					s_code.a1 = 0;
					s_code.a2 = 0;
					s_code.a3 = 0;
					s_code.a4 = 0;
					s_code.a5 = 0;
					s_code.a6 = 0;
					s_code.a7 = 0;
					s_code.a8 = 0;
					tempadj = 1;
				}
			}
			else if (tempadj == 4)
			{
				if (s_code.a4 == c.a4)
					tempadj++;
				else
				{
					s_code.a1 = 0;
					s_code.a2 = 0;
					s_code.a3 = 0;
					s_code.a4 = 0;
					s_code.a5 = 0;
					s_code.a6 = 0;
					s_code.a7 = 0;
					s_code.a8 = 0;
					tempadj = 1;
				}
			}
			else if (tempadj == 5)
			{
				if (s_code.a5 == c.a5)
					tempadj++;
				else
				{
					s_code.a1 = 0;
					s_code.a2 = 0;
					s_code.a3 = 0;
					s_code.a4 = 0;
					s_code.a5 = 0;
					s_code.a6 = 0;
					s_code.a7 = 0;
					s_code.a8 = 0;
					tempadj = 1;
				}
			}
			else if (tempadj == 6)
			{
				if (s_code.a6 == c.a6)
					tempadj++;
				else
				{
					s_code.a1 = 0;
					s_code.a2 = 0;
					s_code.a3 = 0;
					s_code.a4 = 0;
					s_code.a5 = 0;
					s_code.a6 = 0;
					s_code.a7 = 0;
					s_code.a8 = 0;
					tempadj = 1;
				}
			}
			else if (tempadj == 7)
			{
				if (s_code.a7 == c.a7)
					tempadj++;
				else
				{
					s_code.a1 = 0;
					s_code.a2 = 0;
					s_code.a3 = 0;
					s_code.a4 = 0;
					s_code.a5 = 0;
					s_code.a6 = 0;
					s_code.a7 = 0;
					s_code.a8 = 0;
					tempadj = 1;
				}
			}
			else if (tempadj == 8)
			{
				if (s_code.a8 == c.a8)
				{
					SetPlayerMode(enumModeStop);
					tempadj = 0;
					funcmode = RTC_HMS;
				}
				else
				{
					s_code.a1 = 0;
					s_code.a2 = 0;
					s_code.a3 = 0;
					s_code.a4 = 0;
					s_code.a5 = 0;
					s_code.a6 = 0;
					s_code.a7 = 0;
					s_code.a8 = 0;
					tempadj = 1;
				}
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyUp) == enumKeyPress)
		{
			if (tempadj == 1)
			{
				s_code.a1++;
				if (s_code.a1 == 10)
					s_code.a1 = 0;
			}
			if (tempadj == 2)
			{
				s_code.a2++;
				if (s_code.a2 == 10)
					s_code.a2 = 0;
			}
			if (tempadj == 3)
			{
				s_code.a3++;
				if (s_code.a3 == 10)
					s_code.a3 = 0;
			}
			if (tempadj == 4)
			{
				s_code.a4++;
				if (s_code.a4 == 10)
					s_code.a4 = 0;
			}
			if (tempadj == 5)
			{
				s_code.a5++;
				if (s_code.a5 == 10)
					s_code.a5 = 0;
			}
			if (tempadj == 6)
			{
				s_code.a6++;
				if (s_code.a6 == 10)
					s_code.a6 = 0;
			}
			if (tempadj == 7)
			{
				s_code.a7++;
				if (s_code.a7 == 10)
					s_code.a7 = 0;
			}
			if (tempadj == 8)
			{
				s_code.a8++;
				if (s_code.a8 == 10)
					s_code.a8 = 0;
			}
		}
		if (GetAdcNavAct(enumAdcNavKeyDown) == enumKeyPress)
		{
			if (tempadj == 1)
			{
				s_code.a1--;
				if (s_code.a1 == -1)
					s_code.a1 = 9;
			}
			if (tempadj == 2)
			{
				s_code.a2--;
				if (s_code.a2 == -1)
					s_code.a2 = 9;
			}
			if (tempadj == 3)
			{
				s_code.a3--;
				if (s_code.a3 == -1)
					s_code.a3 = 9;
			}
			if (tempadj == 4)
			{
				s_code.a4--;
				if (s_code.a4 == -1)
					s_code.a4 = 9;
			}
			if (tempadj == 5)
			{
				s_code.a5--;
				if (s_code.a5 == -1)
					s_code.a5 = 9;
			}
			if (tempadj == 6)
			{
				s_code.a6--;
				if (s_code.a6 == -1)
					s_code.a6 = 9;
			}
			if (tempadj == 7)
			{
				s_code.a7--;
				if (s_code.a7 == -1)
					s_code.a7 = 9;
			}
			if (tempadj == 8)
			{
				s_code.a8--;
				if (s_code.a8 == -1)
					s_code.a8 = 9;
			}
		}
		break;
	default:
		break;
	}
}
void dealwithAlarm()
{
	if (m.hour == t.hour && m.minute == t.minute && m.second == t.second)
	{
		ADCresult = GetADC();
		if (ADCresult.Rop >= 20)
		{
			funcmode = Code_test;
			SetMusic(Music_PM, Music_tone, &song, sizeof(song), 0xF0); //初始化音乐
			SetPlayerMode(enumModePlay); //播放音乐
		}
	}
}

到了这里,关于小学期实训-智慧电子时钟的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数字IC前端学习笔记:时钟切换电路

    相关阅读 数字IC前端 https://blog.csdn.net/weixin_45791458/category_12173698.html?spm=1001.2014.3001.5482         有些时候我们需要在系统运行时切换系统时钟,最简单的方法就是使用一个MUX(数据选择器)选择输出的时钟,如下代码片所示。但这样做会导致毛刺的产生,这可能会导致寄存

    2024年02月04日
    浏览(37)
  • 硬件工程师学习-硬件的单元测试(UT)(1)电源与时钟的测试

    调试功能基本OK后,进入单元测试阶段。 单元测试,一般是指基于开发人员自行开展的功能测试及各个功能单元的单元测试,是硬件信号级的测试,分为基本测试和信号完整性测试。也被称作硬件的白盒测试。 1、单元测试开始前,全项目组人员一起学习《硬件单元测试规范

    2024年02月06日
    浏览(43)
  • 数字电路硬件设计系列(十七)之上电时序控制电路

    上电时序,也叫做Power-up Sequence,是指电源时序关系。 下面 就是一系列电源的上电的先后关系: 采用不同的电容来控制上电延时时间的长短,具体的电路见下图: 这种上电时序控制的方式, 电路结构简单 ,但是 延时时间难以精确的控制 。 在FPGA的电源时序控制中,应用十

    2024年02月12日
    浏览(46)
  • 电子技术课程设计基于FPGA的音乐硬件演奏电路的设计与实现

    【ChatGPT】前些天发现了一个巨牛的人工智能学习电子书,通俗易懂,风趣幽默,无广告,忍不住分享一下给大家。(点击查看学习资料) wx供重浩:创享日记 对话框发送:乐曲电路 免费获取完整无水印论文报告(包含电路图) 1、课程设计题目 设计一个乐曲演奏电路,能够

    2024年02月05日
    浏览(59)
  • 数字电路硬件设计系列(三)之缓启电路设计

            在一些大电压、大电流的产品中,上电的瞬间通常会有较大的电流冲击,下图是一款产品上电过程中波形。最大的电流达到14.2A,这种过流有可能损坏电子元器件。 电流过充波形 解决上述问题,通常采取的策略是在电源的入口增加 缓启动电路 ,也成为 软起动 。

    2024年02月06日
    浏览(54)
  • 数字电路硬件设计系列(十一)之CAN电路设计

    CAN通信时一种工业控制通信系统,最早时应用于汽车电子产品。CAN总线主要的特点: 传输距离远,最远可达10km。 CAN总线抗干扰能力强,有有效保证整个系统的稳定性。 CAM总线传输的速度快,理论上峰值可以达到1Mbps,能有效保证数据通信的即时性。 单条总线上,支持128个节

    2024年02月10日
    浏览(43)
  • 数字电路硬件设计系列(十八)之eMMC电路设计

    eMMC(Embedded Multi Media Card) 是 嵌入式多媒体卡 的简称,主要是针对只能手机和平板电脑特点二设计的。它的实质是在 NAND Flash的基础上增加了一个控制器,并预留了一个标准接口 。 参考设计获取方式:关注下面公众号,回复:eMMC即可。 eMMC颗粒的PIN脚主要分为三组:电源引脚、

    2024年02月10日
    浏览(72)
  • 数字电路硬件设计系列(十三)之HDMI电路设计

    原文:内容更加全面。 高清多媒体接口(High Definition Multimedia Interface,HDMI) 是一种全数字化视频和声音发送接口,可以发送未压缩的 音频 及 视频 信号。 HDMI可用于机顶盒、DVD播放机、个人计算机、电视、游戏主机、综合扩大机、数字音响与电视机等设备。HDMI可以同时发送

    2024年02月11日
    浏览(50)
  • 数字电路硬件设计系列(十二)之USB电路设计

    USB电路,在我们的平时的应用十分的广泛,常见的鼠标,键盘、显示屏的触摸功能等,对外的接口均使用的是USB接口。USB接口主要可以划分为两种: USB 2.0 、 USB 3.0 。从连接器上区分的依据是,内部颜色 白色 的为USB 2.0接口,内部颜色为 蓝色 的为USB 3.0接口(当然也不是绝对

    2024年02月14日
    浏览(76)
  • 数字电路硬件设计系列(十)之RS485电路设计

    RS485通信属于串口通信中的半双工通信,RS485具有支持多节点(32个节点)、传输距离远(最大1219m)、接收灵敏度高(200mV电压)、连接简单(在构成通信网络时,仅需要一对双绞线作传输线)、能抑制共模干扰(差分传输)、成本低廉等特点,最高的传输速率可达10Mbps。在多

    2024年02月06日
    浏览(82)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包