国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當前位置: 首頁 > news >正文

html電子商務網(wǎng)站模板下載網(wǎng)絡平臺怎么推廣

html電子商務網(wǎng)站模板下載,網(wǎng)絡平臺怎么推廣,建立網(wǎng)站的程序,網(wǎng)站怎么做描文本這是I2C的系列的第三篇,這篇主要是寫一個簡單的程序來實踐一下相關的內容。前面博主寫過一個電子密碼鎖的程序初學51單片機之簡易電子密碼鎖及PWM應用擴展_51單片機設計電子密碼鎖-CSDN博客 本篇主要是在此基礎上修改下程序,讓密碼存儲在E2PROM中&#…

? ? ? 這是I2C的系列的第三篇,這篇主要是寫一個簡單的程序來實踐一下相關的內容。前面博主寫過一個電子密碼鎖的程序初學51單片機之簡易電子密碼鎖及PWM應用擴展_51單片機設計電子密碼鎖-CSDN博客

本篇主要是在此基礎上修改下程序,讓密碼存儲在E2PROM中,并且可以通過UART串口通信在線修改E2PROM存儲的密碼。

簡單的介紹下程序的功能:

1:筆者的開發(fā)版在燒錄該程序后一上電,除了數(shù)字鍵可以使能外其他按鍵是沒有功能的。因此需要輸入相應的密碼才能使能其他按鍵的功能。

2:程序的密碼是存放在24C02這個E2PROM器件“非易失區(qū)”的4個存儲地址中(0x00,0x01,0x02,0x03),以密碼2024為例,它是以字符形式‘2’、‘0’、‘2’、‘4’分別按順序存入的。由于密碼鎖的寫法有點問題,該程序目前只支持4位的密碼,

3:當輸入正確的密碼后,鍵盤的其它按鍵功能就能使用。在設置好倒計時比如10秒,按下entel鍵倒計時開始,10s后LED小燈就會被點亮(當然這個秒表還不是非常準確,沒仔細做時間補償),蜂鳴器蜂鳴。按下ESC會復位。

4:通過UART串口,可以通過輸入命令使能蜂鳴器?!癰uzz on”、"buzz off"能分別打開和關閉蜂鳴器?!皉eset password ” 命令能修改24C02存儲的數(shù)據(jù),以輸入命令“reset password 2024”為例,通信軟件接收收區(qū)會顯示命令語句reset password 2024,并且液晶上會顯示“2024”,同時修改了E2PROM密碼存儲區(qū)的數(shù)據(jù),修改后的密碼只會在下次開機啟動后使能。在線修改密碼上電后就可以修改。如果UART傳輸未定義命令,會在接收區(qū)顯示字符串“bad command”用以提醒輸入錯誤的指令。

5:在鍵盤輸入錯誤密碼后。數(shù)碼管基本顯示的是65526這幾個數(shù)字,這時板子無法再繼續(xù)輸入密碼。需要重啟板子才能再次嘗試輸入密碼。

6:該程序實現(xiàn)了UART串口通信,I2C通信的基本用法。對于UART串口通信,前面筆者有一篇博文使用"!"號作為命令結束的通用標識,本篇采用的是另外一種。它是基于對總線空閑時間的監(jiān)控來確定數(shù)據(jù)幀是否傳輸接收。(注意這個數(shù)據(jù)幀不是單指一個字節(jié)的數(shù)據(jù)幀也可能是多個字節(jié)一起構成一段數(shù)據(jù)幀),這個時間本案是30ms,即UART總線上空閑了30ms,就確認一段數(shù)據(jù)幀結束。并開始處理數(shù)據(jù)幀命令。

7:這個密碼鎖的寫法是筆者之前寫的,個人覺得不行,太麻煩。個人覺得把鍵盤輸入的鍵碼轉換為字節(jié)方式存入數(shù)組中,然后和E2PROM中的存儲的字節(jié)比較會快一點。

8:程序的主干來自開發(fā)版老師,一些功能擴展是筆者自己寫的。這個程序還是初版,有些功能還能優(yōu)化一下的,比如該程序目前只支持密碼修改,按密碼時的長短鍵要求還無法通過UART修改,目前該程序按密碼的時候都是短鍵使能。

看代碼:

main.c

#include <reg52.h>sbit BUZZ  = P1^6;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY_IN_1  = P2^4;
sbit KEY_IN_2  = P2^5;
sbit KEY_IN_3  = P2^6;
sbit KEY_IN_4  = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;unsigned char code LedChar[] = {  //數(shù)碼管顯示字符轉換表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[7] = {  //數(shù)碼管+獨立LED顯示緩沖區(qū)0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char code KeyCodeMap[4][4] = { //矩陣按鍵編號到標準鍵盤鍵碼的映射表{ 0x31, 0x32, 0x33, 0x26 }, //數(shù)字鍵1、數(shù)字鍵2、數(shù)字鍵3、向上鍵{ 0x34, 0x35, 0x36, 0x25 }, //數(shù)字鍵4、數(shù)字鍵5、數(shù)字鍵6、向左鍵{ 0x37, 0x38, 0x39, 0x28 }, //數(shù)字鍵7、數(shù)字鍵8、數(shù)字鍵9、向下鍵{ 0x30, 0x1B, 0x0D, 0x27 }  //數(shù)字鍵0、ESC鍵、  回車鍵、 向右鍵
};unsigned char KeySta[4][4] = {  //全部矩陣按鍵的當前狀態(tài){1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1},  {1, 1, 1, 1}};
pdata unsigned long  KeyDownTime[4][4]= {{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0},{0, 0, 0, 0}};bit enBuzz = 0;           //蜂鳴器使能標記bit flag1s = 0;           //1s定時標志bit flagStart = 0;        //倒計時啟動標志bit EntelLongPress = 0;   //Entel長按標志bit LongPress = 0;        //長按標志bit Locksta = 0;          //按鍵轉換狀態(tài)防出錯標志bit PasswordLock = 0;     //使能定時器鍵盤標志bit KeyLock = 1;          //使能密碼鍵盤標志bit PressMark = 0;        //長按標記unsigned char PressStyle = 0;//按鍵方式unsigned int  backword = 0;  //鍵盤密碼值unsigned char T0RH = 0;   //T0重載值高字節(jié)unsigned char T0RL = 0;   //T0重載值低字節(jié)unsigned char CountDown = 0;  //倒計時計數(shù)器unsigned int keybuf = 0;//E2prom儲存的密碼extern void UartDriver();
extern void ConfigUART(unsigned int baud);
extern void UartRxMonitor(unsigned char ms);
extern void UartWrite(unsigned char *buf, unsigned char len);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
extern void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len);unsigned int DataConversion(unsigned char addr);extern void E2Read(unsigned char* buf,unsigned char addr,unsigned char len );extern void E2Write(unsigned char* buf,unsigned char addr, unsigned char len);void ConfigTimer0(unsigned int ms);  //定時器0初值設定函數(shù)void ShowNumber(unsigned long num); //倒計時調整時間,數(shù)碼管顯示函數(shù)void KeyDriver();void Password(unsigned int Num);void main(){unsigned int keybuf = 0;InitLcd1602();     //初始化液晶EA = 1;ENLED = 0;ADDR3 = 1;ConfigUART(9600);  //配置波特率為9600keybuf = DataConversion(0x00);ConfigTimer0(2); //定時2msShowNumber(0);  //數(shù)碼管顯示0while(1){KeyDriver();               //調用按鍵驅動函數(shù)Password(keybuf);UartDriver();  //調用串口驅動if(flagStart && flag1s)    //倒計時啟動且1秒定時到達時,處理倒計時{flag1s = 0;if(CountDown > 0)      //倒計時未到0時,計時器遞減{CountDown--;        //ShowNumber(CountDown); //刷新倒計時數(shù)字顯示if(CountDown == 0){enBuzz = 1;       //啟動蜂鳴器LedBuff[6] = 0x00; //點亮獨立LED;} }}}}/* 內存比較函數(shù),比較兩個指針所指向的內存數(shù)據(jù)是否相同,ptr1-待比較指針1,ptr2-待比較指針2,len-待比較長度返回值-兩段內存數(shù)據(jù)完全相同時返回1,不同返回0 */
bit CmpMemory(unsigned char *ptr1, unsigned char *ptr2, unsigned char len)
{while (len--){if (*ptr1++ != *ptr2++)  //遇到不相等數(shù)據(jù)時即刻返回0{return 0;}}return 1;  //比較完全部長度數(shù)據(jù)都相等則返回1
}/* 串口動作函數(shù),根據(jù)接收到的命令幀執(zhí)行響應的動作buf-接收到的命令幀指針,len-命令幀長度 */
void UartAction(unsigned char *buf, unsigned char len)
{unsigned char i;unsigned char j;unsigned char pdata keybuf[4];unsigned int  pdata PasswordBuf = 0;unsigned char code cmd0[] = "buzz on";   //開蜂鳴器命令unsigned char code cmd1[] = "buzz off";  //關蜂鳴器命令unsigned char code cmd2[] = "reset password ";  //字符串顯示命令unsigned char code cmdLen[] = {          //命令長度匯總表sizeof(cmd0)-1, sizeof(cmd1)-1, sizeof(cmd2)-1,//去掉字符串結束符};unsigned char code *cmdPtr[] = {         //命令指針匯總表&cmd0[0],  &cmd1[0],  &cmd2[0],};for (i=0; i<sizeof(cmdLen); i++)  //遍歷命令列表,查找相同命令{if (len >= cmdLen[i])  //首先接收到的數(shù)據(jù)長度要不小于命令長度{if (CmpMemory(buf, cmdPtr[i], cmdLen[i]))  //比較相同時退出循環(huán){break;}}}switch (i)  //循環(huán)退出時i的值即是當前命令的索引值{case 0:enBuzz = 1; //開啟蜂鳴器break;case 1:enBuzz = 0; //關閉蜂鳴器break;case 2:buf[len] = '\0';  //為接收到的字符串添加結束符LcdShowStr(0, 0, buf+cmdLen[2]);  //顯示命令后的字符串i = len - cmdLen[2];              //計算有效字符個數(shù)if (i < 16)  //有效字符少于16時,清除液晶上的后續(xù)字符位{LcdAreaClear(i, 0, 16-i);}for(j = 0; j<4;j++)  //約定是設置4位密碼,因此輸入密碼的時候要注意長度,輸入5位密碼也只使能前4位{keybuf[j] = *(buf+cmdLen[2]+j);//把串口寫入的密碼存入數(shù)組}E2Write(keybuf,0x00,sizeof(keybuf));//往0x00地址寫入密碼break;default:   //未找到相符命令時,給上機發(fā)送“錯誤命令”的提示UartWrite("bad command.\r\n", sizeof("bad command.\r\n")-1);return;}buf[len++] = '\r';  //有效命令被執(zhí)行后,在原命令幀之后添加buf[len++] = '\n';  //回車換行符后返回給上位機,表示已執(zhí)行UartWrite(buf, len);
}/* 取出E2PROM 0x00 0x01地址的值轉換為16進制的數(shù)作為密碼 addr為起始地址該密碼是4位數(shù)  */unsigned int DataConversion(unsigned char addr){ //	unsigned char tmp;unsigned int key;unsigned char buf[4];//定義一個數(shù)組存儲密碼pdata	unsigned int str[4];  //注意這個數(shù)組一定要用intE2Read(buf,addr,sizeof(buf));//由該函數(shù)buf[4]數(shù)組已經(jīng)取得E2PROM 0x00 0x01 0x02 0x03地址的值分別//存儲在buf[4] 數(shù)組中str[0] = (buf[0] - '0')*1000;str[1] = (buf[1] - '0')*100;str[2] = (buf[2] - '0')*10;str[3] = (buf[3] - '0')*1;key = str[0] + str[1] + str[2] +str[3] ;return key;}/*配置并啟動T0,ms-T0定時時間  */void ConfigTimer0(unsigned int ms){	unsigned long tmp;              //臨時變量tmp = 11059200 / 12;              //每秒機器周期數(shù)tmp = (tmp * ms)/1000;            //計算傳遞實參的機器周期數(shù)tmp = 65536 - tmp ;               //設置定時器重載初值tmp = tmp +28;                    //初值補償T0RH = (unsigned char)(tmp >> 8); //初值高低字節(jié)分離T0RL = (unsigned char)tmp;TMOD &= 0xF0;                     //清零定時器0控制位TMOD |= 0x01;                     //選擇定時器0的工作模式TH0 = T0RH;                       //定時器0高低字節(jié)賦值TL0 = T0RL; ET0 = 1;                          //定時器0中斷使能TR0 = 1;                          //使能定時器0}/*將一個無符號長整型的數(shù)字顯示到數(shù)碼管傷,num位待顯示數(shù)字  */void ShowNumber(unsigned long num){signed char i;unsigned char buf[6]; //把長整形數(shù),每個進制位上的數(shù)轉化成十進制的數(shù)共6個存入數(shù)組for(i = 0; i <6; i++){buf[i] = num %10;num = num / 10;}for(i = 5;i >=1;i--) //從高位起,遇到0轉換為0xff(不顯示),遇到非零則退出循環(huán){if(buf[i] == 0 )LedBuff[i] = 0xFF; // 作用:高位是零則不顯示elsebreak;}for(; i >= 0; i--) //剩余低位都如實轉換成數(shù)碼管要顯示的數(shù){LedBuff[i] = LedChar[buf[i]];}}/* 按鍵動作函數(shù),根據(jù)密碼鎖鍵碼執(zhí)行相應的操作,passcode 為按鍵鍵碼 */void PasswordAction(unsigned char passcode){  static unsigned char cnt = 0;static unsigned int buf[4] = {0,0,0,0};static unsigned i = 0xFF;if(KeyLock == 1) //為1可以輸入密碼,為0密碼輸入屏蔽{ShowNumber(passcode - 0x30);if(passcode >= 0x30 && passcode <= 0x39 | passcode == 0x1B){ //確定輸入的是數(shù)字鍵cnt++;switch(cnt){case 1: buf[0] = (passcode - 0x30)*1000 ; i = i << 1 | PressMark;  break;case 2: buf[1] = (passcode - 0x30)*100 ;  i = i << 1 | PressMark;  break;case 3: buf[2] = (passcode - 0x30)*10 ;   i = i << 1 | PressMark;  break;case 4: buf[3] = (passcode - 0x30)*1 ;    i = i << 1 | PressMark;  break;default: break;}}cnt &= 0x03;if(cnt == 0){PressStyle = i & 0x0F;backword = (buf[0]+buf[1]+buf[2]+buf[3]);buf[0] = 0;buf[1] = 0;buf[2] = 0;buf[3] = 0;i = 0xFF;}if(passcode == 0x1B) //初始化鍵{buf[0] = 0;buf[1] = 0;buf[2] = 0;buf[3] = 0;cnt = 0;i = 0xFF;}}}/* 密碼設置函數(shù) */void Password(unsigned int Num){if(Num == backword && PressStyle == 0x00)//按鍵方式目前都是短鍵PasswordLock = 1;}/* 按鍵動作函數(shù),根據(jù)鍵碼執(zhí)行相應的操作,keycode 為按鍵鍵碼 */void KeyAction(unsigned char keycode){if(PasswordLock == 1) //為1使能定時操作,為0屏蔽按鍵操作{KeyLock = 0;if(keycode == 0x26)       //向上鍵,倒計時設定值每按一下加1{  if(CountDown < 9999)   //最大計數(shù)9999{// LongPress = 0;CountDown++;ShowNumber(CountDown);}}else if (keycode == 0x28) //向下鍵 倒計時設定值遞減{ if(CountDown >1)         //最小計時1s{// LongPress = 0;CountDown--;ShowNumber(CountDown);}}else if(keycode == 0x0D)  //回車鍵 ,啟動倒計時{if(EntelLongPress |  Locksta == 1){flagStart = 0;EntelLongPress = 0;LongPress = 0;}else{flagStart = 1;LongPress = 0;}}else if(keycode == 0x1B)  //ESC 鍵 取消倒計時{LongPress = 0;enBuzz = 0;LedBuff[6] = 0xFF;flagStart = 0;CountDown = 0;ShowNumber(0);}}}/*按鍵驅動函數(shù),檢測按鍵動作,調度相應動作函數(shù),需要在主函數(shù)中調用    */	void KeyDriver(){unsigned char i,j,cnt;				static unsigned char pdata backup[4][4] = {       //按鍵值備份,保存前一次的值{1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}};static unsigned long pdata TimeThr[4][4] = {  //快速輸入執(zhí)行的時間閾值{500,500,500,500},{500,500,500,500},{500,500,500,500},{500,500,500,500}};for(i = 0; i<4; i++)                  //循環(huán)掃描4*4的矩陣按鍵{for(j = 0; j<4; j++){if(backup[i][j] != KeySta[i][j]) //按鍵動作檢查{	if(PasswordLock){if(backup[i][j] == 0 && LongPress == 0  ) //前態(tài)如果是0那么現(xiàn)態(tài)是1,開關從按住彈起{if( Locksta == 0)KeyAction(KeyCodeMap[i][j]);   //調用按鍵動作函數(shù)Locksta = 0;}if(backup[i][j] == 0 && LongPress == 1  ) //前態(tài)如果是0那么現(xiàn)態(tài)是1,開關從按住彈起{LongPress = 0;}}if(KeyLock == 1)//鎖住密碼鎖{if(backup[i][j] == 0 && PressMark == 0) //前態(tài)如果是0那么現(xiàn)態(tài)是1,開關從按住彈起{		       PasswordAction(KeyCodeMap[i][j]); //調用密碼鎖按鍵動作}if(backup[i][j] == 0 && PressMark == 1){PressMark = 0;   }} backup[i][j] = KeySta[i][j];    //刷新前一次備份值cnt = 0;}if(KeyDownTime[i][j] > 0)    //檢測執(zhí)行快速輸入{if(KeyDownTime[i][j] >= TimeThr[i][j]){   if(KeyLock ==1) //密碼鎖鍵盤使能{																	 if( PressMark == 0) {   							 	 PressMark = 1;PasswordAction(KeyCodeMap[i][j]); //調用密碼鎖按鍵動作 										  }TimeThr[i][j] += 100;             //時間閾值增加200ms,以準備下一次執(zhí)行}if(PasswordLock == 1) {										 									 LongPress = 1;                   //達到閾值時執(zhí)行一次動作KeyAction(KeyCodeMap[i][j]);      //調用按鍵動作函數(shù)									     TimeThr[i][j] += 100;             //時間閾值增加200ms,以準備下一次執(zhí)行cnt++;if(cnt >= 11) {cnt = 0;if(i == 3 && j == 2)   //注意entel鍵是3行2列,不是4行3列因為第1行一1列是0,0{EntelLongPress = 1;Locksta = 1;  //按鍵鎖標志防止彈起進入短按函數(shù)}}		}  }} else                     // 按鍵彈起時復位閾值時間{TimeThr[i][j] = 500;  // 恢復1s的初始閾值時間//矩陣函數(shù)cnt = 0復位語句語句不能放在該處// 每4次中斷才能掃描到一次對應按住的按鍵}                       //其他時間一直進入的都是else函數(shù),把它的比較閾值賦值為500,因此cnt=0 不能放在這個位置。}}}/*按鍵掃描函數(shù) ,需要在定時中斷中調用  */void KeyScan(){unsigned char i;static unsigned char keyout = 0;static unsigned char keybuf[4][4] = {{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},{0xFF,0xFF,0xFF,0xFF},};//將一行的4個按鍵值移入緩沖區(qū)keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;//消抖后更新按鍵狀態(tài)for(i = 0; i < 4; i++){if((keybuf[keyout][i] & 0x0F) == 0x00){//連續(xù)4次燒苗值為0,即4x4ms內都是按下狀態(tài)時,可以認為按鍵已穩(wěn)定的按下KeySta[keyout][i] = 0;KeyDownTime[keyout][i] += 4;//按下的持續(xù)時間累加}else if((keybuf[keyout][i] & 0x0F) == 0x0F){ //連續(xù)4次掃描值為1,即4x4ms內都是彈起狀態(tài)時,可認為按鍵已穩(wěn)定的彈起KeySta[keyout][i] = 1;KeyDownTime[keyout][i] = 0;//按下的持續(xù)時間清零}}keyout++;           //輸出索引遞增keyout &= 0x03;     //索引值逢4歸0switch(keyout)     //根據(jù)索引,釋放當前輸出引腳,拉低下次的輸出引腳{case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;default: break;}}/* LED動態(tài)掃描函數(shù),需要在定時中斷中調用  */void LedScan(){static unsigned char i = 0; //動態(tài)掃描索引P0 = 0xFF;              //消除鬼影P1 = (P1 & 0xF8) | i;  // 0xF8 = 1111 1000,位選索引值賦值到P1口低3位P0 = LedBuff[i];      //緩沖區(qū)中索引位置的數(shù)據(jù)送到P0口if(i < 6)             //索引遞增循環(huán),遍歷整個緩沖區(qū)i++;elsei = 0;}/* T0中斷服務函數(shù),完成數(shù)碼管、按鍵掃描與定時 */void interruptTimer0() interrupt 1{static unsigned int tmr1s = 0; //1秒定時器TH0 = T0RH;TL0 = T0RL;UartRxMonitor(2);  //串口接收監(jiān)控if(enBuzz)BUZZ = ~BUZZ;    //蜂鳴器發(fā)聲處理else               //驅動蜂鳴器發(fā)聲BUZZ = 1;LedScan();         //關閉蜂鳴器KeyScan();         //LED 掃描顯示if(flagStart)      //按鍵掃描{                  //倒計時啟動時處理1秒定時tmr1s++;if(tmr1s >= 500){tmr1s = 0;flag1s = 1;}}else{tmr1s = 0;    //倒計時未啟動時1秒定時器始終歸零}}

Uart.c


#include <reg52.h>bit flagFrame = 0;  //幀接收完成標志,即接收到一幀新數(shù)據(jù)
bit flagTxd = 0;    //單字節(jié)發(fā)送完成標志,用來替代TXD中斷標志位
unsigned char cntRxd = 0;   //接收字節(jié)計數(shù)器
unsigned char pdata bufRxd[64];  //接收字節(jié)緩沖區(qū)extern void UartAction(unsigned char *buf, unsigned char len);/* 串口配置函數(shù),baud-通信波特率 */
void ConfigUART(unsigned int baud)
{SCON  = 0x50;  //配置串口為模式1TMOD &= 0x0F;  //清零T1的控制位TMOD |= 0x20;  //配置T1為模式2TH1 = 256 - (11059200/12/32)/baud;  //計算T1重載值TL1 = TH1;     //初值等于重載值ET1 = 0;       //禁止T1中斷ES  = 1;       //使能串口中斷TR1 = 1;       //啟動T1
}
/* 串口數(shù)據(jù)寫入,即串口發(fā)送函數(shù),buf-待發(fā)送數(shù)據(jù)的指針,len-指定的發(fā)送長度 */
void UartWrite(unsigned char *buf, unsigned char len)
{while (len--)  //循環(huán)發(fā)送所有字節(jié){flagTxd = 0;      //清零發(fā)送標志SBUF = *buf++;    //發(fā)送一個字節(jié)數(shù)據(jù)while (!flagTxd); //等待該字節(jié)發(fā)送完成}
}
/* 串口數(shù)據(jù)讀取函數(shù),buf-接收指針,len-指定的讀取長度,返回值-實際讀到的長度 */
unsigned char UartRead(unsigned char *buf, unsigned char len)
{unsigned char i;if (len > cntRxd)  //指定讀取長度大于實際接收到的數(shù)據(jù)長度時,{                  //讀取長度設置為實際接收到的數(shù)據(jù)長度len = cntRxd;}for (i=0; i<len; i++)  //拷貝接收到的數(shù)據(jù)到接收指針上{*buf++ = bufRxd[i];}cntRxd = 0;  //接收計數(shù)器清零return len;  //返回實際讀取長度
}
/* 串口接收監(jiān)控,由空閑時間判定幀結束,需在定時中斷中調用,ms-定時間隔 */
void UartRxMonitor(unsigned char ms)
{static unsigned char cntbkp = 0;static unsigned char idletmr = 0;if (cntRxd > 0)  //接收計數(shù)器大于零時,監(jiān)控總線空閑時間{if (cntbkp != cntRxd)  //接收計數(shù)器改變,即剛接收到數(shù)據(jù)時,清零空閑計時{cntbkp = cntRxd;idletmr = 0;}else                   //接收計數(shù)器未改變,即總線空閑時,累積空閑時間{if (idletmr < 15)  //空閑計時小于30ms時,持續(xù)累加{idletmr += ms;if (idletmr >= 15)  //空閑時間達到30ms時,即判定為一幀接收完畢,該程序是2ms進入一次T0中斷{flagFrame = 1;  //設置幀接收完成標志}}}}else{cntbkp = 0;}
}
/* 串口驅動函數(shù),監(jiān)測數(shù)據(jù)幀的接收,調度功能函數(shù),需在主循環(huán)中調用 */
void UartDriver()
{unsigned char len;unsigned char pdata buf[40];if (flagFrame) //有命令到達時,讀取處理該命令{flagFrame = 0;len = UartRead(buf, sizeof(buf));  //將接收到的命令讀取到緩沖區(qū)中UartAction(buf, len);  //傳遞數(shù)據(jù)幀,調用動作執(zhí)行函數(shù)}
}
/* 串口中斷服務函數(shù) */
void InterruptUART() interrupt 4
{if (RI)  //接收到新字節(jié){RI = 0;  //清零接收中斷標志位if (cntRxd < sizeof(bufRxd)) //接收緩沖區(qū)尚未用完時,{                            //保存接收字節(jié),并遞增計數(shù)器bufRxd[cntRxd++] = SBUF;}}if (TI)  //字節(jié)發(fā)送完畢{TI = 0;   //清零發(fā)送中斷標志位flagTxd = 1;  //設置字節(jié)發(fā)送完成標志}
}

I2C.c

# include<reg52.h>
# include<intrins.h># define I2CDelay() {_nop_();_nop_();_nop_();_nop_();}
//  # define I2CDelay() {_nop_();}
sbit I2C_SCL = P3^7;
sbit I2C_SDA = P3^6; /* 產(chǎn)生總線起始信號   */
void I2CStart()
{I2C_SDA = 1;    //首先確保SDA,SCL都是高電平I2C_SCL = 1;I2CDelay();I2C_SDA = 0;   //先拉低SDAI2CDelay();I2C_SCL = 0;   //再拉低SCL}/* 產(chǎn)生總線停止信號  */
void I2CStop()
{I2C_SCL = 0;  //首先確保SDA,SCL都是低電平I2C_SDA = 0;I2CDelay();I2C_SCL = 1;  //先拉高SCL的電平I2CDelay();I2C_SDA = 1;  //再拉高SDA的電平I2CDelay();}/*I2C總線寫操作,dat為待寫入字節(jié),返回值為從機的應答位的值  */
bit I2CWrite(unsigned char dat)
{bit ack;            //用于暫存應帶位的值unsigned char mask; //用于探測字節(jié)內一位值的掩碼變量for(mask = 0x80; mask != 0; mask >>= 1)//從高位依次進行{if((mask&dat) == 0)I2C_SDA = 0;elseI2C_SDA = 1;      //通過上述語句把dat的8位電平信息從最高位開始依次發(fā)出I2CDelay();I2C_SCL = 1;I2CDelay();I2C_SCL = 0;  //再拉低SCL,完成一個位周期}I2C_SDA = 1; //8位數(shù)據(jù)發(fā)送完后,主機釋放SDA,以檢測從機應答I2CDelay();I2C_SCL = 1; //拉高SCLack = I2C_SDA;//讀取此時的SDA的值,即為從機的應答值I2CDelay();I2C_SCL = 0; //再拉低SCL完成應答位,并保持住總線return(~ack); //應答值取反符合通常的邏輯;0 = 不純在//或忙或寫入失敗,1 = 純在且空閑或者寫入成功}
/* I2C總線讀操作,并發(fā)送非應答信號,返回值為讀到的字節(jié) */
unsigned char I2CReadNAK()
{unsigned char mask;unsigned char dat;I2C_SDA = 1;   //首先確保主機釋放SDAfor(mask = 0x80; mask != 0; mask >>= 1) //從高位到低位依次進行{I2CDelay();I2C_SCL = 1;     //拉高SCLif(I2C_SDA == 0) //讀取SDA的值dat &= ~mask; //為0時,dat中對應位清零elsedat |= mask; //為1時,dat中對應位置1I2CDelay();I2C_SCL = 0;	//再拉低SCL,以使從機發(fā)送下一位}I2C_SDA = 1;  //8位數(shù)據(jù)發(fā)送完后,拉高SDA,發(fā)送非應答信號I2CDelay();I2C_SCL = 1;  //拉高SCLI2CDelay();I2C_SCL = 0; //再拉低SCL完成非應答位,并保持住總線return dat;}/* I2C總線操作,并發(fā)送應答信號,返回值為讀到的字節(jié) */
unsigned char I2CReadACK()
{unsigned char mask;unsigned char dat;I2C_SDA = 1;for(mask = 0x80; mask != 0; mask >>= 1){I2CDelay();I2C_SCL = 1;if(I2C_SDA == 0)dat &= ~mask;elsedat |= mask;I2CDelay();I2C_SCL = 0;//再拉低SCL,以使從機發(fā)送出下一位}I2C_SDA = 0; //8位數(shù)據(jù)發(fā)送完后,拉低SDA。發(fā)送應答信號I2CDelay();I2C_SCL = 1; //拉高SCLI2CDelay();I2C_SCL = 0; //再拉低SCL完成應答,并保持住總線return dat;}

E2PROM.c

# include<reg52.h>extern void I2CStart();
extern void I2CStop();
extern unsigned char I2CReadACK();
extern unsigned char I2CReadNAK();
extern bit I2CWrite(unsigned char dat);/*E2讀取函數(shù),buf為數(shù)據(jù)接收指針,addr為E2中的起始地址,len為讀取長度 ,這是一個讀取相應地址并寫入buf數(shù)組   的程序 */void E2Read(unsigned char* buf,unsigned char addr,unsigned char len )
{do{I2CStart();          //用尋址操作查詢當前是否可以進行讀寫操作if(I2CWrite(0x50<<1)) //應答則跳出循環(huán),非應答則進行下一次查詢{break;}I2CStop();}while(1);I2CWrite(addr);           //寫入起始地址I2CStart();               //發(fā)送重復啟動信號I2CWrite((0x50<<1) | 0x01);//尋址器件后續(xù)為讀操作while(len > 1)             //連續(xù)讀取len-1個字節(jié){*buf++ = I2CReadACK(); //最后字節(jié)前為讀取操作+應答len--;}*buf = I2CReadNAK();   //最后一個字節(jié)為讀操作+非應答I2CStop();
}/* E2寫入函數(shù),buf為數(shù)據(jù)指針,addr為E2中的起始地址,len為寫入長度   */
void E2Write(unsigned char* buf,unsigned char addr, unsigned char len)
{while(len > 0){                               //等待上次寫入操作完成do{                         //用尋址操作查詢當前是否可以進行讀寫操作I2CStart();                if(I2CWrite(0x50 << 1)) //應答則跳出循環(huán),非應答則進行下一次查詢{break;}I2CStop();}while(1);
//按頁寫入模式連續(xù)寫入字節(jié)		I2CWrite(addr);      //寫入起始地址while(len > 0){I2CWrite(*buf++); //寫入一個字節(jié)數(shù)據(jù)len--;            //待寫入長度計數(shù)遞減addr++;           //E2地址遞增if((addr&0x07) == 0)//檢查地址是否到達頁邊界,24C02每頁8字節(jié){                    //所以檢測低3位是否為0即可break;             //到達頁邊界時,跳出循環(huán),結束本次寫操作}}I2CStop();}}

Lcd1602.c

#include <reg52.h>#define LCD1602_DB  P0
sbit LCD1602_RS = P1^0;
sbit LCD1602_RW = P1^1;
sbit LCD1602_E  = P1^5;/* 等待液晶準備好 */
void LcdWaitReady()
{unsigned char sta;LCD1602_DB = 0xFF;LCD1602_RS = 0;LCD1602_RW = 1;do {LCD1602_E = 1;sta = LCD1602_DB; //讀取狀態(tài)字LCD1602_E = 0;} while (sta & 0x80); //bit7等于1表示液晶正忙,重復檢測直到其等于0為止
}
/* 向LCD1602液晶寫入一字節(jié)命令,cmd-待寫入命令值 */
void LcdWriteCmd(unsigned char cmd)
{LcdWaitReady();LCD1602_RS = 0;LCD1602_RW = 0;LCD1602_DB = cmd;LCD1602_E  = 1;LCD1602_E  = 0;
}
/* 向LCD1602液晶寫入一字節(jié)數(shù)據(jù),dat-待寫入數(shù)據(jù)值 */
void LcdWriteDat(unsigned char dat)
{LcdWaitReady();LCD1602_RS = 1;LCD1602_RW = 0;LCD1602_DB = dat;LCD1602_E  = 1;LCD1602_E  = 0;
}
/* 設置顯示RAM起始地址,亦即光標位置,(x,y)-對應屏幕上的字符坐標 */
void LcdSetCursor(unsigned char x, unsigned char y)
{unsigned char addr;if (y == 0)  //由輸入的屏幕坐標計算顯示RAM的地址addr = 0x00 + x;  //第一行字符地址從0x00起始elseaddr = 0x40 + x;  //第二行字符地址從0x40起始LcdWriteCmd(addr | 0x80);  //設置RAM地址
}
/* 在液晶上顯示字符串,(x,y)-對應屏幕上的起始坐標,str-字符串指針 */
void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str)
{LcdSetCursor(x, y);   //設置起始地址while (*str != '\0')  //連續(xù)寫入字符串數(shù)據(jù),直到檢測到結束符{LcdWriteDat(*str++);}
}
/* 區(qū)域清除,清除從(x,y)坐標起始的len個字符位 */
void LcdAreaClear(unsigned char x, unsigned char y, unsigned char len)
{LcdSetCursor(x, y);   //設置起始地址while (len--)         //連續(xù)寫入空格{LcdWriteDat(' ');}
}
/* 初始化1602液晶 */
void InitLcd1602()
{//  LcdWriteCmd(0x38);  //16*2顯示,5*7點陣,8位數(shù)據(jù)接口//  LcdWriteCmd(0x0C);  //顯示器開,光標關閉//  LcdWriteCmd(0x06);  //文字不動,地址自動+1//  LcdWriteCmd(0x01);  //清屏LcdWriteCmd(0x38);//0x38 = 0011 1000 16*2顯示,5*7點陣,8位數(shù)據(jù)接口LcdWriteCmd(0x08);//顯示關閉LcdWriteCmd(0x01);//清屏LcdWriteCmd(0x06);//0x04 = 0000 0100 文字不動,地址自動加1LcdWriteCmd(0x0C);//顯示器開 ,光標關閉
}

貼個相關操作視頻

UART和I2C通信綜合應用_嗶哩嗶哩_bilibili

UART串口工作

簡易的流程圖: https://docs.qq.com/s/sUMg3jiBzjcUANe_68SHnq

只是UART工作的流程圖不是全程序的,筆者自己編的,湊活看吧。

http://aloenet.com.cn/news/33476.html

相關文章:

  • 鶴壁網(wǎng)站推廣公司seo資訊網(wǎng)
  • 品牌網(wǎng)站建設 杭州外貿(mào)seo優(yōu)化
  • 上海石化有做網(wǎng)站設計的嗎專業(yè)代寫軟文
  • 適合女生做的網(wǎng)站清遠seo
  • 優(yōu)化教程網(wǎng)站推廣排名搜索引擎優(yōu)化實訓報告
  • 韓國購物網(wǎng)站網(wǎng)站流量統(tǒng)計分析報告
  • 租賃服務器的網(wǎng)站網(wǎng)上培訓課程平臺
  • 快速網(wǎng)站建設價格百度指數(shù)官網(wǎng)查詢
  • 網(wǎng)站建設哪家好萬維科技推廣軟件賺錢違法嗎
  • mi2設計公司網(wǎng)站2345網(wǎng)止導航
  • 網(wǎng)站后臺被百度蜘蛛抓取百度沒有排名的點擊軟件
  • wap手機網(wǎng)站制作域名注冊查詢網(wǎng)站
  • 網(wǎng)站開發(fā)有哪些模塊網(wǎng)站怎樣被百度收錄
  • wordpress 架站 電子書百度網(wǎng)盤下載速度
  • 四川華泰建設集團網(wǎng)站網(wǎng)絡營銷渠道策略有哪些
  • 網(wǎng)站更換服務器影響網(wǎng)站優(yōu)化的主要內容
  • 有個網(wǎng)站可以學做ppt模板十大營銷案例分析
  • 任何網(wǎng)站都可以做谷歌推廣的嗎專業(yè)的網(wǎng)頁制作公司
  • 新塘做網(wǎng)站東莞有哪些做推廣的網(wǎng)站
  • 榆林國貿(mào)網(wǎng)站建設怎么做關鍵詞排名靠前
  • 新疆錦旭建設工程公司網(wǎng)站seo信息優(yōu)化
  • 比較出名的文創(chuàng)產(chǎn)品南寧百度seo
  • 深圳 微網(wǎng)站建設ydgcm獎券世界推廣網(wǎng)站
  • 如何判斷網(wǎng)站html5上海高端seo公司
  • 網(wǎng)站開源模板百度指數(shù)排名明星
  • app平臺網(wǎng)站搭建潮州seo建站
  • 雙語網(wǎng)站建設報價百度鏈接提交收錄入口
  • dw網(wǎng)頁設計期末作業(yè)seo的主要分析工具
  • 公司網(wǎng)站設計方案網(wǎng)站查詢是否安全
  • 天津做網(wǎng)站哪個公司好seo排名優(yōu)化工具推薦