2024年1月8日发(作者:阚迎南)
学院名称论文提交日期
本科毕业设计
基于单片机的多功能数字时钟
负西弱
2
指导教师 XXX 讲师
工程学院
专业名称
电子信息工程
2014年4月30日
论文答辩日期
2014年5月10日
摘 要
随着数字集成电路的发展和石英晶体与振荡器的广泛应用,数字时钟的精度远远超过了老式钟表,而且能够方便地扩展钟表原先的报时功能,满足人们日常应用的各种需求,数字时钟不管在性能还是功能上都远远超过了传统的钟表。
本设计中的多功能数字时钟采用基于ARM Cortex-M3核心的32 位微控制器STM32F103RCT6作为控制系统的核心,采用内置晶振、具有标准I2C接口的实时时钟芯片SD2403API计算当前的秒、分、时、日、月、年,可保证时钟精度为+5ppm(在25℃±1℃下),通过编程配合芯片内置的数字化时间精度调整电路还可以进一步提高时钟精度,通过2.2寸TFT液晶屏的友好人机界面将结果直观地呈现给用户。为具有更高的实用价值,利用数字温湿度传感器DHT11获取温湿度,增加了温湿度显示功能;移植Fatfs文件系统读取SD卡的文件,增加了数码相框功能;通过阳历转阴历算法,实现了阴历显示;此外,还增加了红外遥控、闹钟、电子挂历、节日提醒、备忘录等功能。
关键词:Cortex-M3 STM32F103RCT6 数字时钟
The Multifunctional Digital Clock Based On Single Chip Microcomputer
Fu Dongqiang
(College of Engineering, South China Agricultural University, Guangzhou 510642, China)
Abstract: With the development and wide application of digital integrated circuits and quartz
crystal oscillators , precision digital clock is far more than the old-fashioned clocks, watches
and clocks, and can easily extend the original timekeeping features to meet the diverse needs of
everyday applications , digital clock regardless of performance or features are far more than the
traditional watches .
The design of the multi-function digital clock based on ARM Cortex-M3 core, 32-bit
microcontrollers STM32F103RCT6 as the core of the control system, with built-in crystal
oscillator , with a standard I2C interface, real-time clock chip SD2403API calculate the current
seconds , minutes, hours, day, month , year, can guarantee that the clock accuracy of +5 ppm
( at 25 ℃ ± 1 ℃), adjustment circuit programmed with chip built-in digital time accuracy
can be further improved clock accuracy , by 2.2 -inch TFT LCD screen and friendly people
machine interface will result visually presented to the user . To have a higher practical value ,
the use of digital temperature and humidity sensor DHT11 get temperature, humidity, increased
temperature and humidity display function; transplant Fatfs SD card file system reads files ,
increasing the digital photo frame function ; through Gregorian lunar transfer algorithm to
achieve a lunar display ; addition , it has added an infrared remote control , alarm clock ,
electronic calendar, festival reminders, memos and other functions.
Key words: Cortex-M3 STM32F103RCT6 digital clock
目 录
1 前言 .......................................................................................................................................... 1
1.1 设计意义 ............................................................................................................................... 1
1.2 设计内容 ............................................................................................................................... 1
2 总体方案确定 .......................................................................................................................... 2
2.1 主控芯片方案 ....................................................................................................................... 2
2.2 显示方案 ............................................................................................................................... 3
2.3 实时时钟方案 ....................................................................................................................... 3
2.4 温湿度传感器方案 ............................................................................................................... 4
2.5 图片存储方案 ....................................................................................................................... 4
3 硬件电路设计 .......................................................................................................................... 5
3.1 系统总体框图 ....................................................................................................................... 5
3.2 STM32F103RCT6最小系统设计 ......................................................................................... 5
3.3 SD2403电路图设计 .............................................................................................................. 6
3.4 DHT11电路图设计 ............................................................................................................... 7
3.5 TFT显示电路设计 ................................................................................................................ 8
3.6 SD存储卡电路设计 .............................................................................................................. 8
3.7 红外接收电路设计 ............................................................................................................... 9
4 程序设计 .................................................................................................................................. 9
4.1 系统初始化流程 ................................................................................................................. 10
4.1.1 SD卡初始化介绍 ............................................................................................................. 10
4.1.2 Fatfs文件系统介绍 .......................................................................................................... 11
4.2 时间调整程序设计 ............................................................................................................. 12
4.3 日期调整程序设计 ............................................................................................................. 14
4.4 闹钟处理程序设计 ............................................................................................................. 15
4.5 节日提醒程序设计 ............................................................................................................. 16
5 调试与调试结果 .................................................................................................................... 16
5.1 硬件调试 ............................................................................................................................. 16
5.2 调试结果 ............................................................................................................................. 17
6 结论 ........................................................................................................................................ 17
参考文献 .................................................................................................................................... 18
附录 ............................................................................................................................................ 19
附录A 设计主要电路图 .......................................................................................................... 19
附录B 主要设计程序 .............................................................................................................. 20
致谢 ............................................................................................................................................ 77
华南农业大学本科生毕业设计成绩评定表
I
1 前言
1.1 设计意义
自1975年美国德州仪器公司第一块微型计算机芯片TMS-1000问世以来,在短短的20年间,单片机技术已发展成为计算机领域一个非常有前途的分之,它有自己的技术特征、规范和应用领域。单片机是自动控制系统的核心部件,主要用于工业控制、智能化仪器仪表、家用电器等机器中。它具有体积小、性能突出可靠性高、价格低廉等优点,并且其应用领域不断扩大,除了工业控制、智能化仪表、通信、家用电器外,在智能化的高档电子玩具产品中也大量采用单片机芯片作为核心控制部件,已经渗入到人们工作和生活的每个角落,有力地推动了各行业的技术改造和产品的更新换代,前景广阔。这多功能数字钟具备单片机最小系统的基本组成,对于我们了解单片机有很大的帮助。
当今社会是一个追求快速、高效的社会,时间就是金钱因此准确的掌握时间和分配时间对人们来说至关重要。在飞速发展的单片机技术的推动下,现代的电子产品几乎渗透到了社会的各个领域,人们对时间计量的精度要求越来越高,应用越来越广。时钟不仅要更好、更方便、更精确的显示时间,还要有其它的一些实用的附加功能,这就要求人们不断设计研发出新型的时钟。所以一个能够精确计时以及有其他多种用途的时钟是对人们的生活工作是非常具有现实意义的。 由于数字集成电路的发展和石英晶体与振荡器的广泛应用,使得数字时钟的精度远远超过老式钟表,而且能够方便地扩展钟表原先的报时功能,数字时钟不管在性能还是功能上都远远超过了传统的钟表,给人们的生活带来了极大的便利。因此,对多功能数字钟进行研究有着非常现实的意义。 而且本设计还实现了电子挂历功能,在日常生活当中,一般挂历都用纸做成的,对于现今世界的环保问题有不少坏处,虽然也有一些是用可再循环的材料,但是一般的挂历基本上都是用完就扔掉,但是电子挂历则可以一直用,既能支持环保又能跟上时代。
1.2 设计内容
多功能数字时钟的基本功能就是时钟显示时分秒,年月日,闹钟。另外还根据人们日常生活需求扩展了以下几种功能:阴历、万年历、温湿度显示、红外遥控、数码相框、节日提醒。本设计以单片机STM32F103RCT6作为数字时钟的核心控制器;采用实时时钟芯片SD2403API计算当前的秒、分、时、日、月、年;通过数字温湿度传感器DHT11获取环境温湿度;使用SPI接口配合文件系统Fatfs读取SD卡文件实现数码相框和备忘录功能;并且通过软件编写,实现电子挂历、节日提醒等功能。
1
2 总体方案确定
2.1 主控芯片方案
方案一:STC89C52是一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash 存储器。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。 具有以下标准功能: 8k字节Flash,512字节RAM, 32 位I/O 口线, 看门狗定时器,内置4KB
EEPROM,MAX810复位电路,三个16 位 定时器/计数器,一个6向量2级中断结构,全双工 串行口。另外 STC89X52 可降至0Hz 静态逻辑操作,支持2种 软件可选择节电模式。空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结, 单片机一切工作停止,直到下一个中断或硬件复位为止。最高运作频率35MHz,6T/12T可选。
方案二:选用意法半导体公司推出的基于ARM CORTEX-M3内核的STM32F103RCT6微控制器。STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M3内核。按性能分成两个不同的系列:STM32F103“增强型”系列和STM32F101“基本型”系列。增强型系列时钟频率达到72MHz,是同类产品中性能最高的产品;基本型时钟频率为36MHz,以16位产品的价格得到比16位产品大幅提升的性能,是16位产品用户的最佳选择。两个系列都内置32K到128K的闪存,不同的是SRAM的最大容量和外设接口的组合。时钟频率72MHz时,从闪存执行代码,STM32功耗36mA,是32位市场上功耗最低的产品,相当于0.5mA/MHz。STM32F103RCT6属于“增强型”,其包含256KB闪存和48KB RAM,时钟频率可达72MHz,指令速度可接近80MIPS,且集成了丰富的片内外设。在芯片功耗方面,已接近MSP430超低功耗单片机水平,而且芯片价格便宜。
方案三:采用S3C2410A作为嵌入式处理芯片实现TFT液晶显示。S3C2410A的CPU内核采用的是ARM公司设计的16/32为ARM920T RISC处理器,该处理器提供了一组完整的系统外围设备,从而大大减少了整个系统的成本,省去了为系统配置额外器件的开销。
方案比较:STC89C52的片上ROM和RAM较少,而本设计的软件程序较大,需要外扩ROM和RAM;而且STC89C52的运行速度较慢,用户体验效果不好。基于S3C2410A
2
的系统硬件构建比较复杂,成本也较高。相比之下,STM32F103RCT6的系统构建比较简单,成本较低,再结合本设计对于硬件资源、功耗等方面的需求,选用方案二更合适。
2.2 显示方案
方案一:采用LED数码管动态扫描。LED数码管价格便宜,对于显示数字最合适,但功耗较大,占用体积大,且显示容量不够。
方案二:采用TFT液晶屏幕,响应速度快,一般是在40MS以下,色彩丰富有过渡感,工作稳定,除了可以显示数字和汉字外,还能显示真彩图像。
方案比较:本设计中的显示内容较多,包括了数字、汉字、图片,显然TFT液晶屏幕更符合本设计的需求,因此选择方案二。
2.3 实时时钟方案
方案一:利用STM32的RTC模块实现,RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。RTC模块和时钟配置系统(RCC_BDCR寄存器)是在后备区域,即在系统复位或从待机模式唤醒后RTC的设置和时间维持不变。当我们需要在掉电之后,又需要RTC时钟正常运行的话,单片机的VBAT脚需外接3.3V的锂电池。当我们重新上电的时候,主电源给VBAT供电,当系统掉电之后VBAT给RTC时钟工作,RTC中的数据都会保持在后备寄存器当中。
方案二:采用常用的DS1302芯片。DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后备电源双电源引脚,同时提供了对后备电源进行涓细电流充电的能力。
方案三:采用内置晶振、具有标准I2C接口的高精度国产实时时钟芯片SD2403API。SD2403API是一种内置晶振、具有标准IIC接口的实时时钟芯片,CPU可使用该接口通过5位地址寻址来读写片内32字节寄存器的数据(包括时间寄存器、报警寄存器、控制寄存器、通用SRAM寄存器);内置晶振,该芯片可保证时钟精度为±5ppm(在25℃±1℃下),
3
即年误差小于2.5分钟;具有一个后备电池输入脚VBAT,当芯片检测到主电源VDD掉到后备电池电压以下,芯片会自动转为由接在VBAT的后备电池供电。
方案比较:STM32的RTC模块工作时不稳定,受外部晶振的影响较大。DS1302的时钟精度易受外加晶振和电容的影响,而高精度的晶振和电容价格较贵。而SD2403API不需要外加晶振和电容,而且内置时钟精度数字调整功能,不需要太多设置就能保证很高的精度,因此选择方案三。
2.4 温湿度传感器方案
方案一:采用常用的温度传感器DS18B20加湿度传感器HS1101/HS1100。DS18B20,常用的温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。HS1101是法国Humirel公司推出的一款电容式相对湿度传感器。该传感器可广泛应用于办公室、家庭、汽车驾驶室、和工业过程控制系统等,对空气湿度进行检测。
方案二:采用由瑞士Sensirion推出的SHT10数字温度传感器。SHT10体积微小、响应迅速、低能耗、可浸没、抗干扰能力强、温湿一体,兼有露点测量,性价比高,使该产品能够适用于多种场合的应用。
方案三:采用常用的温湿度传感器DHT11。DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。
方案比较:采用温湿一体的传感器可以简化电路,节约成本。DHT11的价格便宜,电路简单,测量精度: 湿度±5%RH, 温度±2℃,既能满足本设计的需求,性价比又高,因此选择方案三。
2.5 图片存储方案
方案一:通过取模软件将图片的点阵信息和颜色信息提取出来并以数组形式保存,把这些数组直接放在主控芯片的片上ROM上,这样就可以不用添加外部存储器。
方案二:将图片直接保存在SD卡上,由主控芯片从SD卡中读取图片数据并完成解码,然后送往TFT液晶屏进行显示。
方案比较:虽然方案一更容易实现,但是只能显示特定的几张图片,而且需要更4
换图片时就必须要进行重新进行取模、修改代码、烧录程序等操作,缺乏灵活性。而方案二更换图片时只需要更换SD卡内的图片,不涉及程序改动,更具灵活性,因此选择方案二。
3 硬件电路设计
3.1 系统总体框图
红外模块
SD2403模块
STM32F103RCT6核心控制系统
DHT11温湿度模块
SD存储卡模块
TFT液晶显示模块块
图 1 系统总体框图
3.2 STM32F103RCT6最小系统设计
STM32F103RCT6最小系统包括晶振电路、复位电路、启动模式选择电路、SWJ接口电路、供电电路,如图2所示:
5
3.3 SD2403电路图设计
图 2 STM32F103RCT6最小系统电路图
应将VBAT脚接地,电池和主电源均通过二极管向芯片的VDD供电,如图3所示:
SD2403API内置晶振,不需要外加晶振和电容作为振荡电路,只需要为IIC引脚加上上拉电阻,并添加主电源VDD和后背电源VBAT电路。在电源设计方面,需要注意,当VDD=3.3V时 ,VBAT接3V电池会有一些问题:通常标称3V的电池在刚开始使用时电压会达到3.3V或更多,这是芯片会进入VBAT模式而读不出数据。要解决此问题,6
信息,如图4所示:
3.4 DHT11电路图设计
图 3 SD2403API电路图
主控芯片STM32F103RCT6通过单总线方式和DHT11进行通信,从而获取到温湿度图 4 DHT11电路图
7
3.5 TFT显示电路设计
本设计采用一块2.2寸的TFT液晶屏,该液晶屏采用ILI9340作为主控芯片,采用SPI通信协议,最少只需要4个IO口驱动,只需要把液晶屏的SPI引脚与主控芯片STM32F103RCT6对应的硬件SPI引脚相连即可,如图5所示:
图 5 TFT显示电路图
3.6 SD存储卡电路设计
SD卡有两种读取模式:SD方式和SPI方式。本设计中采用的是SPI方式,这样只需要把SD卡的SPI引脚与主控芯片STM32F103RCT6对应的硬件SPI引脚相连即可,如图6所示:
8
图 6 SD存储卡电路图
3.7 红外接收电路设计
本设计采用红外一体化接收头VS1838接收来自遥控器的调制信号,VS1838将调制信号转化为脉冲信号后传输给主控芯片,再由主控芯片进行软件解码,电路图如图7所示:
图 7 红外接收电路
4 程序设计
本设计的程序设计主要包括以下几个部分:1、系统初始化流程;2、时间调整程序设计;3、日期调整程序设计;4、闹钟处理程序设计; 5、节日提醒程序设计。下面会对
9
这几个部分的程序设计进行解析并附有相应的流程图。
4.1 系统初始化流程
系统初始化主要完成一下几个工作:1、主控芯片STM32F103RCT6引脚配置、中断和片上外设的初始化;2、TFT液晶屏幕的初始化;3、SD卡的初始化;4、Fatfs文件系统的初始化;5、主界面初始化。
流程图如下所示:
开始
主控芯片STM32F103RCT6初始化
TFT液晶屏初始化
SD卡
初始化
Fatfs文件系统
初始化
主界面初始化
结束
图 8 系统初始化流程图
4.1.1 SD卡初始化介绍
SD卡的初始化对于后续的Fatfs文件系统初始化和图片的显示是非常重要的,只有进行了正确的初始化,才能进行后面的各项操作。在初始化过程中,SPI的时钟不能太快(400KHz以下),否则会初始化失败。初始化成功后再提升SPI的时钟速率,以提高读取
10
文件的速度。初始化步骤如下:
(1)延时至少74个时钟,等待SD卡内部操作完成,在MMC协议中有明确说明。
(2)CS低电平选中SD卡。
(3)发送CMD0,需要返回0x01,进入Idle状态。
(4)为了区别SD卡是2.0还是1.0,或是MMC卡,这里根据协议向上兼容的原理,首先发送只有SD2.0才有的命令CMD8,如果CMD8返回无错误,则初步判断为2.0卡,进一步发送命令循环发送CMD55+ACMD41,直到返回0x00,确定SD2.0卡初始化成功,进入Ready状态,再发送CMD58命令来判断是HCSD还是SCSD,到此SD2.0卡初始化成功。如果CMD8返回错误则进一步判断为1.0卡还是MMC卡,循环发送CMD55+ACMD41,返回无错误,则为SD1.0卡,到此SD1.0卡初始成功,如果在一定的循环次数下,返回为错误,则进一步发送CMD1进行初始化,如果返回无错误,则确定为MMC卡,如果在一定的次数下,返回为错误,则不能识别该卡,初始结束。
(5)CS拉高。
(6)SPI设置到高速模式。
4.1.2 Fatfs文件系统介绍
Fatfs是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT文件系统。Fatfs的编写遵循ANSI C,因此不依赖于硬件平台。它可以嵌入到便宜的微控制器中,如 8051,
PIC, AVR, SH, Z80, H8, ARM 等等,不需要做任何修改。
FatFs 提供下面的函数:
f_mount - 注册/注销一个工作区域(Work Area)
f_open - 打开/创建一个文件f_close - 关闭一个文件
f_read - 读文件f_write - 写文件
f_lseek - 移动文件读/写指针
f_truncate - 截断文件
f_sync - 冲洗缓冲数据 Flush Cached Data
f_opendir - 打开一个目录
f_readdir - 读取目录条目
f_getfree - 获取空闲簇 Get Free Clusters
f_stat - 获取文件状态
11
f_mkdir - 创建一个目录
f_unlink - 删除一个文件或目录
f_chmod - 改变属性(Attribute)
f_utime - 改变时间戳(Timestamp)
f_rename - 重命名/移动一个文件或文件夹
f_mkfs - 在驱动器上创建一个文件系统
f_forward - 直接转移文件数据到一个数据流 Forward file data to the stream
directly
f_gets - 读一个字符串
f_putc - 写一个字符
f_puts - 写一个字符传
f_printf - 写一个格式化的字符磁盘I/O接口
Fatfs的移植:
(1)定义数据类型,修改integer.h ,使其中定义的数据类型与相应的MCU相匹配。
(2)配 置 ff.h,用户可以对应于不同的文件系统的配置,在相应的地方进行修改,ff.h文件中有详细注释,用户可以根据具体情况进行修改。
(3)最关键的一步,底层函数的修改。本系统有6个底层函数需要用户根据具体情况进行修改:
DSTATUS disk_initialize磁盘初始化,如果SD卡设置正常,直接返回0或者其他状态。
DSTATUS disk_status磁盘状态监测,可以返回0或者其他状态。
DRESULT disk_read磁盘读函数,调用SPI读单个或多个区块的函数。
DRESULT disk_write磁盘写函数,调用SPI写单个或多个区块的函数。
DRESULT disk_ioctl仅在磁盘格式化时需要,如不需要可返回0。
DWORD get_fattime RCT时间获得,具体格式可以参考具体的文献说明。
此外还需要配置4个底层函数,函数分别是主控芯片使用SPI读/写一个sector和读/写多个sector的函数。
4.2 时间调整程序设计
时间调整的主要调整程序流程为:首先按下设置键进行状态转换,进入时间设置状态12
(此时屏幕在时间下会出现下划线),然后通过左右键,就可以进行移位调整,依次能够利用上下键调整秒、分、时。当调整完所有时间后,就可以通过设置键退出时间设置状态,或者系统检测无输入按键状态超时后自动退出时间设置状态,接着就把新设置的时间更新到SD2403中。流程图如下所示:
开始
使用设置键进入时间设置状态
左右键选择需要调整的对象
上下键调整数值
使用设置键或者等待无输入状态超时退出时间设置状态
系统更新SD2403时间
结束
图 9 时间调整流程图
13
4.3 日期调整程序设计
日期调整的主要调整程序流程为:首先按下设置键进行状态转换,进入日期设置状态(此时屏幕在日期下会出现下划线),然后通过左右键,就可以进行移位调整,依次能够利用上下键调整日、月、年。当调整完所有日期后,就可以通过设置键退出日期设置状态,或者系统检测无输入按键状态超时后自动退出日期设置状态,接着就把新设置的日期更新到SD2403中。流程图如下所示:
开始
使用设置键进入日期设置状态
左右键选择需要调整的对象
上下键调整数值
使用设置键或者等待无输入状态超时退出日期设置状态
系统更新SD2403日期
结束
图 10 日期调整流程图
14
4.4 闹钟处理程序设计
闹钟处理的主要程序流程为:首先按下设置键进行状态转换,进入闹钟设置状态,可以设置闹钟的开关状态和闹钟时间。系统每过一分钟,就取当前时间与闹钟时间比较,当两者一致并且闹钟处于开启状态时,闹钟响起,按任意键取消闹钟铃响,或者等待闹钟铃响时间超时后自动关闭铃响。流程图如下所示:
开始
N
一分钟时间到?
Y
取闹钟时间,
取当前时间
两者比较
结果
相等?
Y
N
闹铃响起
结束
图 11 闹钟处理流程图
15
4.5 节日提醒程序设计
节日提醒的主要程序流程为:系统中有一个预先设置的节日表,这个表记录各个节日的日期和名称。系统日期每更新一次(手动设置或者一天时间到),就遍历这个节日表,检测明天和今天是否某个节日的日期,如果是就更新显示,屏幕显示相关节日提醒的信息。流程图如下所示:
开始
N
系统日期更新?
Y
遍历节日表
有节日需要显示?
Y
更新显示
N
结束
图 12 节日提醒流程图
5 调试与调试结果
5.1 硬件调试
在没通电之前,先用万用表检查线路的正确性,并核对元器件的型号、规格是否符合
16
要求。首要检查的电源的正负极有没有接反以及电源之间有没有短路,各电源之间需要共VCC并且所有的地线需要共地。然后再检查各个模块的线路是否有短路、断路的情况出现,另外晶体振荡器和电容应尽可能靠近单片机芯片安装,以减少寄生电容,更好是保证振荡器稳定和可靠地工作。经过仔细全面的排查,本设计确保了电路的正确的焊接,能为接下来的通电调试提供很大的方便。
接上+5V电源后,分别测量各点电位是否正常。在断电的情况下,除单片机以外,用仿真插头将所连接电路与单片机仿真器的仿真接口相连,为软件调试做好准备。
在硬件调试的过程中,存在的主要问题是,为了增加设计的可重用性和可维护性,很多器件都做成了可插拔的形式,有些器件可能会存在接触不好的情况,影响了电路的调试。
5.2 调试结果
首先调试出TFT液晶显示,方便观看其他各项调试结果。其次调试SD2403模块、DHT11温湿度模块、SD存储卡模块、红外模块,保证这些模块能够被正常初始化成功,与主控芯片间的通信正常。最后再逐一对各个功能进行调试,通过TFT液晶显示查看实际效果是否与预期的一样。经过调试,发现各个硬件模块都能正常工作,各个功能的实际效果与预期的一致,并且在TFT液晶显示屏中显示出来,实现了设计所要功能,
6 结论
本次毕业设计收获良多,完成了毕业设计的要求,利用SD2403API时钟芯片实现了时间显示时、分、秒,年、月、日与星期的基本功能,并且能够进行时间调整,同时根据我们中国人的使用习惯,增加了阴历的显示。另外还外加了一些扩展功能,比如:电子挂历、温湿度显示、红外遥控、数码相框、节日提醒、备忘录等,大大增加了设计的实用性。
本设计虽然完成了基本功能,且有扩展,但是还有许多可以完善的地方。如可以增加语音报时,用于定点报时,更加方便人们对时间的掌握;如可以增加MP3播放功能,用于设置闹铃类型或者平时听音乐,更加方便于日常生活。
17
参 考 文 献
王卫星,邓小玲,代芬,等.单片机原理与应用开发技术[M].北京:中国水利水电出版社,2013:1-14.
罗建军,朱丹军,顾刚,等.C++程序设计教程[M].北京:高等教育出版社,2007:110-114.
刘火良,杨森.STM32库开发实战指南[M].北京:机械工业出版社,2013:240-277.
[英] Joseph Yiu. ARM Cortex-M3权威指南[M].北京: 北京航空航天大学出版社,2013:132-134.
张涛,左谨平,马华玲.FatFs在32位微控制器STM32上的移植[J].电子技术,2013,3:25-26.
徐建功, 赵捷,李伟,等.基于STM32F103XX微处理器的Micro SD卡读写[J].现代电子技术,2013,20:26-28.
杨河理,熊晓东.电子万年历中公历农历互换算法研究[J].长江大学学报(自科版)理工卷,2013,4:86-88.
凌志斌,邓超平,郑益慧,等.红外遥控技术及其解码方案[J].微处理机,2013,6:59-63.
郭小芳,佘明辉.基于单片机的多功能数字钟系统设计与分析[J].电子技术,2012,6:35-40.
18
附录A 设计主要电路图
附 录
19
附录B 主要设计程序
--******************************文件开始******************************
** 文件名称: Main.c
** 最后修改日期: 2014/4/28
** 功能描述: 主函数
*******************************************************************--
#include "stm32f10x.h"
#include "GPIO_Config.h"
#include "SPI.h"
#include "NVIC_Config.h"
#include "TIM67.H"
#include "SysTick_Delay_Period.h"
#include "./GUI/TFTSPI.h"
#include "./Time/Time.h"
#include "./Calendar/Calendar.h"
#include "./Calendar/Gregorian2Lunar.h"
#include "./Calendar/HolidayRemind.h"
#include "./DHT11/DHT11.H"
#include "./FatFS_R0.10/ff.h"
#include "./spi_sd/stm32_eval_spi_sd.h"
#include "./Infrared/Infrared.h"
#include "./Control/Control.h"
#include "./SD2403/SD2403.H"
#include
/* Global variables ---------------------------------------------------------*/
uint8_t strTime[] = "23:59:55";
uint8_t strDate[] = "2014-04-13";
uint8_t strAlarm[] = "*12:30";
uint8_t Key_Value;
uint8_t u8NumOfPic;
//按键值和红外接收码
//可供显示的图片数量
20
extern uint32_t uiSetStatusTimes; //统计设置状态处于设定状态却没有按键输入的时间
extern uint8_t uiTempSecLow;
秒钟时间到
extern uint8_t uiTempMinuteLow; //如果这个变量和时间的分钟低位不同,则说明一分钟时间到
extern uint8_t uiTempBCDDay;
间到
extern uint8_t uiAlarmOnOff;
extern uint32_t uiAlarmTimes;
//0-闹钟响,1-闹钟没响
//统计闹钟已经响的时间
//如果这个变量BCD_Day不同,则说明一天时 //如果这个变量和时间的秒低位不同,则说明一extern enum {SET_IDLE,SET_TIME,SET_DATE,SET_ALARM}eSetStatus;
extern
{SET_TIMEIDLE,SET_SECOND,SET_MINUTE,SET_HOUR}eSetTimeStatus;
extern enum {SET_YEAR,SET_MONTH,SET_DAY}eSetDateStatus;
int main()
{
SD_Error status;
FATFS fs;
FILINFO finfo;
DIR dir;
FRESULT res;
uint8_t uiGetTemHumTime; //保存上一次获取温湿度的分钟值,默认enum
每分钟更新一次
/* Vector Table is in RAM at 0x0 */
// NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
NVIC_Config();
GPIO_Config();
SPI1_Config();
21
SysTick_Conf();
TFTSPI_Init();
/*初始化通用定时器TIM2作为PWM输出,并启动定时器2*/
TIMx_PWMOutConf();
TIM_Cmd(TIM2,ENABLE);
TIM67_Conf();
TFTSPI_Clear(LCD_COLOR_MAGENTA);
/*禁止输出PWM*/
TIM_CCxCmd(TIM2,TIM_Channel_3,DISABLE);
TFTSPI_Write_CharString(XPOS_HOLIDAYREMIND,YPOS_HOLIDAYREMIND_TO/*初始化SD卡配置*/
status = SD_Init();
if(status != SD_RESPONSE_NO_ERROR)
{
//while(1);
TFTSPI_SetFont(&Font12x12);
TFTSPI_SetColors(LCD_COLOR_RED,LCD_COLOR_WHITE);
DAY,"SD Error");
}
/*设置到高速模式*/
SD_SPI_SetSpeed(SPI_SPEED_4);
/*初始化文件系统环境*/
res = f_mount(&fs ,"0:", 0);
if(res != FR_OK)
22
{
//while(1);
TFTSPI_SetFont(&Font12x12);
TFTSPI_SetColors(LCD_COLOR_RED,LCD_COLOR_WHITE);
TFTSPI_Write_CharString(XPOS_HOLIDAYREMIND,YPOS_HOLIDAYREMIND_TODAY,"Fatfs Error");
文件夹
/*变量初始化*/
DHT11_GetResult();//开机先获取温湿度
}
}
{
}
u8NumOfPic++;
/*统计可供显示的图片数量,要求Pic文件夹下只能存放符合规格的图片*/
u8NumOfPic = 0;
if(f_opendir(&dir,"/Pic") == FR_OK) //打开文件夹
{
while (f_readdir(&dir, &finfo) == FR_OK) //按照顺序读文件夹
{
if(0==[0]) break; //如果文件名为0,结束
if(b == AM_ARC) //判断文件属性,只处理非}
SD2403_Read_Date();//开机先获取SD2403存储的时间
strTime[SECOND_LOW] = (BCD_Second&0x0F)+'0';
strTime[SECOND_HIGH] = ((BCD_Second&0xF0)>>4)+'0';
23
strTime[MINUTE_LOW] = (BCD_Minute&0x0F)+'0';
strTime[MINUTE_HIGH] = ((BCD_Minute&0xF0)>>4)+'0';
strTime[HOUR_LOW] = (BCD_Hour&0x0F)+0x30;
strTime[HOUR_HIGH] = ((BCD_Hour&0x70)>>4)+'0';
strDate[DAY_LOW] = (BCD_Day&0x0F)+'0';
strDate[DAY_HIGH] = ((BCD_Day&0xF0)>>4)+'0';
strDate[MONTH_LOW] = (BCD_Month&0x0F)+'0';
strDate[MONTH_HIGH] = ((BCD_Month&0xF0)>>4)+'0';
strDate[YEAR0] = (BCD_Year&0x0F)+'0';
strDate[YEAR1] = ((BCD_Year&0xF0)>>4)+'0';
uiYear = 2000+((BCD_Year&0xF0)>>4)*10+(BCD_Year&0x0F);
uiMonth = ((BCD_Month&0xF0)>>4)*10+(BCD_Month&0x0F);
uiDay = ((BCD_Day&0xF0)>>4)*10+(BCD_Day&0x0F);
if(2==uiMonth)
{
}
else
{
}
uiMaxDay = iDaysOfYear[uiMonth-1];
uiMaxDay = iDaysOfYear[uiMonth-1]+is_leapyear(uiYear);
uiUnderline = 0;
uiLengthPreUnderline = 0;
Key_Value = 0;
uiAlarmOnOff = 0;
uiAlarmTimes = 0;
uiTempSecLow = strTime[SECOND_LOW];
uiTempMinuteLow = strTime[MINUTE_LOW];
24
uiTempBCDDay = BCD_Day;
/*显示挂历*/
print_year_month(uiYear,uiMonth);
week_of_today(iWeekOfMonth,uiDay);
Dis_Calendar_Pic = 0;
/*填充时间、日期、星期、农历、温度和湿度的背景色(统一为白色背景)*/
Fill_Rect(XPOS_STRTIME-2,YPOS_STRTIME-2,XPOS_STRALARM+12*6,YPOS_STRWEEK+16+2,LCD_COLOR_BLACK,MAIN_BACK_COLOR);
/*显示时间和日期*/
TFTSPI_SetFont(&Font16x24);
TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
TFTSPI_Write_CharString(XPOS_STRTIME,YPOS_STRTIME,strTime);
TFTSPI_Write_CharString(XPOS_STRDATE,YPOS_STRDATE,strDate);
/*显示周几*/
TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
TFTSPI_SetArea(XPOS_STRWEEK,YPOS_STRWEEK);
TFTSPI_Draw_ChFont((uint8_t
*)GB_Font16x16_MyChFontTable+(MyChFont_Zhou)*16*2);//显示“周”字
TFTSPI_SetArea(XPOS_STRWEEK+16,YPOS_STRWEEK);
TFTSPI_Draw_ChFont((uint8_t
*)GB_Font16x16_MyChFontTable+(MyChFont_Zero+iWeekOfToday%7)*16*2);//显示“周(几)”字
/*显示农历*/
Conversion(strDate[YEAR3]-'0'-1,((strDate[YEAR1]-'0')<<4) |
| (strDate[YEAR0]-'0'),((strDate[MONTH_HIGH]-'0')<<4)
(strDate[MONTH_LOW]-'0'),((strDate[DAY_HIGH]-'0')<<4) | (strDate[DAY_LOW]-'0'));
25
Print_Lunar(month_moon,day_moon);
/*显示温度和湿度*/
Print_Tem_Hum(DHT11_Temp,DHT11_Hump);
uiGetTemHumTime = strTime[MINUTE_LOW]; //保存上一次获取温湿度的分钟值,默认每分钟更新一次
/*使能TIM6计数*/
/*节日提醒*/
holiday_remind();
/*显示闹钟*/
TFTSPI_SetFont(&Font12x12);
TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
TFTSPI_Write_CharString(XPOS_STRALARM,YPOS_STRALARM,strAlarm);
TIM_Cmd(TIM6,ENABLE);
26
while(1)
{
/*检测是否一秒时间已经到了*/
if(uiTempSecLow != strTime[SECOND_LOW])
{
uiTempSecLow = strTime[SECOND_LOW];
/*显示时间*/
TFTSPI_SetFont(&Font16x24);
TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
TFTSPI_Write_CharString(XPOS_STRTIME,YPOS_STRTIME,strTime);
/*统计设置状态处于设定状态却没有按键输入的时间*/
if(SET_IDLE!=eSetStatus)
{
uiSetStatusTimes++;
if(SET_TIMEOUT==uiSetStatusTimes)//设置状态处于设定状态SET_TIMEOUTs内没有按键输入就自动退出设置状态
/*清除上一次的下划线(线的颜色用填充色)*/
if(0!=uiLengthPreUnderline)
{
{
uiSetStatusTimes = 0;
eSetStatus = SET_IDLE;
eSetTimeStatus = SET_TIMEIDLE;
Draw_Horizontal_Line(uiXposPreUnderline,uiYposPreUnderline,0,uiLengthPreUnderline,MAIN_BACK_COLOR);
}
}
}
uiLengthPreUnderline = 0;
uiUnderline = 0;
/*一天的时间到了*/
if(uiTempBCDDay != BCD_Day)
{
uiTempBCDDay = BCD_Day;
/*显示日期*/
TFTSPI_SetFont(&Font16x24);
27
TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
TFTSPI_Write_CharString(XPOS_STRDATE,YPOS_STRDATE,strDate);
/*重新计算星期并显示挂历*/
/*判断是否要更新挂历显示*/
if(0==Dis_Calendar_Pic)
{
print_year_month(uiYear,uiMonth);//没有重新运行该函数就要运行以下函数更新星期
}
else
{
/*如果运行了print_year_month就不用再运行这三个函数*/
iWeekOfNewYear = week_of_newyear(uiYear);
iIsLeapYear = is_leapyear(uiYear);
iWeekOfMonth =
week_of_month(iWeekOfNewYear,iIsLeapYear,uiMonth);
week_of_today(iWeekOfMonth,uiDay);
TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE);
TFTSPI_SetArea(XPOS_STRWEEK,YPOS_STRWEEK);
TFTSPI_Draw_ChFont((uint8_t
}
*)GB_Font16x16_MyChFontTable+(MyChFont_Zhou)*16*2);//显示“周”字
TFTSPI_SetArea(XPOS_STRWEEK+16,YPOS_STRWEEK);
TFTSPI_Draw_ChFont((uint8_t
*)GB_Font16x16_MyChFontTable+(MyChFont_Zero+iWeekOfToday%7)*16*2);//显示“周(几)”字
/*重新计算并显示农历*/
28
/*显示农历*/
Conversion(strDate[YEAR3]-'0'-1,((strDate[YEAR1]-'0')<<4) |
| (strDate[YEAR0]-'0'),((strDate[MONTH_HIGH]-'0')<<4)
(strDate[MONTH_LOW]-'0'),((strDate[DAY_HIGH]-'0')<<4) | (strDate[DAY_LOW]-'0'));
Print_Lunar(month_moon,day_moon);
}
}
/*节日提醒*/
holiday_remind();
Key_Value = Check_IR();
if(0x00!=Key_Value)
{
Key_Handle();
}
/*闹钟响了,任意键按停闹钟*/
if(1==uiAlarmOnOff)
{
}
uiAlarmOnOff = 0;
uiAlarmTimes = 0;
/*禁止输出PWM*/
TIM_CCxCmd(TIM2,TIM_Channel_3,DISABLE);
while(0x00!=Key_Value); //等待按键被处理
/*更新温湿度*/
if(uiGetTemHumTime != strTime[MINUTE_LOW])
29
{
TIM_Cmd(TIM6,DISABLE);//DHT11时序要求比较严格,所以先暂停一下定时器
}
--******************************文件开始******************************
** 文件名称: HolidayRemind.c
** 最后修改日期: 2014/4/28
** 功能描述: 节假日提醒相关函数实现
*******************************************************************--
}
}
DHT11_GetResult();
TIM_Cmd(TIM6,ENABLE);//重新启动定时器
Print_Tem_Hum(DHT11_Temp,DHT11_Hump);
uiGetTemHumTime = strTime[MINUTE_LOW];
return 1;
#include "HolidayRemind.h"
#include "Calendar.h"
#include "Gregorian2Lunar.h"
#include "../GUI/TFTSPI.h"
#include "../SD2403/SD2403.H"
/*公历节日表*/
const stHoliday stGregorianHoliday[]=
{
{0x0101,{MyChFont_Yuan,MyChFont_Dan}},
{0x0214,{MyChFont_Qing2,MyChFont_Ren}},
{0x0308,{MyChFont_Fu,MyChFont_Nv}},
//元旦
//情人
//妇女
//植树
//劳动
{0x0312,{MyChFont_Zhi,MyChFont_Shu}},
{0x0501,{MyChFont_Lao,MyChFont_Dong}},
30
{0x0504,{MyChFont_Qingn,MyChFont_Nian2}},
{0x0601,{MyChFont_Er,MyChFont_Tong}},
{0x0701,{MyChFont_Jian,MyChFont_Dang}},
{0x0801,{MyChFont_Jian,MyChFont_Jun}},
{0x0910,{MyChFont_Jiao,MyChFont_Shi1}},
//青年
//儿童
//建党
//建军
//教师
//国庆 {0x1001,{MyChFont_Guo,MyChFont_Qing4}}
};
/*阴历节日表*/
const stHoliday stLunarHoliday[]=
{
{0x0101,{MyChFont_Blank,MyChFont_Chun}},
{0x0115,{MyChFont_Yuan,MyChFont_Xiao}},
//春节
//元宵
//端午
//七夕
//中秋
//重阳
//腊八
{0x0505,{MyChFont_Duan,MyChFont_Wu}},
{0x0707,{MyChFont_Zero+7,MyChFont_Xi}},
{0x0815,{MyChFont_Zhong,MyChFont_Qiu}},
};
{0x0909,{MyChFont_Chong,MyChFont_Yang}},
{0x1208,{MyChFont_La,MyChFont_Zero+8}}
uint16_t u16TommorrwRemindFlag=0;//是否已经有明天节日提示显示
uint16_t u16TodayRemindFlag=0;//是否已经有今天节日提示显示
void holiday_remind()
{
uint16_t uiTextColor,uiBackColor,uiTempXpos,uiTempYpos,u16Temp;
sFONT *Prefonts;
uint16_t u16GregorianBCDMonDay; //公历月日BCD码
uint16_t u16LunarMonDay;
31
//阴历月日
BCD码
uint16_t u16NumOfHolidays,tempNum;
uint8_t u8BCDmonth,u8BCDday;
uint16_t u16MyChFontTablePos0=0xffff,u16MyChFontTablePos1=0xffff;//记录待显示节日名称字模数组的位置
/*检查明天是否有阴历节日*/
if(12==month_moon && 30==day_moon) //阴历/*保存当前颜色和字体*/
TFTSPI_GetColors(&uiTextColor,&uiBackColor);
Prefonts = TFTSPI_GetFont();
节日主要就一个春节会涉及月份进位问题
{
u8BCDmonth = 0x01;
u8BCDday = 0x01;
u16LunarMonDay = (u8BCDmonth<<8) | u8BCDday;
}
else
{
u8BCDmonth = ((month_moon/10)<<4) | (month_moon%10);
u8BCDday = (((day_moon+1)/10)<<4) | ((day_moon+1)%10);
u16LunarMonDay = (u8BCDmonth<<8) | u8BCDday;
}
u16NumOfHolidays = sizeof(stLunarHoliday)/sizeof(stHoliday);
for(tempNum = 0; tempNum { if(u16LunarMonDay==stLunarHoliday[tempNum].m_u16BCDMonDay) { u16MyChFontTablePos0 32 = stLunarHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos0; u16MyChFontTablePos1 stLunarHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos1; break; } } /*检查明天是否有公历节日*/ if(uiDay+1>uiMaxDay) { if(uiMonth+1>12) { u8BCDmonth = 0x01; = } else { u8BCDmonth = (((uiMonth+1)/10)<<4) | ((uiMonth+1)%10); } u8BCDday = 0x01; } else { u8BCDmonth = ((uiMonth/10)<<4) | (uiMonth%10); u8BCDday = (((uiDay+1)/10)<<4) | ((uiDay+1)%10); } u16GregorianBCDMonDay = (u8BCDmonth<<8) | u8BCDday; u16NumOfHolidays = sizeof(stGregorianHoliday)/sizeof(stHoliday); for(tempNum = 0; tempNum { if(u16GregorianBCDMonDay==stGregorianHoliday[tempNum].m_u16BCDMonDay) 33 { u16MyChFontTablePos0 stGregorianHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos0; u16MyChFontTablePos1 stGregorianHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos1; break; } } if(0xffff!=u16MyChFontTablePos0) { TFTSPI_SetFont(&Font16x16_MyChFont); TFTSPI_SetColors(LCD_COLOR_BLACK,MAIN_BACK_COLOR); u16TommorrwRemindFlag =1; uiTempXpos = XPOS_HOLIDAYREMIND; uiTempYpos = YPOS_HOLIDAYREMIND_TOMORROW; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t = = *)GB_Font16x16_MyChFontTable+(MyChFont_Ming)*16*2);//显示“明”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Tian)*16*2);//显示“天”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Shi4)*16*2);//显示“是”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(u16MyChFontTablePos0)*16*2);//显示*#节的“*”字 34 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(u16MyChFontTablePos1)*16*2);//显示*#节的“#”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Jie)*16*2);//显示“节”字 } else if(0!=u16TommorrwRemindFlag) { /*清除明天节日提醒信息*/ TFTSPI_SetFont(&Font16x16_MyChFont); TFTSPI_SetColors(LCD_COLOR_BLACK,CLEAR_BACK_COLOR); u16TommorrwRemindFlag = 0; uiTempXpos = XPOS_HOLIDAYREMIND; uiTempYpos = YPOS_HOLIDAYREMIND_TOMORROW; for(u16Temp=0;u16Temp<6;u16Temp++) { TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Blank)*16*2);//显示“ ”字 u16MyChFontTablePos0=0xffff; u16MyChFontTablePos1=0xffff; } } uiTempXpos += 16; /*检查今天是否有阴历节日*/ u8BCDmonth = ((month_moon/10)<<4) | (month_moon%10); 35 u8BCDday = ((day_moon/10)<<4) | (day_moon%10); u16LunarMonDay = (u8BCDmonth<<8) | u8BCDday; u16NumOfHolidays = sizeof(stLunarHoliday)/sizeof(stHoliday); for(tempNum = 0; tempNum { if(u16LunarMonDay==stLunarHoliday[tempNum].m_u16BCDMonDay) { u16MyChFontTablePos0 stLunarHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos0; u16MyChFontTablePos1 stLunarHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos1; break; } } /*检查今天是否有公历节日*/ u8BCDmonth = ((uiMonth/10)<<4) | (uiMonth%10); u8BCDday = ((uiDay/10)<<4) | (uiDay%10); u16GregorianBCDMonDay = (u8BCDmonth<<8) | u8BCDday; u16NumOfHolidays = sizeof(stGregorianHoliday)/sizeof(stHoliday); for(tempNum = 0; tempNum { if(u16GregorianBCDMonDay==stGregorianHoliday[tempNum].m_u16BCDMonDay) { u16MyChFontTablePos0 stGregorianHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos0; u16MyChFontTablePos1 stGregorianHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos1; break; } 36 = = = = } if(0xffff!=u16MyChFontTablePos0) { TFTSPI_SetFont(&Font16x16_MyChFont); TFTSPI_SetColors(LCD_COLOR_BLACK,MAIN_BACK_COLOR); u16TodayRemindFlag =1; uiTempXpos = XPOS_HOLIDAYREMIND; uiTempYpos = YPOS_HOLIDAYREMIND_TODAY; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Jin)*16*2);//显示“今”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Tian)*16*2);//显示“天”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Shi4)*16*2);//显示“是”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(u16MyChFontTablePos0)*16*2);//显示*#节的“*”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(u16MyChFontTablePos1)*16*2);//显示*#节的“#”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t 37 *)GB_Font16x16_MyChFontTable+(MyChFont_Jie)*16*2);//显示“节”字 } else if(0!=u16TodayRemindFlag) { /*清除今天节日提醒信息*/ TFTSPI_SetFont(&Font16x16_MyChFont); TFTSPI_SetColors(LCD_COLOR_BLACK,CLEAR_BACK_COLOR); u16TodayRemindFlag = 0; uiTempXpos = XPOS_HOLIDAYREMIND; uiTempYpos = YPOS_HOLIDAYREMIND_TODAY; for(u16Temp=0;u16Temp<6;u16Temp++) { TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Blank)*16*2);//显示“ ”字 } --******************************文件开始****************************** ** 文件名称: Control.c ** 最后修改日期: 2014/4/28 ** 功能描述: 按键处理和状态转换 *******************************************************************-- } } uiTempXpos += 16; /*恢复当前颜色和字体*/ TFTSPI_SetColors(uiTextColor,uiBackColor); TFTSPI_SetFont(Prefonts); #include "Control.h" #include "../GUI/TFTSPI.h" #include "../Time/Time.h" 38 #include "../Infrared/Infrared.h" #include "../Calendar/Calendar.h" #include "../Calendar/Gregorian2Lunar.h" #include "../Calendar/HolidayRemind.h" #include "../SD2403/SD2403.H" #include "../GUI/draw_bmp.h" #include "../FatFS_R0.10/ff.h" /*全局变量*/ enum {SET_IDLE,SET_TIME,SET_DATE,SET_ALARM}eSetStatus; enum {SET_TIMEIDLE,SET_SECOND,SET_MINUTE,SET_HOUR}eSetTimeStatus; enum {SET_AONOFF,SET_AMINUTE,SET_AHOUR}eSetAlarmStatus; enum {SET_YEAR,SET_MONTH,SET_DAY}eSetDateStatus; uint32_t uiUnderline; //记录时间、日期、闹钟是否有下划线,0没有,1时间有,2日期有,3闹钟有 uint32_t uiXposPreUnderline,uiYposPreUnderline,uiLengthPreUnderline;//记录上一次下划线的位置和长度(清除用) uint8_t Dis_Calendar_Pic; 挂历,1图片 extern uint8_t Key_Value,IR_Rec; extern uint8_t u8NumOfPic; extern uint8_t strTime[]; extern uint8_t strDate[]; extern uint8_t strAlarm[]; extern uint32_t uiSetStatusTimes; //统计设置状态处于设定状态却没有按键输入的时间 /* * 函数名:Draw_Time_Underline * 描述 :为当前设置时间增加下划线 39 //记录当前是在显示挂历还是图片,0 //按键值和红外接收码 //可供显示的图片数量 * 输入 :右移0,左移1,不移2 * 返回 :无 */ void Draw_Time_Underline(uint32_t HV) { uint16_t uiXpos,uiYpos,uiLength; switch(eSetTimeStatus) { case SET_TIMEIDLE: { if(0==HV) { } else if(1==HV) { } eSetTimeStatus = SET_MINUTE; eSetTimeStatus = SET_HOUR; }break; case SET_SECOND: { if(0==HV) { } else if(1==HV) { eSetTimeStatus = SET_MINUTE; 40 eSetTimeStatus = SET_HOUR; } }break; case SET_MINUTE: { if(0==HV) { } else if(1==HV) { } eSetTimeStatus = SET_HOUR; eSetTimeStatus = SET_SECOND; }break; case SET_HOUR: { if(0==HV) { } else if(1==HV) { } eSetTimeStatus = SET_SECOND; eSetTimeStatus = SET_MINUTE; }break; default: { break; 41 } } switch(eSetTimeStatus) { case SET_TIMEIDLE: case SET_SECOND: { uiXpos = XPOS_STRTIME+16*6; uiYpos = YPOS_STRTIME+24+1; uiLength = 16*2; }break; case SET_MINUTE: { uiXpos = XPOS_STRTIME+16*3; uiYpos = YPOS_STRTIME+24+1; uiLength = 16*2; }break; case SET_HOUR: { uiXpos = XPOS_STRTIME; uiYpos = YPOS_STRTIME+24+1; uiLength = 16*2; }break; default: { break; 42 } } /*清除上一次的下划线(线的颜色用填充色)*/ if(0!=uiLengthPreUnderline) { Draw_Horizontal_Line(uiXposPreUnderline,uiYposPreUnderline,0,uiLengthPreUnderline,MAIN_BACK_COLOR); } /* * 函数名:Draw_Date_Underline * 描述 :为当前设置日期增加下划线 * 输入 :右移0,左移1,不移2 * 返回 :无 */ void Draw_Date_Underline(uint32_t HV) { 43 } /*画下划线*/ Draw_Horizontal_Line(uiXpos,uiYpos,0,uiLength,LCD_COLOR_BLACK); /*记录该次所画下划线信息*/ uiXposPreUnderline = uiXpos; uiYposPreUnderline = uiYpos; uiLengthPreUnderline = uiLength; uint16_t uiXpos,uiYpos,uiLength; switch(eSetDateStatus) { case SET_YEAR: { if(0==HV) { } else if(1==HV) { } eSetDateStatus = SET_DAY; eSetDateStatus = SET_MONTH; }break; case SET_MONTH: { if(0==HV) { } else if(1==HV) { } eSetDateStatus = SET_YEAR; eSetDateStatus = SET_DAY; }break; case SET_DAY: { if(0==HV) { 44 } eSetDateStatus = SET_YEAR; else if(1==HV) { } eSetDateStatus = SET_MONTH; }break; } default: { } break; switch(eSetDateStatus) { case SET_YEAR: { uiXpos = XPOS_STRDATE; uiYpos = YPOS_STRDATE+24+1; uiLength = 16*4; }break; case SET_MONTH: { uiXpos = XPOS_STRDATE+16*5; uiYpos = YPOS_STRDATE+24+1; uiLength = 16*2; }break; 45 2024年1月8日发(作者:阚迎南) 学院名称论文提交日期 本科毕业设计 基于单片机的多功能数字时钟 负西弱 2 指导教师 XXX 讲师 工程学院 专业名称 电子信息工程 2014年4月30日 论文答辩日期 2014年5月10日 摘 要 随着数字集成电路的发展和石英晶体与振荡器的广泛应用,数字时钟的精度远远超过了老式钟表,而且能够方便地扩展钟表原先的报时功能,满足人们日常应用的各种需求,数字时钟不管在性能还是功能上都远远超过了传统的钟表。 本设计中的多功能数字时钟采用基于ARM Cortex-M3核心的32 位微控制器STM32F103RCT6作为控制系统的核心,采用内置晶振、具有标准I2C接口的实时时钟芯片SD2403API计算当前的秒、分、时、日、月、年,可保证时钟精度为+5ppm(在25℃±1℃下),通过编程配合芯片内置的数字化时间精度调整电路还可以进一步提高时钟精度,通过2.2寸TFT液晶屏的友好人机界面将结果直观地呈现给用户。为具有更高的实用价值,利用数字温湿度传感器DHT11获取温湿度,增加了温湿度显示功能;移植Fatfs文件系统读取SD卡的文件,增加了数码相框功能;通过阳历转阴历算法,实现了阴历显示;此外,还增加了红外遥控、闹钟、电子挂历、节日提醒、备忘录等功能。 关键词:Cortex-M3 STM32F103RCT6 数字时钟 The Multifunctional Digital Clock Based On Single Chip Microcomputer Fu Dongqiang (College of Engineering, South China Agricultural University, Guangzhou 510642, China) Abstract: With the development and wide application of digital integrated circuits and quartz crystal oscillators , precision digital clock is far more than the old-fashioned clocks, watches and clocks, and can easily extend the original timekeeping features to meet the diverse needs of everyday applications , digital clock regardless of performance or features are far more than the traditional watches . The design of the multi-function digital clock based on ARM Cortex-M3 core, 32-bit microcontrollers STM32F103RCT6 as the core of the control system, with built-in crystal oscillator , with a standard I2C interface, real-time clock chip SD2403API calculate the current seconds , minutes, hours, day, month , year, can guarantee that the clock accuracy of +5 ppm ( at 25 ℃ ± 1 ℃), adjustment circuit programmed with chip built-in digital time accuracy can be further improved clock accuracy , by 2.2 -inch TFT LCD screen and friendly people machine interface will result visually presented to the user . To have a higher practical value , the use of digital temperature and humidity sensor DHT11 get temperature, humidity, increased temperature and humidity display function; transplant Fatfs SD card file system reads files , increasing the digital photo frame function ; through Gregorian lunar transfer algorithm to achieve a lunar display ; addition , it has added an infrared remote control , alarm clock , electronic calendar, festival reminders, memos and other functions. Key words: Cortex-M3 STM32F103RCT6 digital clock 目 录 1 前言 .......................................................................................................................................... 1 1.1 设计意义 ............................................................................................................................... 1 1.2 设计内容 ............................................................................................................................... 1 2 总体方案确定 .......................................................................................................................... 2 2.1 主控芯片方案 ....................................................................................................................... 2 2.2 显示方案 ............................................................................................................................... 3 2.3 实时时钟方案 ....................................................................................................................... 3 2.4 温湿度传感器方案 ............................................................................................................... 4 2.5 图片存储方案 ....................................................................................................................... 4 3 硬件电路设计 .......................................................................................................................... 5 3.1 系统总体框图 ....................................................................................................................... 5 3.2 STM32F103RCT6最小系统设计 ......................................................................................... 5 3.3 SD2403电路图设计 .............................................................................................................. 6 3.4 DHT11电路图设计 ............................................................................................................... 7 3.5 TFT显示电路设计 ................................................................................................................ 8 3.6 SD存储卡电路设计 .............................................................................................................. 8 3.7 红外接收电路设计 ............................................................................................................... 9 4 程序设计 .................................................................................................................................. 9 4.1 系统初始化流程 ................................................................................................................. 10 4.1.1 SD卡初始化介绍 ............................................................................................................. 10 4.1.2 Fatfs文件系统介绍 .......................................................................................................... 11 4.2 时间调整程序设计 ............................................................................................................. 12 4.3 日期调整程序设计 ............................................................................................................. 14 4.4 闹钟处理程序设计 ............................................................................................................. 15 4.5 节日提醒程序设计 ............................................................................................................. 16 5 调试与调试结果 .................................................................................................................... 16 5.1 硬件调试 ............................................................................................................................. 16 5.2 调试结果 ............................................................................................................................. 17 6 结论 ........................................................................................................................................ 17 参考文献 .................................................................................................................................... 18 附录 ............................................................................................................................................ 19 附录A 设计主要电路图 .......................................................................................................... 19 附录B 主要设计程序 .............................................................................................................. 20 致谢 ............................................................................................................................................ 77 华南农业大学本科生毕业设计成绩评定表 I 1 前言 1.1 设计意义 自1975年美国德州仪器公司第一块微型计算机芯片TMS-1000问世以来,在短短的20年间,单片机技术已发展成为计算机领域一个非常有前途的分之,它有自己的技术特征、规范和应用领域。单片机是自动控制系统的核心部件,主要用于工业控制、智能化仪器仪表、家用电器等机器中。它具有体积小、性能突出可靠性高、价格低廉等优点,并且其应用领域不断扩大,除了工业控制、智能化仪表、通信、家用电器外,在智能化的高档电子玩具产品中也大量采用单片机芯片作为核心控制部件,已经渗入到人们工作和生活的每个角落,有力地推动了各行业的技术改造和产品的更新换代,前景广阔。这多功能数字钟具备单片机最小系统的基本组成,对于我们了解单片机有很大的帮助。 当今社会是一个追求快速、高效的社会,时间就是金钱因此准确的掌握时间和分配时间对人们来说至关重要。在飞速发展的单片机技术的推动下,现代的电子产品几乎渗透到了社会的各个领域,人们对时间计量的精度要求越来越高,应用越来越广。时钟不仅要更好、更方便、更精确的显示时间,还要有其它的一些实用的附加功能,这就要求人们不断设计研发出新型的时钟。所以一个能够精确计时以及有其他多种用途的时钟是对人们的生活工作是非常具有现实意义的。 由于数字集成电路的发展和石英晶体与振荡器的广泛应用,使得数字时钟的精度远远超过老式钟表,而且能够方便地扩展钟表原先的报时功能,数字时钟不管在性能还是功能上都远远超过了传统的钟表,给人们的生活带来了极大的便利。因此,对多功能数字钟进行研究有着非常现实的意义。 而且本设计还实现了电子挂历功能,在日常生活当中,一般挂历都用纸做成的,对于现今世界的环保问题有不少坏处,虽然也有一些是用可再循环的材料,但是一般的挂历基本上都是用完就扔掉,但是电子挂历则可以一直用,既能支持环保又能跟上时代。 1.2 设计内容 多功能数字时钟的基本功能就是时钟显示时分秒,年月日,闹钟。另外还根据人们日常生活需求扩展了以下几种功能:阴历、万年历、温湿度显示、红外遥控、数码相框、节日提醒。本设计以单片机STM32F103RCT6作为数字时钟的核心控制器;采用实时时钟芯片SD2403API计算当前的秒、分、时、日、月、年;通过数字温湿度传感器DHT11获取环境温湿度;使用SPI接口配合文件系统Fatfs读取SD卡文件实现数码相框和备忘录功能;并且通过软件编写,实现电子挂历、节日提醒等功能。 1 2 总体方案确定 2.1 主控芯片方案 方案一:STC89C52是一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash 存储器。在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。 具有以下标准功能: 8k字节Flash,512字节RAM, 32 位I/O 口线, 看门狗定时器,内置4KB EEPROM,MAX810复位电路,三个16 位 定时器/计数器,一个6向量2级中断结构,全双工 串行口。另外 STC89X52 可降至0Hz 静态逻辑操作,支持2种 软件可选择节电模式。空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。掉电保护方式下,RAM内容被保存,振荡器被冻结, 单片机一切工作停止,直到下一个中断或硬件复位为止。最高运作频率35MHz,6T/12T可选。 方案二:选用意法半导体公司推出的基于ARM CORTEX-M3内核的STM32F103RCT6微控制器。STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M3内核。按性能分成两个不同的系列:STM32F103“增强型”系列和STM32F101“基本型”系列。增强型系列时钟频率达到72MHz,是同类产品中性能最高的产品;基本型时钟频率为36MHz,以16位产品的价格得到比16位产品大幅提升的性能,是16位产品用户的最佳选择。两个系列都内置32K到128K的闪存,不同的是SRAM的最大容量和外设接口的组合。时钟频率72MHz时,从闪存执行代码,STM32功耗36mA,是32位市场上功耗最低的产品,相当于0.5mA/MHz。STM32F103RCT6属于“增强型”,其包含256KB闪存和48KB RAM,时钟频率可达72MHz,指令速度可接近80MIPS,且集成了丰富的片内外设。在芯片功耗方面,已接近MSP430超低功耗单片机水平,而且芯片价格便宜。 方案三:采用S3C2410A作为嵌入式处理芯片实现TFT液晶显示。S3C2410A的CPU内核采用的是ARM公司设计的16/32为ARM920T RISC处理器,该处理器提供了一组完整的系统外围设备,从而大大减少了整个系统的成本,省去了为系统配置额外器件的开销。 方案比较:STC89C52的片上ROM和RAM较少,而本设计的软件程序较大,需要外扩ROM和RAM;而且STC89C52的运行速度较慢,用户体验效果不好。基于S3C2410A 2 的系统硬件构建比较复杂,成本也较高。相比之下,STM32F103RCT6的系统构建比较简单,成本较低,再结合本设计对于硬件资源、功耗等方面的需求,选用方案二更合适。 2.2 显示方案 方案一:采用LED数码管动态扫描。LED数码管价格便宜,对于显示数字最合适,但功耗较大,占用体积大,且显示容量不够。 方案二:采用TFT液晶屏幕,响应速度快,一般是在40MS以下,色彩丰富有过渡感,工作稳定,除了可以显示数字和汉字外,还能显示真彩图像。 方案比较:本设计中的显示内容较多,包括了数字、汉字、图片,显然TFT液晶屏幕更符合本设计的需求,因此选择方案二。 2.3 实时时钟方案 方案一:利用STM32的RTC模块实现,RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。RTC模块和时钟配置系统(RCC_BDCR寄存器)是在后备区域,即在系统复位或从待机模式唤醒后RTC的设置和时间维持不变。当我们需要在掉电之后,又需要RTC时钟正常运行的话,单片机的VBAT脚需外接3.3V的锂电池。当我们重新上电的时候,主电源给VBAT供电,当系统掉电之后VBAT给RTC时钟工作,RTC中的数据都会保持在后备寄存器当中。 方案二:采用常用的DS1302芯片。DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周日、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.5V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后备电源双电源引脚,同时提供了对后备电源进行涓细电流充电的能力。 方案三:采用内置晶振、具有标准I2C接口的高精度国产实时时钟芯片SD2403API。SD2403API是一种内置晶振、具有标准IIC接口的实时时钟芯片,CPU可使用该接口通过5位地址寻址来读写片内32字节寄存器的数据(包括时间寄存器、报警寄存器、控制寄存器、通用SRAM寄存器);内置晶振,该芯片可保证时钟精度为±5ppm(在25℃±1℃下), 3 即年误差小于2.5分钟;具有一个后备电池输入脚VBAT,当芯片检测到主电源VDD掉到后备电池电压以下,芯片会自动转为由接在VBAT的后备电池供电。 方案比较:STM32的RTC模块工作时不稳定,受外部晶振的影响较大。DS1302的时钟精度易受外加晶振和电容的影响,而高精度的晶振和电容价格较贵。而SD2403API不需要外加晶振和电容,而且内置时钟精度数字调整功能,不需要太多设置就能保证很高的精度,因此选择方案三。 2.4 温湿度传感器方案 方案一:采用常用的温度传感器DS18B20加湿度传感器HS1101/HS1100。DS18B20,常用的温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。HS1101是法国Humirel公司推出的一款电容式相对湿度传感器。该传感器可广泛应用于办公室、家庭、汽车驾驶室、和工业过程控制系统等,对空气湿度进行检测。 方案二:采用由瑞士Sensirion推出的SHT10数字温度传感器。SHT10体积微小、响应迅速、低能耗、可浸没、抗干扰能力强、温湿一体,兼有露点测量,性价比高,使该产品能够适用于多种场合的应用。 方案三:采用常用的温湿度传感器DHT11。DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器,它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。因此该产品具有品质卓越、超快响应、抗干扰能力强、性价比极高等优点。 方案比较:采用温湿一体的传感器可以简化电路,节约成本。DHT11的价格便宜,电路简单,测量精度: 湿度±5%RH, 温度±2℃,既能满足本设计的需求,性价比又高,因此选择方案三。 2.5 图片存储方案 方案一:通过取模软件将图片的点阵信息和颜色信息提取出来并以数组形式保存,把这些数组直接放在主控芯片的片上ROM上,这样就可以不用添加外部存储器。 方案二:将图片直接保存在SD卡上,由主控芯片从SD卡中读取图片数据并完成解码,然后送往TFT液晶屏进行显示。 方案比较:虽然方案一更容易实现,但是只能显示特定的几张图片,而且需要更4 换图片时就必须要进行重新进行取模、修改代码、烧录程序等操作,缺乏灵活性。而方案二更换图片时只需要更换SD卡内的图片,不涉及程序改动,更具灵活性,因此选择方案二。 3 硬件电路设计 3.1 系统总体框图 红外模块 SD2403模块 STM32F103RCT6核心控制系统 DHT11温湿度模块 SD存储卡模块 TFT液晶显示模块块 图 1 系统总体框图 3.2 STM32F103RCT6最小系统设计 STM32F103RCT6最小系统包括晶振电路、复位电路、启动模式选择电路、SWJ接口电路、供电电路,如图2所示: 5 3.3 SD2403电路图设计 图 2 STM32F103RCT6最小系统电路图 应将VBAT脚接地,电池和主电源均通过二极管向芯片的VDD供电,如图3所示: SD2403API内置晶振,不需要外加晶振和电容作为振荡电路,只需要为IIC引脚加上上拉电阻,并添加主电源VDD和后背电源VBAT电路。在电源设计方面,需要注意,当VDD=3.3V时 ,VBAT接3V电池会有一些问题:通常标称3V的电池在刚开始使用时电压会达到3.3V或更多,这是芯片会进入VBAT模式而读不出数据。要解决此问题,6 信息,如图4所示: 3.4 DHT11电路图设计 图 3 SD2403API电路图 主控芯片STM32F103RCT6通过单总线方式和DHT11进行通信,从而获取到温湿度图 4 DHT11电路图 7 3.5 TFT显示电路设计 本设计采用一块2.2寸的TFT液晶屏,该液晶屏采用ILI9340作为主控芯片,采用SPI通信协议,最少只需要4个IO口驱动,只需要把液晶屏的SPI引脚与主控芯片STM32F103RCT6对应的硬件SPI引脚相连即可,如图5所示: 图 5 TFT显示电路图 3.6 SD存储卡电路设计 SD卡有两种读取模式:SD方式和SPI方式。本设计中采用的是SPI方式,这样只需要把SD卡的SPI引脚与主控芯片STM32F103RCT6对应的硬件SPI引脚相连即可,如图6所示: 8 图 6 SD存储卡电路图 3.7 红外接收电路设计 本设计采用红外一体化接收头VS1838接收来自遥控器的调制信号,VS1838将调制信号转化为脉冲信号后传输给主控芯片,再由主控芯片进行软件解码,电路图如图7所示: 图 7 红外接收电路 4 程序设计 本设计的程序设计主要包括以下几个部分:1、系统初始化流程;2、时间调整程序设计;3、日期调整程序设计;4、闹钟处理程序设计; 5、节日提醒程序设计。下面会对 9 这几个部分的程序设计进行解析并附有相应的流程图。 4.1 系统初始化流程 系统初始化主要完成一下几个工作:1、主控芯片STM32F103RCT6引脚配置、中断和片上外设的初始化;2、TFT液晶屏幕的初始化;3、SD卡的初始化;4、Fatfs文件系统的初始化;5、主界面初始化。 流程图如下所示: 开始 主控芯片STM32F103RCT6初始化 TFT液晶屏初始化 SD卡 初始化 Fatfs文件系统 初始化 主界面初始化 结束 图 8 系统初始化流程图 4.1.1 SD卡初始化介绍 SD卡的初始化对于后续的Fatfs文件系统初始化和图片的显示是非常重要的,只有进行了正确的初始化,才能进行后面的各项操作。在初始化过程中,SPI的时钟不能太快(400KHz以下),否则会初始化失败。初始化成功后再提升SPI的时钟速率,以提高读取 10 文件的速度。初始化步骤如下: (1)延时至少74个时钟,等待SD卡内部操作完成,在MMC协议中有明确说明。 (2)CS低电平选中SD卡。 (3)发送CMD0,需要返回0x01,进入Idle状态。 (4)为了区别SD卡是2.0还是1.0,或是MMC卡,这里根据协议向上兼容的原理,首先发送只有SD2.0才有的命令CMD8,如果CMD8返回无错误,则初步判断为2.0卡,进一步发送命令循环发送CMD55+ACMD41,直到返回0x00,确定SD2.0卡初始化成功,进入Ready状态,再发送CMD58命令来判断是HCSD还是SCSD,到此SD2.0卡初始化成功。如果CMD8返回错误则进一步判断为1.0卡还是MMC卡,循环发送CMD55+ACMD41,返回无错误,则为SD1.0卡,到此SD1.0卡初始成功,如果在一定的循环次数下,返回为错误,则进一步发送CMD1进行初始化,如果返回无错误,则确定为MMC卡,如果在一定的次数下,返回为错误,则不能识别该卡,初始结束。 (5)CS拉高。 (6)SPI设置到高速模式。 4.1.2 Fatfs文件系统介绍 Fatfs是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT文件系统。Fatfs的编写遵循ANSI C,因此不依赖于硬件平台。它可以嵌入到便宜的微控制器中,如 8051, PIC, AVR, SH, Z80, H8, ARM 等等,不需要做任何修改。 FatFs 提供下面的函数: f_mount - 注册/注销一个工作区域(Work Area) f_open - 打开/创建一个文件f_close - 关闭一个文件 f_read - 读文件f_write - 写文件 f_lseek - 移动文件读/写指针 f_truncate - 截断文件 f_sync - 冲洗缓冲数据 Flush Cached Data f_opendir - 打开一个目录 f_readdir - 读取目录条目 f_getfree - 获取空闲簇 Get Free Clusters f_stat - 获取文件状态 11 f_mkdir - 创建一个目录 f_unlink - 删除一个文件或目录 f_chmod - 改变属性(Attribute) f_utime - 改变时间戳(Timestamp) f_rename - 重命名/移动一个文件或文件夹 f_mkfs - 在驱动器上创建一个文件系统 f_forward - 直接转移文件数据到一个数据流 Forward file data to the stream directly f_gets - 读一个字符串 f_putc - 写一个字符 f_puts - 写一个字符传 f_printf - 写一个格式化的字符磁盘I/O接口 Fatfs的移植: (1)定义数据类型,修改integer.h ,使其中定义的数据类型与相应的MCU相匹配。 (2)配 置 ff.h,用户可以对应于不同的文件系统的配置,在相应的地方进行修改,ff.h文件中有详细注释,用户可以根据具体情况进行修改。 (3)最关键的一步,底层函数的修改。本系统有6个底层函数需要用户根据具体情况进行修改: DSTATUS disk_initialize磁盘初始化,如果SD卡设置正常,直接返回0或者其他状态。 DSTATUS disk_status磁盘状态监测,可以返回0或者其他状态。 DRESULT disk_read磁盘读函数,调用SPI读单个或多个区块的函数。 DRESULT disk_write磁盘写函数,调用SPI写单个或多个区块的函数。 DRESULT disk_ioctl仅在磁盘格式化时需要,如不需要可返回0。 DWORD get_fattime RCT时间获得,具体格式可以参考具体的文献说明。 此外还需要配置4个底层函数,函数分别是主控芯片使用SPI读/写一个sector和读/写多个sector的函数。 4.2 时间调整程序设计 时间调整的主要调整程序流程为:首先按下设置键进行状态转换,进入时间设置状态12 (此时屏幕在时间下会出现下划线),然后通过左右键,就可以进行移位调整,依次能够利用上下键调整秒、分、时。当调整完所有时间后,就可以通过设置键退出时间设置状态,或者系统检测无输入按键状态超时后自动退出时间设置状态,接着就把新设置的时间更新到SD2403中。流程图如下所示: 开始 使用设置键进入时间设置状态 左右键选择需要调整的对象 上下键调整数值 使用设置键或者等待无输入状态超时退出时间设置状态 系统更新SD2403时间 结束 图 9 时间调整流程图 13 4.3 日期调整程序设计 日期调整的主要调整程序流程为:首先按下设置键进行状态转换,进入日期设置状态(此时屏幕在日期下会出现下划线),然后通过左右键,就可以进行移位调整,依次能够利用上下键调整日、月、年。当调整完所有日期后,就可以通过设置键退出日期设置状态,或者系统检测无输入按键状态超时后自动退出日期设置状态,接着就把新设置的日期更新到SD2403中。流程图如下所示: 开始 使用设置键进入日期设置状态 左右键选择需要调整的对象 上下键调整数值 使用设置键或者等待无输入状态超时退出日期设置状态 系统更新SD2403日期 结束 图 10 日期调整流程图 14 4.4 闹钟处理程序设计 闹钟处理的主要程序流程为:首先按下设置键进行状态转换,进入闹钟设置状态,可以设置闹钟的开关状态和闹钟时间。系统每过一分钟,就取当前时间与闹钟时间比较,当两者一致并且闹钟处于开启状态时,闹钟响起,按任意键取消闹钟铃响,或者等待闹钟铃响时间超时后自动关闭铃响。流程图如下所示: 开始 N 一分钟时间到? Y 取闹钟时间, 取当前时间 两者比较 结果 相等? Y N 闹铃响起 结束 图 11 闹钟处理流程图 15 4.5 节日提醒程序设计 节日提醒的主要程序流程为:系统中有一个预先设置的节日表,这个表记录各个节日的日期和名称。系统日期每更新一次(手动设置或者一天时间到),就遍历这个节日表,检测明天和今天是否某个节日的日期,如果是就更新显示,屏幕显示相关节日提醒的信息。流程图如下所示: 开始 N 系统日期更新? Y 遍历节日表 有节日需要显示? Y 更新显示 N 结束 图 12 节日提醒流程图 5 调试与调试结果 5.1 硬件调试 在没通电之前,先用万用表检查线路的正确性,并核对元器件的型号、规格是否符合 16 要求。首要检查的电源的正负极有没有接反以及电源之间有没有短路,各电源之间需要共VCC并且所有的地线需要共地。然后再检查各个模块的线路是否有短路、断路的情况出现,另外晶体振荡器和电容应尽可能靠近单片机芯片安装,以减少寄生电容,更好是保证振荡器稳定和可靠地工作。经过仔细全面的排查,本设计确保了电路的正确的焊接,能为接下来的通电调试提供很大的方便。 接上+5V电源后,分别测量各点电位是否正常。在断电的情况下,除单片机以外,用仿真插头将所连接电路与单片机仿真器的仿真接口相连,为软件调试做好准备。 在硬件调试的过程中,存在的主要问题是,为了增加设计的可重用性和可维护性,很多器件都做成了可插拔的形式,有些器件可能会存在接触不好的情况,影响了电路的调试。 5.2 调试结果 首先调试出TFT液晶显示,方便观看其他各项调试结果。其次调试SD2403模块、DHT11温湿度模块、SD存储卡模块、红外模块,保证这些模块能够被正常初始化成功,与主控芯片间的通信正常。最后再逐一对各个功能进行调试,通过TFT液晶显示查看实际效果是否与预期的一样。经过调试,发现各个硬件模块都能正常工作,各个功能的实际效果与预期的一致,并且在TFT液晶显示屏中显示出来,实现了设计所要功能, 6 结论 本次毕业设计收获良多,完成了毕业设计的要求,利用SD2403API时钟芯片实现了时间显示时、分、秒,年、月、日与星期的基本功能,并且能够进行时间调整,同时根据我们中国人的使用习惯,增加了阴历的显示。另外还外加了一些扩展功能,比如:电子挂历、温湿度显示、红外遥控、数码相框、节日提醒、备忘录等,大大增加了设计的实用性。 本设计虽然完成了基本功能,且有扩展,但是还有许多可以完善的地方。如可以增加语音报时,用于定点报时,更加方便人们对时间的掌握;如可以增加MP3播放功能,用于设置闹铃类型或者平时听音乐,更加方便于日常生活。 17 参 考 文 献 王卫星,邓小玲,代芬,等.单片机原理与应用开发技术[M].北京:中国水利水电出版社,2013:1-14. 罗建军,朱丹军,顾刚,等.C++程序设计教程[M].北京:高等教育出版社,2007:110-114. 刘火良,杨森.STM32库开发实战指南[M].北京:机械工业出版社,2013:240-277. [英] Joseph Yiu. ARM Cortex-M3权威指南[M].北京: 北京航空航天大学出版社,2013:132-134. 张涛,左谨平,马华玲.FatFs在32位微控制器STM32上的移植[J].电子技术,2013,3:25-26. 徐建功, 赵捷,李伟,等.基于STM32F103XX微处理器的Micro SD卡读写[J].现代电子技术,2013,20:26-28. 杨河理,熊晓东.电子万年历中公历农历互换算法研究[J].长江大学学报(自科版)理工卷,2013,4:86-88. 凌志斌,邓超平,郑益慧,等.红外遥控技术及其解码方案[J].微处理机,2013,6:59-63. 郭小芳,佘明辉.基于单片机的多功能数字钟系统设计与分析[J].电子技术,2012,6:35-40. 18 附录A 设计主要电路图 附 录 19 附录B 主要设计程序 --******************************文件开始****************************** ** 文件名称: Main.c ** 最后修改日期: 2014/4/28 ** 功能描述: 主函数 *******************************************************************-- #include "stm32f10x.h" #include "GPIO_Config.h" #include "SPI.h" #include "NVIC_Config.h" #include "TIM67.H" #include "SysTick_Delay_Period.h" #include "./GUI/TFTSPI.h" #include "./Time/Time.h" #include "./Calendar/Calendar.h" #include "./Calendar/Gregorian2Lunar.h" #include "./Calendar/HolidayRemind.h" #include "./DHT11/DHT11.H" #include "./FatFS_R0.10/ff.h" #include "./spi_sd/stm32_eval_spi_sd.h" #include "./Infrared/Infrared.h" #include "./Control/Control.h" #include "./SD2403/SD2403.H" #include /* Global variables ---------------------------------------------------------*/ uint8_t strTime[] = "23:59:55"; uint8_t strDate[] = "2014-04-13"; uint8_t strAlarm[] = "*12:30"; uint8_t Key_Value; uint8_t u8NumOfPic; //按键值和红外接收码 //可供显示的图片数量 20 extern uint32_t uiSetStatusTimes; //统计设置状态处于设定状态却没有按键输入的时间 extern uint8_t uiTempSecLow; 秒钟时间到 extern uint8_t uiTempMinuteLow; //如果这个变量和时间的分钟低位不同,则说明一分钟时间到 extern uint8_t uiTempBCDDay; 间到 extern uint8_t uiAlarmOnOff; extern uint32_t uiAlarmTimes; //0-闹钟响,1-闹钟没响 //统计闹钟已经响的时间 //如果这个变量BCD_Day不同,则说明一天时 //如果这个变量和时间的秒低位不同,则说明一extern enum {SET_IDLE,SET_TIME,SET_DATE,SET_ALARM}eSetStatus; extern {SET_TIMEIDLE,SET_SECOND,SET_MINUTE,SET_HOUR}eSetTimeStatus; extern enum {SET_YEAR,SET_MONTH,SET_DAY}eSetDateStatus; int main() { SD_Error status; FATFS fs; FILINFO finfo; DIR dir; FRESULT res; uint8_t uiGetTemHumTime; //保存上一次获取温湿度的分钟值,默认enum 每分钟更新一次 /* Vector Table is in RAM at 0x0 */ // NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); NVIC_Config(); GPIO_Config(); SPI1_Config(); 21 SysTick_Conf(); TFTSPI_Init(); /*初始化通用定时器TIM2作为PWM输出,并启动定时器2*/ TIMx_PWMOutConf(); TIM_Cmd(TIM2,ENABLE); TIM67_Conf(); TFTSPI_Clear(LCD_COLOR_MAGENTA); /*禁止输出PWM*/ TIM_CCxCmd(TIM2,TIM_Channel_3,DISABLE); TFTSPI_Write_CharString(XPOS_HOLIDAYREMIND,YPOS_HOLIDAYREMIND_TO/*初始化SD卡配置*/ status = SD_Init(); if(status != SD_RESPONSE_NO_ERROR) { //while(1); TFTSPI_SetFont(&Font12x12); TFTSPI_SetColors(LCD_COLOR_RED,LCD_COLOR_WHITE); DAY,"SD Error"); } /*设置到高速模式*/ SD_SPI_SetSpeed(SPI_SPEED_4); /*初始化文件系统环境*/ res = f_mount(&fs ,"0:", 0); if(res != FR_OK) 22 { //while(1); TFTSPI_SetFont(&Font12x12); TFTSPI_SetColors(LCD_COLOR_RED,LCD_COLOR_WHITE); TFTSPI_Write_CharString(XPOS_HOLIDAYREMIND,YPOS_HOLIDAYREMIND_TODAY,"Fatfs Error"); 文件夹 /*变量初始化*/ DHT11_GetResult();//开机先获取温湿度 } } { } u8NumOfPic++; /*统计可供显示的图片数量,要求Pic文件夹下只能存放符合规格的图片*/ u8NumOfPic = 0; if(f_opendir(&dir,"/Pic") == FR_OK) //打开文件夹 { while (f_readdir(&dir, &finfo) == FR_OK) //按照顺序读文件夹 { if(0==[0]) break; //如果文件名为0,结束 if(b == AM_ARC) //判断文件属性,只处理非} SD2403_Read_Date();//开机先获取SD2403存储的时间 strTime[SECOND_LOW] = (BCD_Second&0x0F)+'0'; strTime[SECOND_HIGH] = ((BCD_Second&0xF0)>>4)+'0'; 23 strTime[MINUTE_LOW] = (BCD_Minute&0x0F)+'0'; strTime[MINUTE_HIGH] = ((BCD_Minute&0xF0)>>4)+'0'; strTime[HOUR_LOW] = (BCD_Hour&0x0F)+0x30; strTime[HOUR_HIGH] = ((BCD_Hour&0x70)>>4)+'0'; strDate[DAY_LOW] = (BCD_Day&0x0F)+'0'; strDate[DAY_HIGH] = ((BCD_Day&0xF0)>>4)+'0'; strDate[MONTH_LOW] = (BCD_Month&0x0F)+'0'; strDate[MONTH_HIGH] = ((BCD_Month&0xF0)>>4)+'0'; strDate[YEAR0] = (BCD_Year&0x0F)+'0'; strDate[YEAR1] = ((BCD_Year&0xF0)>>4)+'0'; uiYear = 2000+((BCD_Year&0xF0)>>4)*10+(BCD_Year&0x0F); uiMonth = ((BCD_Month&0xF0)>>4)*10+(BCD_Month&0x0F); uiDay = ((BCD_Day&0xF0)>>4)*10+(BCD_Day&0x0F); if(2==uiMonth) { } else { } uiMaxDay = iDaysOfYear[uiMonth-1]; uiMaxDay = iDaysOfYear[uiMonth-1]+is_leapyear(uiYear); uiUnderline = 0; uiLengthPreUnderline = 0; Key_Value = 0; uiAlarmOnOff = 0; uiAlarmTimes = 0; uiTempSecLow = strTime[SECOND_LOW]; uiTempMinuteLow = strTime[MINUTE_LOW]; 24 uiTempBCDDay = BCD_Day; /*显示挂历*/ print_year_month(uiYear,uiMonth); week_of_today(iWeekOfMonth,uiDay); Dis_Calendar_Pic = 0; /*填充时间、日期、星期、农历、温度和湿度的背景色(统一为白色背景)*/ Fill_Rect(XPOS_STRTIME-2,YPOS_STRTIME-2,XPOS_STRALARM+12*6,YPOS_STRWEEK+16+2,LCD_COLOR_BLACK,MAIN_BACK_COLOR); /*显示时间和日期*/ TFTSPI_SetFont(&Font16x24); TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE); TFTSPI_Write_CharString(XPOS_STRTIME,YPOS_STRTIME,strTime); TFTSPI_Write_CharString(XPOS_STRDATE,YPOS_STRDATE,strDate); /*显示周几*/ TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE); TFTSPI_SetArea(XPOS_STRWEEK,YPOS_STRWEEK); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Zhou)*16*2);//显示“周”字 TFTSPI_SetArea(XPOS_STRWEEK+16,YPOS_STRWEEK); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Zero+iWeekOfToday%7)*16*2);//显示“周(几)”字 /*显示农历*/ Conversion(strDate[YEAR3]-'0'-1,((strDate[YEAR1]-'0')<<4) | | (strDate[YEAR0]-'0'),((strDate[MONTH_HIGH]-'0')<<4) (strDate[MONTH_LOW]-'0'),((strDate[DAY_HIGH]-'0')<<4) | (strDate[DAY_LOW]-'0')); 25 Print_Lunar(month_moon,day_moon); /*显示温度和湿度*/ Print_Tem_Hum(DHT11_Temp,DHT11_Hump); uiGetTemHumTime = strTime[MINUTE_LOW]; //保存上一次获取温湿度的分钟值,默认每分钟更新一次 /*使能TIM6计数*/ /*节日提醒*/ holiday_remind(); /*显示闹钟*/ TFTSPI_SetFont(&Font12x12); TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE); TFTSPI_Write_CharString(XPOS_STRALARM,YPOS_STRALARM,strAlarm); TIM_Cmd(TIM6,ENABLE); 26 while(1) { /*检测是否一秒时间已经到了*/ if(uiTempSecLow != strTime[SECOND_LOW]) { uiTempSecLow = strTime[SECOND_LOW]; /*显示时间*/ TFTSPI_SetFont(&Font16x24); TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE); TFTSPI_Write_CharString(XPOS_STRTIME,YPOS_STRTIME,strTime); /*统计设置状态处于设定状态却没有按键输入的时间*/ if(SET_IDLE!=eSetStatus) { uiSetStatusTimes++; if(SET_TIMEOUT==uiSetStatusTimes)//设置状态处于设定状态SET_TIMEOUTs内没有按键输入就自动退出设置状态 /*清除上一次的下划线(线的颜色用填充色)*/ if(0!=uiLengthPreUnderline) { { uiSetStatusTimes = 0; eSetStatus = SET_IDLE; eSetTimeStatus = SET_TIMEIDLE; Draw_Horizontal_Line(uiXposPreUnderline,uiYposPreUnderline,0,uiLengthPreUnderline,MAIN_BACK_COLOR); } } } uiLengthPreUnderline = 0; uiUnderline = 0; /*一天的时间到了*/ if(uiTempBCDDay != BCD_Day) { uiTempBCDDay = BCD_Day; /*显示日期*/ TFTSPI_SetFont(&Font16x24); 27 TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE); TFTSPI_Write_CharString(XPOS_STRDATE,YPOS_STRDATE,strDate); /*重新计算星期并显示挂历*/ /*判断是否要更新挂历显示*/ if(0==Dis_Calendar_Pic) { print_year_month(uiYear,uiMonth);//没有重新运行该函数就要运行以下函数更新星期 } else { /*如果运行了print_year_month就不用再运行这三个函数*/ iWeekOfNewYear = week_of_newyear(uiYear); iIsLeapYear = is_leapyear(uiYear); iWeekOfMonth = week_of_month(iWeekOfNewYear,iIsLeapYear,uiMonth); week_of_today(iWeekOfMonth,uiDay); TFTSPI_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE); TFTSPI_SetArea(XPOS_STRWEEK,YPOS_STRWEEK); TFTSPI_Draw_ChFont((uint8_t } *)GB_Font16x16_MyChFontTable+(MyChFont_Zhou)*16*2);//显示“周”字 TFTSPI_SetArea(XPOS_STRWEEK+16,YPOS_STRWEEK); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Zero+iWeekOfToday%7)*16*2);//显示“周(几)”字 /*重新计算并显示农历*/ 28 /*显示农历*/ Conversion(strDate[YEAR3]-'0'-1,((strDate[YEAR1]-'0')<<4) | | (strDate[YEAR0]-'0'),((strDate[MONTH_HIGH]-'0')<<4) (strDate[MONTH_LOW]-'0'),((strDate[DAY_HIGH]-'0')<<4) | (strDate[DAY_LOW]-'0')); Print_Lunar(month_moon,day_moon); } } /*节日提醒*/ holiday_remind(); Key_Value = Check_IR(); if(0x00!=Key_Value) { Key_Handle(); } /*闹钟响了,任意键按停闹钟*/ if(1==uiAlarmOnOff) { } uiAlarmOnOff = 0; uiAlarmTimes = 0; /*禁止输出PWM*/ TIM_CCxCmd(TIM2,TIM_Channel_3,DISABLE); while(0x00!=Key_Value); //等待按键被处理 /*更新温湿度*/ if(uiGetTemHumTime != strTime[MINUTE_LOW]) 29 { TIM_Cmd(TIM6,DISABLE);//DHT11时序要求比较严格,所以先暂停一下定时器 } --******************************文件开始****************************** ** 文件名称: HolidayRemind.c ** 最后修改日期: 2014/4/28 ** 功能描述: 节假日提醒相关函数实现 *******************************************************************-- } } DHT11_GetResult(); TIM_Cmd(TIM6,ENABLE);//重新启动定时器 Print_Tem_Hum(DHT11_Temp,DHT11_Hump); uiGetTemHumTime = strTime[MINUTE_LOW]; return 1; #include "HolidayRemind.h" #include "Calendar.h" #include "Gregorian2Lunar.h" #include "../GUI/TFTSPI.h" #include "../SD2403/SD2403.H" /*公历节日表*/ const stHoliday stGregorianHoliday[]= { {0x0101,{MyChFont_Yuan,MyChFont_Dan}}, {0x0214,{MyChFont_Qing2,MyChFont_Ren}}, {0x0308,{MyChFont_Fu,MyChFont_Nv}}, //元旦 //情人 //妇女 //植树 //劳动 {0x0312,{MyChFont_Zhi,MyChFont_Shu}}, {0x0501,{MyChFont_Lao,MyChFont_Dong}}, 30 {0x0504,{MyChFont_Qingn,MyChFont_Nian2}}, {0x0601,{MyChFont_Er,MyChFont_Tong}}, {0x0701,{MyChFont_Jian,MyChFont_Dang}}, {0x0801,{MyChFont_Jian,MyChFont_Jun}}, {0x0910,{MyChFont_Jiao,MyChFont_Shi1}}, //青年 //儿童 //建党 //建军 //教师 //国庆 {0x1001,{MyChFont_Guo,MyChFont_Qing4}} }; /*阴历节日表*/ const stHoliday stLunarHoliday[]= { {0x0101,{MyChFont_Blank,MyChFont_Chun}}, {0x0115,{MyChFont_Yuan,MyChFont_Xiao}}, //春节 //元宵 //端午 //七夕 //中秋 //重阳 //腊八 {0x0505,{MyChFont_Duan,MyChFont_Wu}}, {0x0707,{MyChFont_Zero+7,MyChFont_Xi}}, {0x0815,{MyChFont_Zhong,MyChFont_Qiu}}, }; {0x0909,{MyChFont_Chong,MyChFont_Yang}}, {0x1208,{MyChFont_La,MyChFont_Zero+8}} uint16_t u16TommorrwRemindFlag=0;//是否已经有明天节日提示显示 uint16_t u16TodayRemindFlag=0;//是否已经有今天节日提示显示 void holiday_remind() { uint16_t uiTextColor,uiBackColor,uiTempXpos,uiTempYpos,u16Temp; sFONT *Prefonts; uint16_t u16GregorianBCDMonDay; //公历月日BCD码 uint16_t u16LunarMonDay; 31 //阴历月日 BCD码 uint16_t u16NumOfHolidays,tempNum; uint8_t u8BCDmonth,u8BCDday; uint16_t u16MyChFontTablePos0=0xffff,u16MyChFontTablePos1=0xffff;//记录待显示节日名称字模数组的位置 /*检查明天是否有阴历节日*/ if(12==month_moon && 30==day_moon) //阴历/*保存当前颜色和字体*/ TFTSPI_GetColors(&uiTextColor,&uiBackColor); Prefonts = TFTSPI_GetFont(); 节日主要就一个春节会涉及月份进位问题 { u8BCDmonth = 0x01; u8BCDday = 0x01; u16LunarMonDay = (u8BCDmonth<<8) | u8BCDday; } else { u8BCDmonth = ((month_moon/10)<<4) | (month_moon%10); u8BCDday = (((day_moon+1)/10)<<4) | ((day_moon+1)%10); u16LunarMonDay = (u8BCDmonth<<8) | u8BCDday; } u16NumOfHolidays = sizeof(stLunarHoliday)/sizeof(stHoliday); for(tempNum = 0; tempNum { if(u16LunarMonDay==stLunarHoliday[tempNum].m_u16BCDMonDay) { u16MyChFontTablePos0 32 = stLunarHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos0; u16MyChFontTablePos1 stLunarHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos1; break; } } /*检查明天是否有公历节日*/ if(uiDay+1>uiMaxDay) { if(uiMonth+1>12) { u8BCDmonth = 0x01; = } else { u8BCDmonth = (((uiMonth+1)/10)<<4) | ((uiMonth+1)%10); } u8BCDday = 0x01; } else { u8BCDmonth = ((uiMonth/10)<<4) | (uiMonth%10); u8BCDday = (((uiDay+1)/10)<<4) | ((uiDay+1)%10); } u16GregorianBCDMonDay = (u8BCDmonth<<8) | u8BCDday; u16NumOfHolidays = sizeof(stGregorianHoliday)/sizeof(stHoliday); for(tempNum = 0; tempNum { if(u16GregorianBCDMonDay==stGregorianHoliday[tempNum].m_u16BCDMonDay) 33 { u16MyChFontTablePos0 stGregorianHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos0; u16MyChFontTablePos1 stGregorianHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos1; break; } } if(0xffff!=u16MyChFontTablePos0) { TFTSPI_SetFont(&Font16x16_MyChFont); TFTSPI_SetColors(LCD_COLOR_BLACK,MAIN_BACK_COLOR); u16TommorrwRemindFlag =1; uiTempXpos = XPOS_HOLIDAYREMIND; uiTempYpos = YPOS_HOLIDAYREMIND_TOMORROW; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t = = *)GB_Font16x16_MyChFontTable+(MyChFont_Ming)*16*2);//显示“明”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Tian)*16*2);//显示“天”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Shi4)*16*2);//显示“是”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(u16MyChFontTablePos0)*16*2);//显示*#节的“*”字 34 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(u16MyChFontTablePos1)*16*2);//显示*#节的“#”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Jie)*16*2);//显示“节”字 } else if(0!=u16TommorrwRemindFlag) { /*清除明天节日提醒信息*/ TFTSPI_SetFont(&Font16x16_MyChFont); TFTSPI_SetColors(LCD_COLOR_BLACK,CLEAR_BACK_COLOR); u16TommorrwRemindFlag = 0; uiTempXpos = XPOS_HOLIDAYREMIND; uiTempYpos = YPOS_HOLIDAYREMIND_TOMORROW; for(u16Temp=0;u16Temp<6;u16Temp++) { TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Blank)*16*2);//显示“ ”字 u16MyChFontTablePos0=0xffff; u16MyChFontTablePos1=0xffff; } } uiTempXpos += 16; /*检查今天是否有阴历节日*/ u8BCDmonth = ((month_moon/10)<<4) | (month_moon%10); 35 u8BCDday = ((day_moon/10)<<4) | (day_moon%10); u16LunarMonDay = (u8BCDmonth<<8) | u8BCDday; u16NumOfHolidays = sizeof(stLunarHoliday)/sizeof(stHoliday); for(tempNum = 0; tempNum { if(u16LunarMonDay==stLunarHoliday[tempNum].m_u16BCDMonDay) { u16MyChFontTablePos0 stLunarHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos0; u16MyChFontTablePos1 stLunarHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos1; break; } } /*检查今天是否有公历节日*/ u8BCDmonth = ((uiMonth/10)<<4) | (uiMonth%10); u8BCDday = ((uiDay/10)<<4) | (uiDay%10); u16GregorianBCDMonDay = (u8BCDmonth<<8) | u8BCDday; u16NumOfHolidays = sizeof(stGregorianHoliday)/sizeof(stHoliday); for(tempNum = 0; tempNum { if(u16GregorianBCDMonDay==stGregorianHoliday[tempNum].m_u16BCDMonDay) { u16MyChFontTablePos0 stGregorianHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos0; u16MyChFontTablePos1 stGregorianHoliday[tempNum].m_stHolidayName.u16MyChFontTablePos1; break; } 36 = = = = } if(0xffff!=u16MyChFontTablePos0) { TFTSPI_SetFont(&Font16x16_MyChFont); TFTSPI_SetColors(LCD_COLOR_BLACK,MAIN_BACK_COLOR); u16TodayRemindFlag =1; uiTempXpos = XPOS_HOLIDAYREMIND; uiTempYpos = YPOS_HOLIDAYREMIND_TODAY; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Jin)*16*2);//显示“今”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Tian)*16*2);//显示“天”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Shi4)*16*2);//显示“是”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(u16MyChFontTablePos0)*16*2);//显示*#节的“*”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(u16MyChFontTablePos1)*16*2);//显示*#节的“#”字 uiTempXpos += 16; TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t 37 *)GB_Font16x16_MyChFontTable+(MyChFont_Jie)*16*2);//显示“节”字 } else if(0!=u16TodayRemindFlag) { /*清除今天节日提醒信息*/ TFTSPI_SetFont(&Font16x16_MyChFont); TFTSPI_SetColors(LCD_COLOR_BLACK,CLEAR_BACK_COLOR); u16TodayRemindFlag = 0; uiTempXpos = XPOS_HOLIDAYREMIND; uiTempYpos = YPOS_HOLIDAYREMIND_TODAY; for(u16Temp=0;u16Temp<6;u16Temp++) { TFTSPI_SetArea(uiTempXpos,uiTempYpos); TFTSPI_Draw_ChFont((uint8_t *)GB_Font16x16_MyChFontTable+(MyChFont_Blank)*16*2);//显示“ ”字 } --******************************文件开始****************************** ** 文件名称: Control.c ** 最后修改日期: 2014/4/28 ** 功能描述: 按键处理和状态转换 *******************************************************************-- } } uiTempXpos += 16; /*恢复当前颜色和字体*/ TFTSPI_SetColors(uiTextColor,uiBackColor); TFTSPI_SetFont(Prefonts); #include "Control.h" #include "../GUI/TFTSPI.h" #include "../Time/Time.h" 38 #include "../Infrared/Infrared.h" #include "../Calendar/Calendar.h" #include "../Calendar/Gregorian2Lunar.h" #include "../Calendar/HolidayRemind.h" #include "../SD2403/SD2403.H" #include "../GUI/draw_bmp.h" #include "../FatFS_R0.10/ff.h" /*全局变量*/ enum {SET_IDLE,SET_TIME,SET_DATE,SET_ALARM}eSetStatus; enum {SET_TIMEIDLE,SET_SECOND,SET_MINUTE,SET_HOUR}eSetTimeStatus; enum {SET_AONOFF,SET_AMINUTE,SET_AHOUR}eSetAlarmStatus; enum {SET_YEAR,SET_MONTH,SET_DAY}eSetDateStatus; uint32_t uiUnderline; //记录时间、日期、闹钟是否有下划线,0没有,1时间有,2日期有,3闹钟有 uint32_t uiXposPreUnderline,uiYposPreUnderline,uiLengthPreUnderline;//记录上一次下划线的位置和长度(清除用) uint8_t Dis_Calendar_Pic; 挂历,1图片 extern uint8_t Key_Value,IR_Rec; extern uint8_t u8NumOfPic; extern uint8_t strTime[]; extern uint8_t strDate[]; extern uint8_t strAlarm[]; extern uint32_t uiSetStatusTimes; //统计设置状态处于设定状态却没有按键输入的时间 /* * 函数名:Draw_Time_Underline * 描述 :为当前设置时间增加下划线 39 //记录当前是在显示挂历还是图片,0 //按键值和红外接收码 //可供显示的图片数量 * 输入 :右移0,左移1,不移2 * 返回 :无 */ void Draw_Time_Underline(uint32_t HV) { uint16_t uiXpos,uiYpos,uiLength; switch(eSetTimeStatus) { case SET_TIMEIDLE: { if(0==HV) { } else if(1==HV) { } eSetTimeStatus = SET_MINUTE; eSetTimeStatus = SET_HOUR; }break; case SET_SECOND: { if(0==HV) { } else if(1==HV) { eSetTimeStatus = SET_MINUTE; 40 eSetTimeStatus = SET_HOUR; } }break; case SET_MINUTE: { if(0==HV) { } else if(1==HV) { } eSetTimeStatus = SET_HOUR; eSetTimeStatus = SET_SECOND; }break; case SET_HOUR: { if(0==HV) { } else if(1==HV) { } eSetTimeStatus = SET_SECOND; eSetTimeStatus = SET_MINUTE; }break; default: { break; 41 } } switch(eSetTimeStatus) { case SET_TIMEIDLE: case SET_SECOND: { uiXpos = XPOS_STRTIME+16*6; uiYpos = YPOS_STRTIME+24+1; uiLength = 16*2; }break; case SET_MINUTE: { uiXpos = XPOS_STRTIME+16*3; uiYpos = YPOS_STRTIME+24+1; uiLength = 16*2; }break; case SET_HOUR: { uiXpos = XPOS_STRTIME; uiYpos = YPOS_STRTIME+24+1; uiLength = 16*2; }break; default: { break; 42 } } /*清除上一次的下划线(线的颜色用填充色)*/ if(0!=uiLengthPreUnderline) { Draw_Horizontal_Line(uiXposPreUnderline,uiYposPreUnderline,0,uiLengthPreUnderline,MAIN_BACK_COLOR); } /* * 函数名:Draw_Date_Underline * 描述 :为当前设置日期增加下划线 * 输入 :右移0,左移1,不移2 * 返回 :无 */ void Draw_Date_Underline(uint32_t HV) { 43 } /*画下划线*/ Draw_Horizontal_Line(uiXpos,uiYpos,0,uiLength,LCD_COLOR_BLACK); /*记录该次所画下划线信息*/ uiXposPreUnderline = uiXpos; uiYposPreUnderline = uiYpos; uiLengthPreUnderline = uiLength; uint16_t uiXpos,uiYpos,uiLength; switch(eSetDateStatus) { case SET_YEAR: { if(0==HV) { } else if(1==HV) { } eSetDateStatus = SET_DAY; eSetDateStatus = SET_MONTH; }break; case SET_MONTH: { if(0==HV) { } else if(1==HV) { } eSetDateStatus = SET_YEAR; eSetDateStatus = SET_DAY; }break; case SET_DAY: { if(0==HV) { 44 } eSetDateStatus = SET_YEAR; else if(1==HV) { } eSetDateStatus = SET_MONTH; }break; } default: { } break; switch(eSetDateStatus) { case SET_YEAR: { uiXpos = XPOS_STRDATE; uiYpos = YPOS_STRDATE+24+1; uiLength = 16*4; }break; case SET_MONTH: { uiXpos = XPOS_STRDATE+16*5; uiYpos = YPOS_STRDATE+24+1; uiLength = 16*2; }break; 45