作息時間提示控制項目

来源:https://www.cnblogs.com/Lavender-edgar/archive/2023/11/19/17842438.html
-Advertisement-
Play Games

目錄前言一、使用的元器件二、模擬圖三、項目分析四、代碼編寫總結 前言 這個項目主要針對於選擇的人們作息不規律而設計的一個項目,這個項目是使用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時鐘的。

總結

其實這個項目還是很簡單的,等後面有時間我會改寫一下這個項目,讓單片機中插入一個系統,然後再用系統進行控制。大家有什麼想法可以在下麵留言,我這都會看到的。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在 Go 語言中,panic、recover 和 defer 是用於處理異常情況的關鍵字。它們通常一起使用來實現對程式錯誤的處理和恢復。 1. defer 語句 defer 用於在函數返回之前執行一段代碼。被 defer 修飾的語句或函數會在包含 defer 的函數執行完畢後執行。defer 常用於 ...
  • 建議看看電腦科學速成課,一門很全面的電腦原理入門課程,短短10分鐘可以把大學老師十幾節課講的東西講清楚!整個系列一共41個視頻,B站上有中文字幕版。 每個視頻都是一個特定的主題,例如軟體工程、人工智慧、操作系統等,主題之間都是緊密相連的,比國內很多大學電腦課程強太多! 這門課程通過生動形象的講 ...
  • ✨前言✨ 本片文章,主要在於C#連接MySQL資料庫,由於這之間無法建立直接聯繫,這時候就涉及到了第三方連接工具.NET,以此來建立C#與MySQL資料庫的連接 🍒歡迎點贊 👍 收藏 ⭐留言評論 📝私信必回喲😁 🍒博主將持續更新學習記錄收穫,友友們有任何問題可以在評論區留言 目錄🍊 一, ...
  • SciPy庫的optimize模塊主要用於執行各種優化任務。優化是尋找特定函數的最小值或最大值的過程,通常用於機器學習、數據分析、工程和其他領域。 scipy.optimize提供了多種優化演算法,包括梯度下降法、牛頓法、最小二乘法等,可以解決各種複雜的優化問題。該模塊還包含一些特定的函數,用於解決某 ...
  • .NET8發佈後,Blazor支持四種渲染方式 靜態渲染,這種頁面只可顯示,不提供交互,可用於網頁內容展示 使用Blazor Server托管的通過Server交互方式 使用WebAssembly托管的在瀏覽器端交互方式 使用Auto自動交互方式,最初使用 Blazor Server,併在隨後訪問時 ...
  • AOT介紹 .Net8的本地預編機器碼AOT,它幾乎進行了100%的自舉。微軟為了擺脫C++的鉗制,做了很多努力。也就是代碼幾乎是用C#重寫,包括了虛擬機,GC,記憶體模型等等。而需要C++做的,也就僅僅是引導程式,本篇通過代碼來看下這段至關重要的引導程式的運作模式。 支持功能 SqlSugar OR ...
  • 關於Anolis8/Centos8系統重啟後ip地址不顯示的原因 版權聲明:原創作品,謝絕轉載!否則將追究法律責任。 ————— 作者:kirin #、今天把之前在VMware安裝的Anolis8系統重啟了,啟動之後發現Xshell連接不上。在VMware上登錄後執行ip a命令發現ip地址不見了 ...
  • DX後臺截圖C++實現代碼 文章僅發佈於https://www.cnblogs.com/Icys/p/DXGI.html和知乎上。 傳統的GDI API (BitBlt)雖然可以完美的完成後臺截圖的任務,但是歸根結底效率還是太低。 直接使用DXGI方法截圖只能完成前臺視窗的截圖,而DX HOOK的截 ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...