作息时间提示控制项目
前言
这个项目主要针对于选择的人们作息不规律而设计的一个项目,这个项目是使用stm32f103系列的芯片来制作的(R6和C8)都可以使用。
一、使用的元器件
- DS1302时钟芯片
- STM32F103R6
- 按键
- LCD1602显示屏
- 蜂鸣器
- 蓝牙模块HC-05
二、仿真图
这个可以添加一个蓝牙手机连接功能,但是我这个仿真有问题所以等实物的时候我会添加一个蓝牙模块上去实现远程停止定时和设置时间等内容。
三、项目分析
首先先实现LCD显示时间内容,这里需要写一个DS1302的驱动来进行读取内容,然后将读取的内容显示到屏幕上面即可。然后需要写一个判断来判断获取到的时间与设计的时间进行一个比较,然后如果时间到了那就可以启动蜂鸣器报警模块来提醒用户该休息了。
然后需要对按键进行判断,当按下KEY1按键那就将提醒关闭,KEY2按键是设置内容的。
四、代码编写
这里就开始写代码了,首先要编写一个驱动模块,先实现DS1302的读取和设置,这里已经写好了,直接使用即可:
#include "ds1302.h"
// 设置命令
u8 gREAD_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
u8 gWRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
// 用来设置时钟的数组,秒 分 时 日 月 年,都是BCD码
u8 gDS1302_TIME[7] = {0x57, 0x59, 0x21, 0x20, 0x04, 0x05, 0x21};
void MX_Init_DS1302(){
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Pin = RST | CLK | IO;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
}
void ds1302_write_byte(u8 addr,u8 dat)
{
u8 i=0;
GPIO_WriteBit(GPIOC, RST, Bit_RESET);
GPIO_WriteBit(GPIOC, CLK, Bit_RESET);
GPIO_WriteBit(GPIOC, RST, Bit_SET);
for(i=0;i<8;i++){
GPIO_WriteBit(GPIOC, IO, addr&0x01);
addr>>=1;
GPIO_WriteBit(GPIOC, CLK, Bit_SET);
GPIO_WriteBit(GPIOC, CLK, Bit_RESET);
}
for(i=0;i<8;i++){
GPIO_WriteBit(GPIOC, IO, dat&0x01);
dat>>=1;
GPIO_WriteBit(GPIOC, CLK, Bit_SET);
GPIO_WriteBit(GPIOC, CLK, Bit_RESET);
}
GPIO_WriteBit(GPIOC, RST, Bit_RESET);
}
u8 ds1302_read_byte(u8 addr)
{
u8 i=0;
u8 temp=0;
u8 value=0;
GPIO_WriteBit(GPIOC, RST, Bit_RESET);
GPIO_WriteBit(GPIOC, CLK, Bit_RESET);
GPIO_WriteBit(GPIOC, RST, Bit_SET);
for(i=0;i<8;i++){
GPIO_WriteBit(GPIOC, IO, addr&0x01);
addr>>=1;
GPIO_WriteBit(GPIOC, CLK, Bit_SET);
GPIO_WriteBit(GPIOC, CLK, Bit_RESET);
}
for(i=0;i<8;i++){
temp=GPIO_ReadInputDataBit(GPIOC, IO);
value=(temp<<7)|(value>>1);
GPIO_WriteBit(GPIOC, CLK, Bit_SET);
GPIO_WriteBit(GPIOC, CLK, Bit_RESET);
}
GPIO_WriteBit(GPIOC, RST, Bit_RESET);
GPIO_WriteBit(GPIOC, CLK, Bit_SET);
GPIO_WriteBit(GPIOC, IO, Bit_RESET);
GPIO_WriteBit(GPIOC, IO, Bit_SET);
return value;
}
void ds1302_init(void)
{
u8 i=0;
ds1302_write_byte(0x8E,0X00);
for(i=0;i<7;i++)
{
ds1302_write_byte(gWRITE_RTC_ADDR[i],gDS1302_TIME[i]);
}
ds1302_write_byte(0x8E,0X80);
}
void ds1302_read_time(void)
{
u8 i=0;
for(i=0;i<7;i++)
{
gDS1302_TIME[i]=ds1302_read_byte(gREAD_RTC_ADDR[i]);
}
}
#ifndef __DS1302_H
#define __DS1302_H
#include "stm32f10x.h"
#define RST GPIO_Pin_1
#define CLK GPIO_Pin_2
#define IO GPIO_Pin_3
extern u8 gDS1302_TIME[7]; // 读取时间的数组
void MX_Init_DS1302();
void ds1302_init(void);
void ds1302_read_time(void);
#endif
也可以直接到我的gitee中进行下载:DS1302
然后就可以进行读取其中的内容了,这里使用的就是一个全局数组进行接收数据,接收的顺序是秒,分,时,读取的代码如下:
ds1302_read_time();
time = gDS1302_TIME[2]/16 * 10 + (gDS1302_TIME[2]&0x0f);
minute = gDS1302_TIME[1]/16 * 10 + (gDS1302_TIME[1]&0x0f);
second = gDS1302_TIME[0]/16 * 10 + (gDS1302_TIME[0]&0x0f);
这里需要转换一下,因为读取的是BCD码,然后就可以进行显示了:
sprintf((char*)time_buf, "%2d:%2d:%2d", time, minute, second);
show_string(0, 0, time_buf);
这里使用的是LCD1602
的驱动程序中的显示字符串的函数,下载链接:led1602模块。
然后就可以进行时间的判断了:
if ((time == TIME) && ((minute < MINUTE + response) && (minute >= MINUTE)) && (flag == 1)){
// 时间到了开始警报
alarm();
}
else {
// 如果还在定时的范围中就不复位flag
if ((time == TIME) && ((minute < MINUTE + response) && (minute >= MINUTE))){
flag = 0;
}
else{
// 如果不在这个范围中就复位flag
flag = 1;
}
}
这里添加了一个flag
变量,这个变量是当按下了KEY1
后就会停止响应,如果按下了,但是还是在定时的范围中,那么不会复位,因为你停止了就没必要继续响了。
然后就是按键的功能实现:
if (GPIO_ReadInputDataBit(GPIOA, KEY1) == Bit_RESET){
// 按下了停止按键
flag = 0;
stopSound();
}
if (GPIO_ReadInputDataBit(GPIOA, KEY2) == Bit_RESET){
// 设置和确认
delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOA, KEY2) == Bit_RESET);
// 清屏
show_string(0, 0, (unsigned char*)" ");
show_string(0, 1, (unsigned char*)" ");
while(1){
sprintf((char*)buf, "TIME:%2d", TIME);
show_string(3, 0, buf);
sprintf((char*)buf, "MINUTE:%2d", MINUTE);
show_string(3, 1, buf);
if (select == 0){
show_string(0, 0, (unsigned char*)"->");
show_string(0, 1, (unsigned char*)" ");
}
else{
show_string(0, 1, (unsigned char*)"->");
show_string(0, 0, (unsigned char*)" ");
}
if (GPIO_ReadInputDataBit(GPIOA, KEY1) == Bit_RESET){
// 选择
delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOA, KEY1) == Bit_RESET);
select = ~select & 0x01;
}
else if (GPIO_ReadInputDataBit(GPIOA, KEY3) == Bit_RESET){
// 增加
delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOA, KEY3) == Bit_RESET);
if (select == 0){
if (++TIME >= 24){
TIME = 0;
}
}
else{
if (++MINUTE >= 60){
MINUTE = 0;
}
}
}
else if (GPIO_ReadInputDataBit(GPIOA, KEY4) == Bit_RESET){
// 减少
delay_ms(20);
while(GPIO_ReadInputDataBit(GPIOA, KEY4) == Bit_RESET);
if (select == 0){
if (--TIME == 255){
TIME = 23;
}
}
else{
if (--MINUTE == 255){
MINUTE = 59;
}
}
}
if (GPIO_ReadInputDataBit(GPIOA, KEY2) == Bit_RESET){
delay_ms(20); // 消抖
// 清屏
show_string(0, 0, (unsigned char*)" ");
show_string(0, 1, (unsigned char*)" ");
break;
}
}
}
这里的按键功能比较复杂,因为涉及到一个按键判断功能的一个内容,所以在KEY2
中又添加了一个死循环,在死循环中进行设置,当然这个功能不会影响DS1302
时钟的。
总结
其实这个项目还是很简单的,等后面有时间我会改写一下这个项目,让单片机中插入一个系统,然后再用系统进行控制。大家有什么想法可以在下面留言,我这都会看到的。