目錄前言一、使用的元器件二、模擬圖三、項目分析四、代碼編寫總結 前言 這個項目主要針對於選擇的人們作息不規律而設計的一個項目,這個項目是使用stm32f103系列的晶元來製作的(R6和C8)都可以使用。 一、使用的元器件 DS1302時鐘晶元 STM32F103R6 按鍵 LCD1602顯示屏 蜂鳴 ...
目錄
前言
這個項目主要針對於選擇的人們作息不規律而設計的一個項目,這個項目是使用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
時鐘的。
總結
其實這個項目還是很簡單的,等後面有時間我會改寫一下這個項目,讓單片機中插入一個系統,然後再用系統進行控制。大家有什麼想法可以在下麵留言,我這都會看到的。