wordpress 插件 支付搜索引擎關(guān)鍵詞優(yōu)化有哪些技巧
之前學(xué)習(xí)過(guò)用定時(shí)器做的時(shí)鐘,但是那樣不僅誤差大還費(fèi)CPU,接下來(lái)利用DS1302時(shí)鐘模塊做一個(gè)可調(diào)實(shí)時(shí)時(shí)鐘
這一次直接編寫(xiě)DS1302模塊,首先要在DS1392.c 中根據(jù)下面的模塊原理圖進(jìn)行位聲明:
sbit DS1302_SCLK = P3^6;
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;
命令字: 命令字確定了是要寫(xiě)還是要讀,以及操作的是時(shí)還是分還是秒
首先需要一個(gè)初始化函數(shù):
void DS1302_Init(void)
{DS1302_CE = 0;DS1302_SCLK = 0;
}
工作時(shí)CE必須置1,上升沿的時(shí)候可以讀, 下降沿的時(shí)候可以寫(xiě)
可以理解為0是寫(xiě)入模式,1是讀取模式
IO口從左往右是由低位到高位
要注意時(shí)序圖中Read比Write少一個(gè)脈沖因?yàn)樗仙?完成了最后一個(gè)命令行位的寫(xiě)入之后馬上要回到0開(kāi)始進(jìn)行讀取功能了
單字節(jié)寫(xiě)入函數(shù):
按照時(shí)序圖進(jìn)行模擬,Command:命令行,Data:寫(xiě)入的數(shù)據(jù)
void DS1302_WriteByte(unsigned char Command, Data)
{unsigned char i;DS1302_CE = 1;for(i = 0; i < 8; i ++) {DS1302_IO = Command & (0x01 << i); //IO非0即1,從低到高每次取出一位DS1302_SCLK = 1;Delay(10);DS1302_SCLK = 0;}for(i = 0; i < 8; i ++) {DS1302_IO = Data & (0x01 << i); //IO非0即1,從低到高每次取出一位DS1302_SCLK = 1;Delay(10);DS1302_SCLK = 0;}DS1302_CE = 0;
}
單字節(jié)讀出函數(shù)
unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i, Data = 0x00;DS1302_CE = 1;for(i = 0; i < 8; i ++) {DS1302_IO = Command & (0x01 << i); //IO非0即1,從低到高每次取出一位DS1302_SCLK = 0; //寫(xiě)入Delay(10);DS1302_SCLK = 1; //這樣在不改變寫(xiě)入時(shí)序的同時(shí)還能保證最后是1}Delay(10);//接下來(lái)要讀的數(shù)據(jù)已經(jīng)在IO口上了已經(jīng)可以讀了for(i = 0; i < 8; i ++) {DS1302_SCLK = 1; //讀入Delay(10);DS1302_SCLK = 0;if(DS1302_IO) {Data |= (0x01 << i);} //把IO口的數(shù)據(jù)由低位到高位復(fù)現(xiàn)在Data上}DS1302_IO = 0;DS1302_CE = 0;return Data;
}
要注意在main.c中使用時(shí)需要在DS1302初始化后,調(diào)用:DS1302_WriteByte(0x8E, 0x00); //關(guān)閉寫(xiě)入保護(hù)
再進(jìn)行正常的寫(xiě)入
但其實(shí),在DS1302模塊的寄存器存儲(chǔ)的數(shù)據(jù)都是BCD碼
所以時(shí)鐘的秒會(huì)從1, 2, ····9然后直接跳到16
9 = 0000 1001
根據(jù)BCD的進(jìn)位原則,四位二進(jìn)制數(shù)達(dá)到10就要清零進(jìn)位了,下一個(gè)BCD碼是:
0001 0000 這個(gè)數(shù)以十進(jìn)制顯示在LCD上就是16
此時(shí)只要把ShowNum改成ShowHexNum即可正常顯示10, 11, 12·····
也可以利用公式來(lái)用十進(jìn)制顯示:
LCD_ShowNum(2, 1, Sec / 16 * 10 + Sec % 16, 3 );
接下來(lái)就可以編寫(xiě)一個(gè)完整的時(shí)鐘模塊了
#include <REGX52.H>
#include "Delay.h"sbit DS1302_SCLK = P3^6;
sbit DS1302_IO = P3^4;
sbit DS1302_CE = P3^5;//其實(shí)寫(xiě)的地址 或上 0x01 就是讀的地址了
//所以下面只要重定義寫(xiě)的地址就行了
#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 //寫(xiě)入保護(hù)的地址unsigned char DS1302_Time[] = {23, 8, 2, 10, 28, 50, 3};void DS1302_Init(void)
{DS1302_CE = 0;DS1302_SCLK = 0;
}void DS1302_WriteByte(unsigned char Command, Data)
{unsigned char i;DS1302_CE = 1;for(i = 0; i < 8; i ++) {DS1302_IO = Command & (0x01 << i); //IO非0即1,從低到高每次取出一位DS1302_SCLK = 1;Delay(10);DS1302_SCLK = 0;}for(i = 0; i < 8; i ++) {DS1302_IO = Data & (0x01 << i); //IO非0即1,從低到高每次取出一位DS1302_SCLK = 1;Delay(10);DS1302_SCLK = 0;}DS1302_CE = 0;
}unsigned char DS1302_ReadByte(unsigned char Command)
{unsigned char i, Data = 0x00;DS1302_CE = 1;for(i = 0; i < 8; i ++) {DS1302_IO = Command & (0x01 << i); //IO非0即1,從低到高每次取出一位DS1302_SCLK = 0; //寫(xiě)入Delay(10);DS1302_SCLK = 1; //這樣在不改變寫(xiě)入時(shí)序的同時(shí)還能保證最后是1}Delay(10);//接下來(lái)要讀的數(shù)據(jù)已經(jīng)在IO口上了已經(jīng)可以讀了for(i = 0; i < 8; i ++) {DS1302_SCLK = 1; //讀入Delay(10);DS1302_SCLK = 0;if(DS1302_IO) {Data |= (0x01 << i);} //把IO口的數(shù)據(jù)由低位到高位復(fù)現(xiàn)在Data上}DS1302_IO = 0;DS1302_CE = 0;return Data;
}void DS1302_SetTime(void) //將數(shù)組中的時(shí)間寫(xiě)入芯片
{DS1302_WriteByte(DS1302_WP, 0x00); //關(guān)閉寫(xiě)保護(hù)DS1302_WriteByte(DS1302_YEAR, DS1302_Time[0]/10*16+DS1302_Time[0]%10);DS1302_WriteByte(DS1302_MONTH, DS1302_Time[1]/10*16+DS1302_Time[1]%10);DS1302_WriteByte(DS1302_DATE, DS1302_Time[2]/10*16+DS1302_Time[2]%10);DS1302_WriteByte(DS1302_HOUR, DS1302_Time[3]/10*16+DS1302_Time[3]%10);DS1302_WriteByte(DS1302_MINUTE, DS1302_Time[4]/10*16+DS1302_Time[4]%10);DS1302_WriteByte(DS1302_SECOND, DS1302_Time[5]/10*16+DS1302_Time[5]%10);DS1302_WriteByte(DS1302_DAY, DS1302_Time[6]/10*16+DS1302_Time[6]%10);DS1302_WriteByte(DS1302_WP, 0x80); //打開(kāi)寫(xiě)保護(hù)
}void DS1302_ReadTime(void) //把芯片中的時(shí)間讀到數(shù)組中
{unsigned char temp;temp = DS1302_ReadByte(DS1302_YEAR | 0x01); //寫(xiě)的地址或上0x01就是讀的地址DS1302_Time[0] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_MONTH | 0x01);DS1302_Time[1] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_DATE | 0x01);DS1302_Time[2] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_HOUR | 0x01);DS1302_Time[3] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_MINUTE | 0x01);DS1302_Time[4] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_SECOND | 0x01);DS1302_Time[5] = temp/16*10+temp%16;temp = DS1302_ReadByte(DS1302_DAY | 0x01);DS1302_Time[6] = temp/16*10+temp%16;
}
其實(shí)如果把BCD碼與十進(jìn)制相互轉(zhuǎn)化的部分寫(xiě)成函數(shù)來(lái)處理,會(huì)大大減少代碼量
要注意,這個(gè)封裝好的DS1302.c要拿到外部調(diào)用的話(huà),其中的DS1302_Time數(shù)組也需要在頭文件中聲明,外部可調(diào)用的變量要加上關(guān)鍵字extern
#ifndef __DS1302_H__
#define __DS1302_H__extern unsigned char DS1302_Time[]; //外部可調(diào)用的變量也需要聲明void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command, Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);#endif
最后給出main.c代碼
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"unsigned char Sec;void main()
{LCD_Init();DS1302_Init();DS1302_WriteByte(0x8E, 0x00); //關(guān)閉寫(xiě)入保護(hù)LCD_ShowString(1, 1, " - - ");LCD_ShowString(2, 1, " : : ");DS1302_SetTime();while(1){DS1302_ReadTime();LCD_ShowNum(1, 1, DS1302_Time[0], 2);LCD_ShowNum(1, 4, DS1302_Time[1], 2);LCD_ShowNum(1, 7, DS1302_Time[2], 2);LCD_ShowNum(2, 1, DS1302_Time[3], 2);LCD_ShowNum(2, 4, DS1302_Time[4], 2);LCD_ShowNum(2, 7, DS1302_Time[5], 2);LCD_ShowNum(2, 10, DS1302_Time[6], 2);}
}
但是一個(gè)好的時(shí)鐘遠(yuǎn)不止顯示時(shí)間這么簡(jiǎn)單,還需要具有可調(diào)的功能。。
于是需要加入按鍵模塊實(shí)現(xiàn)修改時(shí)間和定時(shí)器模塊來(lái)實(shí)現(xiàn)光標(biāo)閃爍效果
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Key.h"
#include "Timer0.h"unsigned char MODE, KeyNum, TimeSetSelect, TimeFlash;void Time_Show(void) //在LCD顯示數(shù)組時(shí)間
{DS1302_ReadTime();LCD_ShowNum(1, 1, DS1302_Time[0], 2);LCD_ShowNum(1, 4, DS1302_Time[1], 2);LCD_ShowNum(1, 7, DS1302_Time[2], 2);LCD_ShowNum(2, 1, DS1302_Time[3], 2);LCD_ShowNum(2, 4, DS1302_Time[4], 2);LCD_ShowNum(2, 7, DS1302_Time[5], 2);LCD_ShowNum(2, 10, DS1302_Time[6], 2);
}void Time_Set(void) //利用按鍵修改數(shù)組并重新讀取數(shù)組顯示在LCD
{if(KeyNum == 2) //選擇修改的位置{TimeSetSelect ++;TimeSetSelect %= 7;}if(KeyNum == 3) //增加時(shí)間{DS1302_Time[TimeSetSelect] ++;}if(KeyNum == 4) //減少時(shí)間{DS1302_Time[TimeSetSelect] --;}//接下來(lái)更新顯示 if(TimeFlash == 0 && TimeSetSelect == 0) LCD_ShowString(1, 1, " ");//熄滅的時(shí)候用空格覆蓋else LCD_ShowNum(1, 1, DS1302_Time[0], 2);if(TimeFlash == 0 && TimeSetSelect == 1) LCD_ShowString(1, 4, " ");else LCD_ShowNum(1, 4, DS1302_Time[1], 2);if(TimeFlash == 0 && TimeSetSelect == 2) LCD_ShowString(1, 7, " ");else LCD_ShowNum(1, 7, DS1302_Time[2], 2);if(TimeFlash == 0 && TimeSetSelect == 3) LCD_ShowString(2, 1, " ");else LCD_ShowNum(2, 1, DS1302_Time[3], 2);if(TimeFlash == 0 && TimeSetSelect == 4) LCD_ShowString(2, 4, " ");else LCD_ShowNum(2, 4, DS1302_Time[4], 2);if(TimeFlash == 0 && TimeSetSelect == 5) LCD_ShowString(2, 7, " ");else LCD_ShowNum(2, 7, DS1302_Time[5], 2);if(TimeFlash == 0 && TimeSetSelect == 6) LCD_ShowString(2, 10, " ");else LCD_ShowNum(2, 10, DS1302_Time[6], 2);
}void Timer0_Routine() interrupt 1
{static unsigned int T0Count;TL0 = 0x66; //設(shè)置定時(shí)初值TH0 = 0xFC; //設(shè)置定時(shí)初值T0Count ++;if(T0Count >= 1000) //1s執(zhí)行一次{T0Count = 0;TimeFlash = !TimeFlash; //1的時(shí)候顯示數(shù)字,0的時(shí)候熄滅,達(dá)成閃爍}
}void main()
{LCD_Init();DS1302_Init();Timer0_Init();DS1302_WriteByte(0x8E, 0x00); //關(guān)閉寫(xiě)入保護(hù)LCD_ShowString(1, 1, " - - ");LCD_ShowString(2, 1, " : : ");DS1302_SetTime(); //先從數(shù)組中讀取時(shí)間到芯片里while(1){KeyNum = Key(); //讀取按鍵if(KeyNum == 1) //按下按鍵1切換時(shí)鐘模式{if(MODE == 1) {MODE = 0; DS1302_SetTime();} //回到顯示模式要重新讀取數(shù)組到芯片里else MODE = 1;}switch(MODE){case 0: Time_Show(); break;case 1: Time_Set(); break;}}
}
但是這個(gè)程序有個(gè)bug,就是修改時(shí)間的部分沒(méi)有進(jìn)行越界判斷,可能會(huì)出現(xiàn)13月,32日這樣的數(shù)據(jù),這個(gè)修改起來(lái)就是邏輯上的事情,在Time++或者–的時(shí)候特判一下就行,比較容易,這里偷個(gè)懶就不改了