摘要:當小于時,由供電讀數(shù)據(jù)工作時序單字節(jié)寫入上升沿置高電平,下降沿置低電平。當總線控制器把數(shù)據(jù)線從高電平拉到低電平時,讀時序開始,數(shù)據(jù)線必須至少保持然后總線被釋放見圖。因此,總線控制器在讀時序開始后必須停止把腳驅(qū)動為低電平以讀取腳狀態(tài)。
目錄
我們小組參加了華南理工大學自動化學院基地組織的二輪創(chuàng)新項目——藍牙電子時鐘的制作,可以說是受益匪淺,故做此記錄,也希望能夠幫助到其他想要制作藍牙電子時鐘或是學習51單片機、藍牙串口通信和簡易手機軟件的編寫的相關愛好者。
本次設計的參考資料(順便相當于做個安利了):
1、CSDN——CSDN - 專業(yè)開發(fā)者社區(qū)(參考內(nèi)容較多不再一一贅述,有興趣的可以自查)。
2、bilibili51單片機入門教程——51單片機入門教程-2020版 程序全程純手打 從零開始入門嗶哩嗶哩bilibili
及藍牙APP制作——藍牙APP制作(App inventor開發(fā)APP、AT指令配置藍牙模塊)嗶哩嗶哩bilibili
3、簡書(同CSDN,有興趣自查即可)
本次藍牙電子時鐘的使用的器材包塊:DS1302時鐘芯片,STC89C52RC,LCD1602,OLED顯示屏,HC-06藍牙模塊,DS18B20溫度傳感器、5V無源蜂鳴器、三極管Q9012、紐扣電池及其插座、11.0592Hz晶振、37.768kHz晶振、杜邦線若干、10k、2.2k、1k電阻若干等。
STC-ISP——負責燒錄程序和發(fā)送/接受簡單數(shù)據(jù)以及獲得簡單延時函數(shù)及晶振相關函數(shù)。
keil uVsion4——主要的單片機程序編寫。
Proteus——仿真電路圖制作。
PCtoLCD2002——OLED顯示漢字及數(shù)字的取模。
VS Studio 2019——編寫內(nèi)部部分程序并運行測試實際效果。
app inventor——用最簡單的可視化編程方法編寫手機app。
首先,學習所有的相關知識并購買兩份器材(一份預備),利用最小開發(fā)板分別實現(xiàn)各個功能;
其次,進行app開發(fā)(后期對接)和電路仿真運行,設計并確定電路圖,進行焊接。
然后,逐步分布實現(xiàn)各個功能:顯示精確時間,藍牙通信,蜂鳴器鬧鐘,日歷及漢字取模,時間修改,app對接。
最后,調(diào)試bug以及完善外部顯現(xiàn)功能。
隊員A | 隊員B |
---|---|
學習單片機相關知識,學習手機軟件制作 | 學習單片機相關知識,學習仿真電路圖 |
進行鬧鐘設計和日歷設計,學習oled | 進行基礎功能模塊設計,學習led,編寫基礎程序 |
讀懂隊員B編寫的基礎程序和完成電路,準備app對接 | 焊接電路,完成硬件基礎設置 |
進行app、藍牙串口通信與單片機的對接 | 根據(jù)電路出現(xiàn)的實際問題進行調(diào)試和修改 |
調(diào)整軟件問題,整合程序 | 完成外部形象優(yōu)化 |
1.DS1302時鐘芯片
(1)概念及優(yōu)勢
DS1302是由DALLAS公司生產(chǎn),具有涓細電流充電能力的實時時鐘電路,采用串行數(shù)據(jù)傳輸,可由掉電電池提供可編程的充電能力,它采用的是獨有的32.768K晶振,具有很強的時鐘功能,是一種高性能、低功耗、帶RAM的實時時鐘電路,它可以對年、月、日、周、時、分、秒進行計時, 具有閏年補償功能,工作電壓為2.5V~5.5V。 DS1302內(nèi)部有一個31字節(jié)的用于臨時性存放數(shù)據(jù)的靜態(tài)RAM寄存器。
(2) DS1302引腳功能
(3)DS1302內(nèi)部結(jié)構(gòu)圖
(4)工作原理
由以上圖可以知道,DS1302與單片機的連線只需3 條,即SCL(7)、I/O(6)、和 RST(5)。 接在CON2上的備用電池通過DS1302的第8腳為 DS1302提供低功耗的電池備份。VCC2在雙電源系統(tǒng)中提供主電源,在這種方式下VCC1連接備用電源,當系統(tǒng)沒有主電源的情況下,能保持時間信息及數(shù)據(jù)不丟失。DS1302由VCC1或 VCC2兩者中較大者供電。當VCC2大于VCC1 0.2V時,VCC2給DS1302供電。當 VCC2小于VCC1時,DS1302由VCC1供電
DS1302讀數(shù)據(jù)工作時序
單字節(jié)寫入
上升沿置高電平,下降沿置低電平。
從時序圖上看,大家可以看得到DS1302是串行驅(qū)動的。通過I/O口先寫入控制字, 還需要讀取相應寄存器的數(shù)據(jù)。每次在對1302操作前都要對1302進行初始化,需要將RST置為高電平, 并將8位地址和命令信息裝入移位寄存器。數(shù)據(jù)在SCLK的上升沿輸入, 前8位指定訪問地址命令, 在之后的時鐘周期, 讀操作時輸出的數(shù)據(jù), 寫操作時輸入數(shù)據(jù)。 時鐘脈沖的個數(shù)在單字節(jié)方式下為8個地址加8位數(shù)據(jù)。
DS1302寫數(shù)據(jù)的時序操作
數(shù)據(jù)在SCLK的上升沿輸入, 前8位指定訪問地址命令, 在之后的時鐘周期, 讀操作時輸出的數(shù)據(jù), 寫操作時輸入數(shù)據(jù)。時鐘脈沖的個數(shù)在單字節(jié)方式下為8個地址加8位數(shù)據(jù)。
日歷,時鐘寄存器配置
BCD碼與十進制轉(zhuǎn)換
DS1302輸出的是8421編碼,8421編碼就是我們常說的BCD碼。所以寫入與讀出時均使用BCD碼而不是十進制。
最常用的BCD編碼,就是使用"0"至"9"這十個數(shù)值的二進碼來表示。其對應的編碼如下: 十進制BCD碼 0=0000 ;1=0001 ;2=0010 ;3=0011; 4=0100 ;5=0101 ;6=0110; 7=0111 ;8=1000; 9=1001
以下是BCD碼和十進制的轉(zhuǎn)化的舉例
十進制轉(zhuǎn)BCD碼: 32/10 = 3*16= 48(十進制)= 30(16進制) 32%10 = 2 30+2 = 32 * 16 + 32 % 10 = 32(BCD碼)
BCD碼轉(zhuǎn)十進制: 51 / 16 = 5 * 10(16進制) = 50(十進制) 51 % 16 = 1 50 + 1 = 51 / 16 + 51 % 16 = 51(十進制)
部分代碼如下:
#include??sbit DS1302_SCLK = P1^0;sbit DS1302_IO = P1^1;sbit DS1302_CE = P1^2;?#define DS1302_SECOND ? ? 0X80 //定義寄存器的位置#define DS1302_MINUTE ? ? 0X82#define DS1302_HOUR ? ? 0X84#define DS1302_DATE ? 0X86#define DS1302_MONTH ? ? 0X88#define DS1302_DAY ? ? 0X8A#define DS1302_YEAR ? ? 0X8C#define DS1302_WP ? 0X8E????unsigned char DS1302_Time[]={21,11,21,9,26,20,7}; //定義一個數(shù)組用來存時間??void DS1302_Init(void) //初始化{ DS1302_CE=0; DS1302_SCLK=0;}?void DS1302_writebyte(unsigned char Command,Data) //向1302中寫入數(shù)據(jù)與指令{ unsigned char i; DS1302_CE=1; for(i=0;i<8;i++) { DS1302_IO=Command&(0x01<
DS18B20溫度傳感器
(1)概念及優(yōu)勢
獨特的單線接口僅需一個端口引腳進行通訊 (單總線通訊協(xié)議)
每個器件有唯一的 64位的序列號存儲在內(nèi)部存儲器中
測溫范圍為-55~+125℃(-67~+ 257℉)
可通過數(shù)據(jù)線供電。供電范圍為 3.0V 到 5.5V。
(2)引腳排列及內(nèi)部結(jié)構(gòu)
GND ——地
DQ ——數(shù)據(jù) I/O
VDD ——可選電源電壓
(3)工作原理
操作流程圖
讀/寫時序
寫時序:寫時序有兩種寫時序:寫 1 時序和寫 0 時序。總線控制器通過寫 1 時序?qū)戇壿?1 到 DS18B20,寫 0 時序?qū)戇壿?0 到 DS18B20。所有寫時序必須最少持續(xù) 60us,包括 兩個寫周期之間至少 1us 的恢復時間。當總線控制器把數(shù)據(jù)線從邏輯高電平拉到 低電平的時候,寫時序開始(見圖 14)。 總線控制器要生產(chǎn)一個寫時序,必須把數(shù)據(jù)線拉到低電平然后釋放,在寫時序開 始后的 15us 釋放總線。當總線被釋放的時候,5K 的上拉電阻將拉高總線。總控 制器要生成一個寫 0 時序,必須把數(shù)據(jù)線拉到低電平并持續(xù)保持(至少 60us)。 總線控制器初始化寫時序后,DS18B20 在一個 15us 到 60us 的窗口內(nèi)對 I/O 線采 樣。如果線上是高電平,就是寫 1。如果線上是低電平,就是寫 0。
讀時序:總線控制器發(fā)起讀時序時,DS18B20 僅被用來傳輸數(shù)據(jù)給控制器。因此,總線控 制器在發(fā)出讀暫存器指令[BEh]或讀電源模式指令[B4H]后必須立刻開始讀時序, DS18B20可以提供請求信息。所有讀時序必須最少 60us,包括兩個讀周期間至少 1us 的恢復時間。當總線控制 器把數(shù)據(jù)線從高電平拉到低電平時,讀時序開始,數(shù)據(jù)線必須至少保持 1us,然 后總線被釋放(見圖 14)。在總線控制器發(fā)出讀時序后,DS18B20 通過拉高或拉 低總線上來傳輸 1 或 0。當傳輸邏輯 0 結(jié)束后,總線將被釋放,通過上拉電阻回 到上升沿狀態(tài)。從 DS18B20 輸出的數(shù)據(jù)在讀時序的下降沿出現(xiàn)后 15us 內(nèi)有效。 因此,總線控制器在讀時序開始后必須停止把 I/O 腳驅(qū)動為低電平 15us,以讀取 I/O 腳狀態(tài)。
部分代碼如下:
#include?//引腳定義sbit OneWire_DQ=P3^7;??unsigned char OneWire_Init(void){ unsigned char i; unsigned char AckBit; OneWire_DQ=1; OneWire_DQ=0; i = 247;while (--i); //Delay 500us OneWire_DQ=1; i = 32;while (--i); //Delay 70us AckBit=OneWire_DQ; i = 247;while (--i); //Delay 500us return AckBit;}??void OneWire_SendBit(unsigned char Bit){ unsigned char i; OneWire_DQ=0; i = 4;while (--i); //Delay 10us OneWire_DQ=Bit; i = 24;while (--i); //Delay 50us OneWire_DQ=1;}?unsigned char OneWire_ReceiveBit(void){ unsigned char i; unsigned char Bit; OneWire_DQ=0; i = 2;while (--i); //Delay 5us OneWire_DQ=1; i = 2;while (--i); //Delay 5us Bit=OneWire_DQ; i = 24;while (--i); //Delay 50us return Bit;}??void OneWire_SendByte(unsigned char Byte){ unsigned char i; for(i=0;i<8;i++) { OneWire_SendBit(Byte&(0x01< 3.LCD及OLED模塊:
[1]LCD模塊:LCD1602
(1)引腳介紹
(2)初始化及顯示
LCD1602內(nèi)置國際標準ASCALL碼字庫,可直接調(diào)用顯示字符,缺點是不能顯示中文。
部分代碼如下:
#include?//引腳配置://sbit LCD_RS=P2^6;//sbit LCD_RW=P2^5;sbit LCD_RS=P2^5;sbit LCD_RW=P2^6;sbit LCD_EN=P2^7;#define LCD_DataPort P0 //定義P0引腳??void LCD_Delay() //@11.0592MHz{ unsigned char i, j;? i = 2; j = 199; do { while (--j); } while (--i);}???void LCD_WriteCommand(unsigned char Command) //LCD1602寫命令, Command 要寫入的命令{ LCD_RS=0; //0為寫入指令 LCD_RW=0; //RW=1為寫入,RS=0為讀出 LCD_DataPort=Command; LCD_EN=1; //E=1,使能,使數(shù)據(jù)有效 LCD_Delay(); LCD_EN=0; LCD_Delay();}?void LCD_WriteData(unsigned char Data) ?//LCD1602寫數(shù)據(jù),Data 要寫入的數(shù)據(jù){ LCD_RS=1; //1為寫入數(shù)據(jù) LCD_RW=0; //RW=1為寫入,RS=0為讀出 LCD_DataPort=Data; LCD_EN=1; //E=1,使能,使數(shù)據(jù)有效 LCD_Delay(); LCD_EN=0; LCD_Delay();}??void LCD_SetCursor(unsigned char Line,unsigned char Column) ? //LCD1602設置光標位置,Line 行位置,范圍:1~2,Column 列位置,范圍:1~16{ if(Line==1) { LCD_WriteCommand(0x80|(Column-1)); } else if(Line==2) { LCD_WriteCommand(0x80|(Column-1+0x40)); }}??void LCD_Init() //LCD1602初始化函數(shù){ LCD_WriteCommand(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點陣 LCD_WriteCommand(0x0c);//顯示開,光標關,閃爍關 LCD_WriteCommand(0x06);//數(shù)據(jù)讀寫操作后,光標自動加一,畫面不動 LCD_WriteCommand(0x01);//光標復位,清屏}?/** ?* ?* @retval 無 ?*/void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char) //在LCD1602指定位置上顯示一個字符,范圍:1~16要顯示的字符{ LCD_SetCursor(Line,Column); LCD_WriteData(Char);}??void LCD_ShowString(unsigned char Line,unsigned char Column,char *String) //在LCD1602指定位置開始顯示所給字符串,String 要顯示的字符串{ unsigned char i; LCD_SetCursor(Line,Column); for(i=0;String[i]!="/0";i++) { LCD_WriteData(String[i]); }}void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length) //在LCD1602指定位置開始顯示所給數(shù)字,Number 要顯示的數(shù)字,范圍:0~65535,Length 要顯示數(shù)字的長度,范圍:1~5{ unsigned char i; LCD_SetCursor(Line,Column); for(i=Length;i>0;i--) { LCD_WriteData(Number/LCD_Pow(10,i-1)%10+"0"); }}? [2]OLED模塊:
(1)原理:
①概念及優(yōu)勢:
OLED,又稱為有機電激光顯示、有機發(fā)光半導體。OLED屬于一種電流型的有機發(fā)光器件,是通過載流子 的注入和復合而致發(fā)光的現(xiàn)象,發(fā)光強度與注入的電流成正比。OLED在電場的作用下,陽極產(chǎn)生的空穴和 陰極產(chǎn)生的電子就會發(fā)生移動,分別向空穴傳輸層和電子傳輸層注入,遷移到發(fā)光層。當二者在發(fā)光層相 遇時,產(chǎn)生能量激子,從而激發(fā)發(fā)光分子最終產(chǎn)生可見光。OLED顯示屏比LCD更輕薄、亮度高、功耗低、 響應快、清晰度高、柔性好、發(fā)光效率高,能滿足消費者對顯示技術的新需求。全球越來越多的顯示器廠 家紛紛投入研發(fā),大大的推動了OLED的產(chǎn)業(yè)化進程。
②SPI接口方式、IIC接口方式:
參考CSDN博客UART, SPI, IIC的詳解及三者的區(qū)別和聯(lián)系_小凡的專欄-CSDN博客
本次制作采用SPI接口方式。
③OLED的顯示原理:
本次制作采用8080接口方式,其對應的并行接口圖如上所示:
并行接口的各個信號線的含義:
GND 地
VCC 電源,3.3V~5V
D0 4 線 ISP 接口模式:時鐘線(CLK) PA4
D1 4 線 ISP 接口模式:串行數(shù)據(jù)線(MOSI)PA3
RES 4 線 ISP 接口模式:命令/數(shù)據(jù)標志位(RET復位)PA2
DC 命令/數(shù)據(jù)標志位 A1
CS OLED 片選
模塊的8080并口讀/寫的過程為:
——將數(shù)據(jù)放到數(shù)據(jù)口;
——根據(jù)要寫入/讀取的數(shù)據(jù)的類型,設置DC(RS)為高(數(shù)據(jù))/低(命令);
——拉低片選,選中SSD1306;
——接著我們根據(jù)是讀數(shù)據(jù),還是要寫數(shù)據(jù)置RD/WR為低;
——讀數(shù)據(jù)過程:在RD的上升沿, 使數(shù)據(jù)鎖存到數(shù)據(jù)線(D[7:0])上;
——寫數(shù)據(jù)過程:在WR的上升沿,使數(shù)據(jù)寫入到SSD1306里面;
——拉高CS和DC(RS)。
[
]
④OLED模塊顯存:
OLED本身是沒有顯存的,它的顯存是依賴于SSD1306提供的。
SSD1306顯存為128*64bit大小, SSD1306將全部顯存分為8頁,每頁128字節(jié)。
OLED相當于64行128列點陣,每個像素點,0點亮,1熄滅。
OLED將縱向64行分為8頁,每頁8行。
(2)代碼(不提供main函數(shù)內(nèi)容):
oled.h
#include#ifndef __OLED_H#define __OLED_H //#include "sys.h"http://#include "stdlib.h" ? #define OLED_CMD 0 //寫命令#define OLED_DATA 1 //寫數(shù)據(jù)#define OLED_MODE 0?//根據(jù)實際引腳位置修改sbit OLED_CS=P2^4; //片選sbit OLED_RST =P2^2;//復位sbit OLED_DC =P2^3;//數(shù)據(jù)/命令控制sbit OLED_SCL=P2^0;//時鐘 D0(SCLK)sbit OLED_SDIN=P2^1;//D1(MOSI) 數(shù)據(jù)?//定義命令#define OLED_CS_Clr() OLED_CS=0#define OLED_CS_Set() OLED_CS=1?#define OLED_RST_Clr() OLED_RST=0#define OLED_RST_Set() OLED_RST=1?#define OLED_DC_Clr() OLED_DC=0#define OLED_DC_Set() OLED_DC=1?#define OLED_SCLK_Clr() OLED_SCL=0#define OLED_SCLK_Set() OLED_SCL=1?#define OLED_SDIN_Clr() OLED_SDIN=0#define OLED_SDIN_Set() OLED_SDIN=1;?????//OLED模式設置//0:4線串行模式//1:并行8080模式?#define SIZE 16#define XLevelL 0x02#define XLevelH 0x10#define Max_Column 128#define Max_Row 64#define Brightness 0xFF #define X_WIDTH 128#define Y_WIDTH 64 ? ?//-----------------OLED端口定義---------------- ? ? 2.oledfont.h(后面會講解)
#ifndef __OLEDFONT_H#define __OLEDFONT_H ? unsigned char xdata sjb[][12]={?{0x00,0x20,0x18,0xCC,0x48,0x48,0xF8,0x48,0x48,0x48,0x08,0x00},{0x00,0x04,0x04,0x07,0x04,0x04,0x7F,0x04,0x04,0x04,0x04,0x04},/*"年",0*/?{0x00,0x00,0x00,0xF8,0x48,0x48,0x48,0x48,0x48,0xF8,0x00,0x00},{0x00,0x40,0x60,0x1F,0x02,0x02,0x02,0x42,0x42,0x7F,0x00,0x00},/*"月",1*/?{0x00,0x00,0xF8,0x08,0x08,0x08,0x08,0x08,0x08,0xF8,0x00,0x00},{0x00,0x00,0x7F,0x11,0x11,0x11,0x11,0x11,0x11,0x3F,0x00,0x00},/*"日",2*/?{0x00,0xF8,0x88,0x88,0xF8,0x20,0x20,0x20,0x20,0xFC,0x20,0x20},{0x00,0x3F,0x08,0x08,0x1F,0x00,0x01,0x42,0x40,0x7F,0x00,0x00},/*"時",3*/?{0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x04,0x18,0x60,0x80,0x00},{0x00,0x01,0x40,0x21,0x11,0x0F,0x01,0x41,0x41,0x3F,0x00,0x00},/*"分",4*/?{0x00,0x48,0xC8,0xF8,0x44,0x44,0xE0,0x10,0xFC,0x10,0x60,0x80},{0x00,0x0C,0x03,0x7F,0x01,0x47,0x40,0x20,0x37,0x18,0x06,0x00},/*"秒",5*/?{0x00,0x00,0x00,0xF8,0xA8,0xA8,0xA8,0xA8,0xA8,0xF8,0x00,0x00},{0x00,0x48,0x47,0x4A,0x4A,0x4A,0x7F,0x4A,0x4A,0x4A,0x42,0x40},/*"星",6*/?{0x00,0x10,0xFC,0x50,0x50,0xFC,0x10,0xF8,0x48,0x48,0xF8,0x00},{0x00,0x64,0x1F,0x15,0x15,0x37,0x64,0x1F,0x02,0x42,0x7F,0x00},/*"期",7*/?};?unsigned char xdata xq[][24]={ {0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80},{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"一",0*/?{0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00},{0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},/*"二",1*/?{0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x00},{0x00,0x20,0x20,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x20,0x20},/*"三",2*/?{0x00,0x00,0xF8,0x08,0x08,0xF8,0x08,0xF8,0x08,0x08,0xF8,0x00},{0x00,0x00,0x7F,0x14,0x13,0x10,0x10,0x17,0x14,0x14,0x7F,0x00},/*"四",3*/?{0x00,0x08,0x88,0x88,0xE8,0x98,0x88,0x88,0x88,0x08,0x00,0x00},{0x20,0x20,0x20,0x30,0x2F,0x20,0x20,0x20,0x3F,0x20,0x20,0x00},/*"五",4*/?{0x00,0x40,0x40,0x40,0x40,0x4C,0x70,0x40,0x40,0x40,0x40,0x40},{0x00,0x20,0x30,0x0C,0x03,0x00,0x00,0x00,0x06,0x08,0x30,0x00},/*"六",5*/?{0x00,0x00,0x00,0x00,0x00,0xFC,0x80,0x80,0x80,0x40,0x40,0x40},{0x00,0x01,0x01,0x01,0x01,0x7F,0x40,0x40,0x40,0x40,0x40,0x70},/*"七",6*/?{0x00,0x00,0xF8,0x08,0x08,0x08,0x08,0x08,0x08,0xF8,0x00,0x00},{0x00,0x00,0x7F,0x11,0x11,0x11,0x11,0x11,0x11,0x3F,0x00,0x00},/*"日",7*/???};??unsigned char code sj[][16]={{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00},{0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00},/*"0",0*/?{0x00,0x00,0x10,0x10,0xF8,0x00,0x00,0x00},{0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00},/*"1",1*/?{0x00,0x70,0x08,0x08,0x08,0x08,0xF0,0x00},{0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00},/*"2",2*/?{0x00,0x30,0x08,0x08,0x08,0x88,0x70,0x00},{0x00,0x18,0x20,0x21,0x21,0x22,0x1C,0x00},/*"3",3*/?{0x00,0x00,0x80,0x40,0x30,0xF8,0x00,0x00},{0x00,0x06,0x05,0x24,0x24,0x3F,0x24,0x24},/*"4",4*/?{0x00,0xF8,0x88,0x88,0x88,0x08,0x08,0x00},{0x00,0x19,0x20,0x20,0x20,0x11,0x0E,0x00},/*"5",5*/?{0x00,0xE0,0x10,0x88,0x88,0x90,0x00,0x00},{0x00,0x0F,0x11,0x20,0x20,0x20,0x1F,0x00},/*"6",6*/?{0x00,0x18,0x08,0x08,0x88,0x68,0x18,0x00},{0x00,0x00,0x00,0x3E,0x01,0x00,0x00,0x00},/*"7",7*/?{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00},{0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00},/*"8",8*/?{0x00,0xF0,0x08,0x08,0x08,0x10,0xE0,0x00},{0x00,0x01,0x12,0x22,0x22,0x11,0x0F,0x00},/*"9",9*/???};unsigned char xdata sj2[][8]={{0x00,0x3C,0x44,0x44,0x44,0x44,0x3C,0x00},/*"0",0*//* (8 X 8 , 方正姚體 )*/{0x00,0x00,0x08,0x04,0x7C,0x00,0x00,0x00},/*"1",1*//* (8 X 8 , 方正姚體 )*/{0x00,0x4C,0x64,0x64,0x54,0x54,0x4C,0x00},/*"2",2*//* (8 X 8 , 方正姚體 )*/{0x00,0x64,0x44,0x54,0x54,0x5C,0x2C,0x00},/*"3",3*//* (8 X 8 , 方正姚體 )*/{0x20,0x30,0x30,0x28,0x24,0x7C,0x20,0x00},/*"4",4*//* (8 X 8 , 方正姚體 )*/{0x00,0x5C,0x54,0x54,0x54,0x54,0x30,0x00},/*"5",5*//* (8 X 8 , 方正姚體 )*/{0x00,0x7C,0x54,0x54,0x54,0x54,0x74,0x00},/*"6",6*//* (8 X 8 , 方正姚體 )*/{0x00,0x00,0x44,0x34,0x1C,0x0C,0x04,0x00},/*"7",7*//* (8 X 8 , 方正姚體 )*/{0x00,0x6C,0x5C,0x54,0x54,0x5C,0x6C,0x00},/*"8",8*//* (8 X 8 , 方正姚體 )*/{0x00,0x5C,0x54,0x64,0x64,0x54,0x3C,0x00},/*"9",9*//* (8 X 8 , 方正姚體 )*/};?unsigned char xdata bd[][2]={{0x36,0x36},/*":"*/{0x60,0x60},/*"."*/};#endif3.oled.c(初始化在最下方)
#include "oled.h"http://#include "stdlib.h"#include "oledfont.h" ?#include "math.h" ? void delay_ms(unsigned int ms){ ? ? ? ? ? ? ? ? ? ? ? ? unsigned int a; while(ms) { a=1800; while(a--); ms--; } return;}#if OLED_MODE==1//向SSD1106寫入一個字節(jié)。//dat:要寫入的數(shù)據(jù)/命令//cmd:數(shù)據(jù)/命令標志 0,表示命令;1,表示數(shù)據(jù);void OLED_WR_Byte(unsigned char dat,unsigned char cmd){ DATAOUT(dat); ? ? if(cmd) OLED_DC_Set(); else OLED_DC_Clr(); ? OLED_CS_Clr(); OLED_WR_Clr(); OLED_WR_Set(); OLED_CS_Set(); ? OLED_DC_Set(); } ? ? ?#else//向SSD1306寫入一個字節(jié)。//dat:要寫入的數(shù)據(jù)/命令//cmd:數(shù)據(jù)/命令標志 0,表示命令;1,表示數(shù)據(jù);void OLED_WR_Byte(unsigned char dat,unsigned char cmd){ unsigned char i; ? if(cmd) OLED_DC_Set(); else OLED_DC_Clr(); ? OLED_CS_Clr(); for(i=0;i<8;i++) { ? OLED_SCLK_Clr(); if(dat&0x80) { ? OLED_SDIN_Set(); }else ? OLED_SDIN_Clr(); OLED_SCLK_Set(); dat<<=1; ? } ? OLED_CS_Set(); OLED_DC_Set(); ? ?} #endifvoid OLED_Set_Pos(unsigned char x, unsigned char y) { OLED_WR_Byte(0xb0+y,OLED_CMD); OLED_WR_Byte((((x+2)&0xf0)>>4)|0x10,OLED_CMD); OLED_WR_Byte(((x+2)&0x0f),OLED_CMD); } ? //開啟OLED顯示 ? ??//清屏函數(shù),清完屏,整個屏幕是黑色的!和沒點亮一樣!!! ?void OLED_Clear(void) ?{ ? unsigned char i,n; ? ? for(i=0;i<8;i++) ? { ? OLED_WR_Byte (0xb0+i,OLED_CMD); ? //設置頁地址(0~7) OLED_WR_Byte (0x02,OLED_CMD); ? ? //設置顯示位置—列低地址 OLED_WR_Byte (0x10,OLED_CMD); ? ? //設置顯示位置—列高地址 ? for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA); } //更新顯示}??//在指定位置顯示一個字符,包括部分字符//x:0~127//y:0~63//mode:0,反白顯示;1,正常顯示 //size:選擇字體 16/12 void OLED_ShowChar(unsigned char x,unsigned char y,unsigned char chr){ ? ? unsigned char c=0,i=0; c=chr-" ";//得到偏移后的值 if(x>Max_Column-1){x=0;y=y+2;} if(SIZE ==16) { OLED_Set_Pos(x,y); for(i=0;i<8;i++) OLED_WR_Byte(F8X16[c*16+i],OLED_DATA); OLED_Set_Pos(x,y+1); for(i=0;i<8;i++) OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA); } else { OLED_Set_Pos(x,y+1); for(i=0;i<6;i++) OLED_WR_Byte(F6x8[c][i],OLED_DATA); }}//m^n函數(shù)unsigned int oled_pow(unsigned char m,unsigned char n){ unsigned int result=1; while(n--)result*=m; ? ? return result;} ?//顯示2個數(shù)字//x,y :起點坐標 //len :數(shù)字的位數(shù)//size:字體大小//mode:模式 0,填充模式;1,疊加模式//num:數(shù)值(0~4294967295); ?/*void OLED_ShowNum(unsigned char x,unsigned char y,unsigned int num,unsigned char len,unsigned char size2){ ? ? ? ? unsigned char t,temp; unsigned char enshow=0; ? for(t=0;t120){x=0;y+=2;} j++; }}//顯示漢字數(shù)組:年、月、日、時、分、秒、星、期void OLED_ShowCHinese1(unsigned char x,unsigned char y,unsigned char no){ ? ? ? ? unsigned char t,adder=0; OLED_Set_Pos(x,y); ? for(t=0;t<12;t++) { OLED_WR_Byte(sjb[2*no][t],OLED_DATA); adder+=1; ? ? } OLED_Set_Pos(x,y+1); ? for(t=0;t<12;t++) { OLED_WR_Byte(sjb[2*no+1][t],OLED_DATA); adder+=1; ? ? } }void OLED_ShowCHinese2(unsigned char x,unsigned char y,unsigned char no){ ? ? ? ? unsigned char t,adder=0; OLED_Set_Pos(x,y); ? for(t=0;t<12;t++) { OLED_WR_Byte(xq[2*no][t],OLED_DATA); adder+=1; ? ? } OLED_Set_Pos(x,y+1); ? for(t=0;t<12;t++) { OLED_WR_Byte(xq[2*no+1][t],OLED_DATA); adder+=1; ? ? } }void OLED_ShowNumber(unsigned char x,unsigned char y,unsigned char no){ ? ? ? ? unsigned char t,adder=0; OLED_Set_Pos(x,y); ? for(t=0;t<8;t++) { OLED_WR_Byte(sj[2*no][t],OLED_DATA); adder+=1; ? ? } OLED_Set_Pos(x,y+1); ? for(t=0;t<8;t++) { OLED_WR_Byte(sj[2*no+1][t],OLED_DATA); adder+=1; ? ? } }void OLED_ShowNumber2(unsigned char x,unsigned char y,unsigned char no){ ? ? ? ? unsigned char t,adder=0; OLED_Set_Pos(x,y); ? for(t=0;t<8;t++) { OLED_WR_Byte(sj2[no][t],OLED_DATA); adder+=1; ? } }?void OLED_Showbd(unsigned char x,unsigned char y,unsigned char no){ unsigned char t,adder=0; OLED_Set_Pos(x,y); ? for(t=0;t<2;t++) { OLED_WR_Byte(bd[no][t],OLED_DATA); adder+=1; ? } }?unsigned char xdata OLED_GRAM[8][128]; //8行128列---->8頁128列/*函數(shù)功能: 畫點函數(shù)函數(shù)參數(shù):unsigned char x 橫坐標 0~127unsigned char y 縱坐標 0~63unsigned char c 顯示值(0滅 1亮)*/void OLED_DisplayPoint(unsigned char x,unsigned char y,unsigned char c){ ? unsigned char page=y/8;//0~7 ? y=y%8; ? if(c) ? { ? ? ? OLED_GRAM[page][x]|=1< 0)incx=1; //設置單步方向 else if(delta_x==0)incx=0;//垂直線 else {incx=-1;delta_x=-delta_x;} if(delta_y>0)incy=1; else if(delta_y==0)incy=0;//水平線 else{incy=-1;delta_y=-delta_y;} if( delta_x>delta_y)distance=delta_x; //選取基本增量坐標軸 else distance=delta_y; for(t=0;t<=distance+1;t++ )//畫線輸出 { ? OLED_DisplayPoint(uRow,uCol,1);//畫點 xerr+=delta_x ; yerr+=delta_y ; if(xerr>distance) { xerr-=distance; uRow+=incx; } if(yerr>distance) { yerr-=distance; uCol+=incy; } } ?} ?? /*函數(shù)功能:任意角度畫直線 參 ? 數(shù): x,y:坐標 du :度數(shù) len:半徑 w :線段的長度 c :顏色值 0或者1例如:OLED_DrawAngleLine(60,30,45,20,20,1);//角度畫線*/?void OLED_DrawAngleLine(unsigned int x,unsigned int y,float du,unsigned int len,unsigned int w,unsigned char c){ int i; int x0,y0; double k=du*(3.1415926535/180); for(i=len-w;i (二)仿真電路及電路模塊
1.實物圖正面
2.部分原理圖(手繪稿在寫本日志時已被處理)
3.仿真圖
(三)鬧鐘及日歷邏輯模塊
1.鬧鐘模塊:
(1)基礎設置:
(2)藍牙拓展設置:
利用中斷系統(tǒng)和二維數(shù)組存儲鬧鐘信息,比較時間儲存數(shù)組,相等時蜂鳴器響起(基礎見上)。
//進入鬧鐘設定 if(SBUF==0x02) {do{ int k1=0; int k2=0; int i; while(RI==0); UART_SendByte(SBUF); RI=0;//得到了第一次信息? if(SBUF==0x20)//進入設定模式 { while(RI==0); UART_SendByte(SBUF); RI=0;//第二次信息:用于選擇第幾個鬧鐘 switch(SBUF) { case 0x00:k1=0;break; case 0x01:k1=1;break; case 0x02:k1=2;break; case 0x03:k1=3;break; case 0x04:k1=4;break; case 0x05:k1=5;break; case 0x06:k1=6;break; case 0x07:k1=7;break; } do { while(RI==0); UART_SendByte(SBUF); RI=0;//第三次信息:確定給到鬧鐘信息的哪位 switch(SBUF) { case 0x0a:k2=0;break; case 0x0b:k2=1;break; case 0x0c:k2=2;break; case 0x0d:k2=3;break; case 0x0e:k2=4;break; default:break; } if(SBUF!=0x50) { while(RI==0); UART_SendByte(SBUF); RI=0;//第四次信息:確定鬧鐘內(nèi)的數(shù) Alarm_Time[k1][k2]=SBUF; } }while(SBUF!=0x50); SBUF=0xff; }? if(SBUF==0x30)//進入刪除模式 { while(RI==0); UART_SendByte(SBUF); RI=0;//第二次信息:選擇鬧鐘 switch(SBUF) { case 0x00:k1=0;break; case 0x01:k1=1;break; case 0x02:k1=2;break; case 0x03:k1=3;break; case 0x04:k1=4;break; case 0x05:k1=5;break; case 0x06:k1=6;break; case 0x07:k1=7;break; } for(i=0;i<5;i++) { Alarm_Time[k1][i]=0; } SBUF=0xff; } if(SBUF==0x41)//關閉鬧鐘 { if(Alarm_state==1) {Alarm_state=0;} SBUF=0xff; } if(SBUF==0x40)//開啟鬧鐘 { if(Alarm_state==0) {Alarm_state=1;} SBUF=0xff; } }while(SBUF!=0x60);//結(jié)束設定鬧鐘 }2.日歷模塊:
利用手機app發(fā)送文本,單片機利用中斷系統(tǒng)多次接受信息后在oled屏幕上顯示日歷。
代碼及解釋如下:
int xdata Rili1[][3]={0};int xdata Rili2[][17]={0};//進入日歷模式 if(SBUF==0x03) {do{ int k1,k2,k3,i,i5,i6; int a1,a2,a3,a4,a5,a6,a7,a8,a9; int temp; i=0; i5=0; i6=1; while(RI==0); UART_SendByte(SBUF); RI=0;//得到第一次信息 if(SBUF==0x01)//第一次信息:設定日歷 {do{ while(RI==0); UART_SendByte(SBUF); RI=0;//第二次信息:選擇日歷數(shù)組位置 switch(SBUF) { case 0x11:k1=0;break; case 0x12:k1=1;break; case 0x13:k1=2;break; default:break; } if(SBUF!=0x00) { while(RI==0); UART_SendByte(SBUF); RI=0;//第三次信息:確定日歷日期數(shù)據(jù) while(Rili1[i][k1]!=0) { i++; } Rili1[i][k1]=SBUF; cs=i; } }while(SBUF!=0x00);// do { while(RI==0); UART_SendByte(SBUF); RI=0;//第四次信息:確定是哪個字 switch(SBUF) { case 0x01:k3=0;break; case 0x02:k3=1;break; case 0x03:k3=2;break; case 0x04:k3=3;break; case 0x05:k3=4;break; case 0x06:k3=5;break; case 0x07:k3=6;break; case 0x08:k3=7;break; case 0x09:k3=8;break; case 0x0a:k3=9;break; case 0x0b:k3=10;break; case 0x0c:k3=11;break; case 0x0d:k3=12;break; case 0x0e:k3=13;break; case 0x0f:k3=14;break; case 0x10:k3=15;break; default:break; } while(RI==0); UART_SendByte(SBUF); RI=0;//第五次信息:確定字在哪里 switch(SBUF) { case 0x01:k2=0;break; case 0x02:k2=1;break; case 0x03:k2=2;break; case 0x04:k2=3;break; case 0x05:k2=4;break; case 0x06:k2=5;break; case 0x07:k2=6;break; case 0x08:k2=7;break; case 0x09:k2=8;break; case 0x0a:k2=9;break; case 0x0b:k2=10;break; case 0x0c:k2=11;break; case 0x0d:k2=12;break; case 0x0e:k2=13;break; case 0x0f:k2=14;break; case 0x10:k2=15;break; } while(Rili2[i5][0]!=0) {i5++;} Rili2[i5][0]=Rili1[i][0]*385+Rili1[i][1]*32+Rili1[i][2]; while(Rili2[i5][i6]!=0) {i6++;} Rili2[i5][i6]=(k2+1)*16+k3; i5=0; i6=1; }while(SBUF!=0x80);//排序日歷: a2=0; a4=1; while(Rili2[a2][0]!=0) a2++; for(a1=0;a1Rili2[a1][a6+1]) { temp=Rili2[a1][a6+1]; ? Rili2[a1][a6+1]=Rili2[a1][a6]; ? Rili2[a1][a6]=temp; ? } } } a4=0; } for(a7=0;a7 Rili2[a8+1][0]) { for(a9=0;a9<17;a9++) { temp=Rili2[a8+1][a9]; ? Rili2[a8+1][a9]=Rili2[a8][a9]; ? Rili2[a8][a9]=temp; } } ? } } } if(SBUF==0x02)//第一次信息:刪除日歷 {do{ int i1=0; int i2=0; int i3=0; while(RI==0); UART_SendByte(SBUF); RI=0;//第二次信息:選擇要刪除的項數(shù) while(Rili2[i1][0]!=0) i1++; for(i2=0;i2<17;i2++) { Rili2[SBUF-1][i2]=0; } for(i3=SBUF-1;i3 利用手機發(fā)送數(shù)據(jù)在單片機中儲存,用二維數(shù)組保存信息,隨后解釋信息,按時間排序日歷順序并將其顯示在oled屏幕上(由于oled屏幕小無法全部顯示,所以只有范例文字,oled詳細代碼不再展示,感興趣的可以深入研究)。
(四)手機app模塊
本次手機app開發(fā)使用了較為簡單的app inventor進行開發(fā),在此進行簡單介紹
1.簡介: App Inventor 原是Google實驗室(Google Lab)的一個子計劃,由一群Google工程師和勇于挑戰(zhàn)的 Google使用者共同參與設計完成。Google App Inventor是一個完全在線開發(fā)的Android編程環(huán)境,拋棄復雜的 程式代碼而使用積木式的堆疊法來完成您的Android程式。除此之外它也正式支持樂高NXT機器人,對Android 初學者或是機器人開發(fā)者來說是一大福音。因為對于想要用手機控制機器人的使用者而言,他們不大需要太華 麗的界面,只要使用基本元件例如按鈕、文字輸入輸出即可。
2.下載:
(1)直接登錄網(wǎng)站(免下載)
麻省理工學院的服務器登錄地址:Redirecting…——這是英語版的。
推薦使用國內(nèi)的廣州服務器:MIT App Inventor——建議使用chrome瀏覽器打開
其他個人搭建的服務器也可查詢csdn或簡書
(2)離線版下載:
鏈接:百度網(wǎng)盤 請輸入提取碼 ? 提取碼:zzh6
3.內(nèi)容學習:詳情見上的b站教程(個人認為做的很好)。
4.代碼展示及界面簡介:
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/125578.html
摘要:文章目錄一作品背景二功能要求三實現(xiàn)基礎功能一首先是要選材二原理圖設計二第一版本設計三焊接板四編寫單片機程序五下載程序驗證四外殼設計一圖紙設計二磨砂亞克力板五重新設計六安卓設計一界面設計二程序設計三功能設計作品嗶哩嗶哩視 ...
摘要:園區(qū)項目一期機房規(guī)劃建設萬個機架,今年月底中國電信開普勒佛山大數(shù)據(jù)中心首批機架個將投入運營。近年來,以云計算、大數(shù)據(jù)為代表的互聯(lián)網(wǎng)等電子信息產(chǎn)業(yè)正呈現(xiàn)出良好發(fā)展勢頭,創(chuàng)新企業(yè)層出不窮,聚焦電子信息產(chǎn)業(yè)的產(chǎn)業(yè)園區(qū)也在全國各地遍地開花在這樣的大背景之下,佛山市互聯(lián)網(wǎng)+創(chuàng)新創(chuàng)業(yè)產(chǎn)業(yè)園應運而生。總投資約80億元, 總建設規(guī)模為40000個機架。佛山市互聯(lián)網(wǎng)+創(chuàng)新創(chuàng)業(yè)產(chǎn)業(yè)園選址佛山居住、產(chǎn)業(yè)和生態(tài)的新...
摘要:本文搭建了一個藍牙遙控器,可配合等藍牙模塊,對小車實現(xiàn)八方向遙控。其他七個按鍵同理,很快,一個藍牙遙控就做好了,修改藍色框的數(shù)字值,可以更改發(fā)送命令。將藍牙模塊接上轉(zhuǎn),用串口助手可以對他進行測試。 ...
摘要:如果使用區(qū)塊鏈技術則可以降低使用版權的門檻。價值化,藝人利益得到保證高曉松在談到區(qū)塊鏈時,也贊成藝人發(fā)行來跳過娛樂公司。通過區(qū)塊鏈技術藝人可以更加貼合粉絲,創(chuàng)造出更高效的內(nèi)容推薦和特色化的消費產(chǎn)品與服務體驗。 2019年1月3日,高曉松的《曉說》在朋友圈刷屏了。 這次高曉松沒有談風花雪月、詩與遠方,而是在其母校清華大學的教室里,跟學弟學妹們深入淺出地聊起了區(qū)塊鏈在文娛產(chǎn)業(yè)的革命。 在傳...
摘要:如果使用區(qū)塊鏈技術則可以降低使用版權的門檻。價值化,藝人利益得到保證高曉松在談到區(qū)塊鏈時,也贊成藝人發(fā)行來跳過娛樂公司。通過區(qū)塊鏈技術藝人可以更加貼合粉絲,創(chuàng)造出更高效的內(nèi)容推薦和特色化的消費產(chǎn)品與服務體驗。 2019年1月3日,高曉松的《曉說》在朋友圈刷屏了。 這次高曉松沒有談風花雪月、詩與遠方,而是在其母校清華大學的教室里,跟學弟學妹們深入淺出地聊起了區(qū)塊鏈在文娛產(chǎn)業(yè)的革命。 在傳...
閱讀 3735·2023-01-11 11:02
閱讀 4244·2023-01-11 11:02
閱讀 3050·2023-01-11 11:02
閱讀 5180·2023-01-11 11:02
閱讀 4735·2023-01-11 11:02
閱讀 5533·2023-01-11 11:02
閱讀 5313·2023-01-11 11:02
閱讀 3986·2023-01-11 11:02