设计、制作一个简易的闹钟。要求如下:
(1)作品需设有电源指示灯(绿),上电后,指示灯亮;
(2)该闹钟能够显示当前的日期和时间,显示界面如下:
Alarm Clock
Date:年-月-日 (日期)
Time:时:分:秒 (时间)
Alm: 时:分:秒 (报警时间)
(3)报警时间可调。设4个按键,分别为调时、调分、调秒、确定
(4)当报警时间到达时,采用蜂鸣器报警,蜂鸣器要求响5S钟。
系统系统
方案一:直接采用STM32单片机自身集成的RTC实时时钟,使用程序实现年、月、日、星期、时、分、秒计数。采用此种方案虽然减少芯片的使用,节约成本,但是单片机掉电会丢失数据,需要外部32.768KHz晶振和纽扣电池供电。
方案二:采用DS1302为计时时钟芯片
该芯片是串行电路,与单片机接口简单,但需另备电池和32.768kHz晶振,因焊接工艺和晶振质量等原因会导致精度降低。
方案三:采用DS3231实时时钟模块
该芯片与单片机通过IIC串行通信,传递速度比较快。自带有电池,不需要外部晶振,完整的时钟日历功能包括秒、分、时、星期、日期、月和年计时,并提供有效期到2100年的闰年补偿,两个日历闹钟。还有集成了温度传感器,成本低。
由于DS3231时钟芯片模块精度高,而且具有闰年补偿功能且价格经济实惠等优点,故采用方案三。
采用STM32F103C8T6作为控制器,采用独立按键输入,0.96寸OLED显示屏spi四线通信作为显示模块,DS3231M模块作为实时时钟模块,发声模块采用有源蜂鸣器模块。
原理图如下:
主程序:
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "oled.h"
#include "picture.h"
#include "ds3231.h"
#include "key.h"
_calendar_part calendar;//声明时钟结构体
_Alarmclock_part Alarmclock;//声明闹钟结构体
typedef struct
{
u8 sure_flag;
u8 stop_flag;
}_Alarm_flag; //标志结构体
_Alarm_flag flag;
void display(void);
void Key_Control(void);
int main()
{
SysTick_Init(72);//系统时钟初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
LED_Init(); //led初始化
OLED_Init(); //OLED初始化
DS3231_Init(); //DS3231初始化
KEY_Init(); //按键初始化
Alarmclock.hour = 8;//闹钟初始值
Alarmclock.min = 50;
Alarmclock.sec = 0;
Alarmclock1_close();//初始先将闹钟关闭并清除闹钟标志位
Alarmclock1_cmd(0);
beep = 1;
while(1)
{
get_time();
display(); //oled显示
Key_Control(); //按键控制
if(flag.sure_flag)
{
Alarmclock1_cmd(1); //闹钟使能
SetAlarmclock(Alarmclock.hour,Alarmclock.min,Alarmclock.sec);//设置闹钟
if(Alarmclock1state()==1&&!flag.stop_flag)//检测闹钟标志位
{
beep = 0; //蜂鸣器打开
Alarmclock1_cmd(0); //闹钟失能
Alarmclock1_close(); //关闭闹钟并清理标志位
flag.stop_flag = 1;
}
}
else
{
beep = 1; //蜂鸣器关闭
}
if(flag.stop_flag) //使闹钟5秒钟后停止
{
Alarmclock1_cmd(1);
SetAlarmclock(Alarmclock.hour,Alarmclock.min,Alarmclock.sec+5);
if(Alarmclock1state()==1)
{
beep = 1;
Alarmclock1_cmd(0);
Alarmclock1_close();
flag.stop_flag = 0;
flag.sure_flag = 0;
}
}
}
}
void display(void)//OLED显示
{
/*****日期显示****/
OLED_ShowNum(0,0,2000+calendar.year,4,16);
OLED_ShowFontHZ(16*2,0,0,16,1); //年
OLED_ShowNum(16*3,0,calendar.month,2,16);
OLED_ShowFontHZ(16*4,0,1,16,1); //月
OLED_ShowNum(16*5,0,calendar.day,2,16);
OLED_ShowFontHZ(16*6,0,2,16,1); //日
/*****时间显示*****/
OLED_ShowChar(24*0,16,calendar.hour/10+'0',24,1); //时
OLED_ShowChar(12*1,16,calendar.hour%10+'0',24,1); //时
OLED_ShowChar(6*5,16,':',24,1);
OLED_ShowChar(24*2,16,calendar.min/10+'0',24,1); //分
OLED_ShowChar(12*5,16,calendar.min%10+'0',24,1); //分
OLED_ShowChar(6*13,16,':',24,1);
OLED_ShowChar(24*4,16,calendar.sec/10+'0',24,1); //秒
OLED_ShowChar(12*9,16,calendar.sec%10+'0',24,1); //秒
/******闹钟******/
if(flag.sure_flag)OLED_ShowString(16*0,48,"A",16);
else OLED_ShowString(16*0,48," ",16);
OLED_ShowChar(16*1,48,Alarmclock.hour/10+'0',16,1); //时
OLED_ShowChar(8*3,48,Alarmclock.hour%10+'0',16,1); //时
OLED_ShowChar(4*9,48,':',16,1);
OLED_ShowChar(16*3,48,Alarmclock.min/10+'0',16,1); //分
OLED_ShowChar(8*7,48,Alarmclock.min%10+'0',16,1); //分
OLED_ShowChar(4*17,48,':',16,1);
OLED_ShowChar(16*5,48,Alarmclock.sec/10+'0',16,1); //秒
OLED_ShowChar(8*11,48,Alarmclock.sec%10+'0',16,1); //秒
OLED_Refresh_Gram(); //刷新GRAM数组
}
void Key_Control(void)//按键控制
{
u8 temp = 0;
temp = KEY_Scan(0);
switch(temp)
{
case 1: Alarmclock.hour+=1;
if(Alarmclock.hour>=24) Alarmclock.hour=0;
break;
case 2: Alarmclock.min+=1;
if(Alarmclock.min>=60) Alarmclock.min=0;
break;
case 3: Alarmclock.sec+=1;
if(Alarmclock.sec>=60) Alarmclock.sec=0;
break;
case 4: flag.sure_flag =~ flag.sure_flag;
break;
}
}
源程序这里https://download.csdn.net/download/qq_44702247/12581386