在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ 數(shù)據(jù)庫(kù)/ 14.7 單片機(jī) I2C 和 EEPROM 的綜合編程
18. RS485 通信與 Modbus 協(xié)議
17.5 A/D 差分輸入信號(hào)
15.8 C 語(yǔ)言復(fù)合數(shù)據(jù)類型(結(jié)構(gòu)體,共用體,枚舉類型)
16.3 NEC 協(xié)議紅外遙控器
13.1 單片機(jī)通信時(shí)序解析
14.4 單片機(jī) EEPROM 單字節(jié)讀寫操作時(shí)序
13.3 多個(gè) .c 文件的初步認(rèn)識(shí)
18.2 Modbus 通信協(xié)議介紹
15.1 BCD 碼介紹
18.3 單片機(jī) Modbus 多機(jī)通信程序設(shè)計(jì)
18.1 單片機(jī) RS485 通信接口、控制線、原理圖及程序?qū)嵗?/span>
15. 實(shí)時(shí)時(shí)鐘 DS1302
14.7 單片機(jī) I2C 和 EEPROM 的綜合編程
17. 模數(shù)轉(zhuǎn)換與數(shù)模轉(zhuǎn)換
16.2 紅外遙控通信原理
13.2 1602 液晶整屏移動(dòng)程序
17.6 D/A 輸出
17.7 單片機(jī)信號(hào)發(fā)生器程序
16.4 溫度傳感器 DS18B20
14.6 單片機(jī)EEPROM的頁(yè)寫入
13.4 單片機(jī)計(jì)算器程序設(shè)計(jì)[詳細(xì)]
17.2 A/D(模數(shù)轉(zhuǎn)換)的主要指標(biāo)
17.4 PCF8591 應(yīng)用程序
17.1 A/D 和 D/A 的基本概念
17.3 PCF8591硬件接口(電路圖引腳圖)
14.3 單片機(jī) EEPROM 簡(jiǎn)介
13.5 單片機(jī)串口通信原理和控制程序
15.5 DS1302 寄存器介紹
15.2 單片機(jī) SPI 通信接口
15.6 DS1302 通信時(shí)序介紹
14.5 單片機(jī) EEPROM 多字節(jié)讀寫操作時(shí)序
16. 紅外通信與 DS18B20 溫度傳感器
14.1 單片機(jī) I2C 時(shí)序介紹
15.3 實(shí)時(shí)時(shí)鐘芯片 DS1302 介紹
15.9 單片機(jī)電子時(shí)鐘程序設(shè)計(jì)
16.1 紅外光的基本原理
15.4 DS1302 的硬件信息
15.7 DS1302 的 BURST 模式
14.2 單片機(jī) I2C 尋址模式
14. 單片機(jī) I2C 總線與 EEPROM
13. 單片機(jī) 1602 液晶與串口的應(yīng)用實(shí)例

14.7 單片機(jī) I2C 和 EEPROM 的綜合編程

電視頻道記憶功能,交通燈倒計(jì)時(shí)時(shí)間的設(shè)定,戶外 LED 廣告的記憶功能,都有可能用到 EEPROM 這類存儲(chǔ)器件。這類器件的優(yōu)勢(shì)是存儲(chǔ)的數(shù)據(jù)不僅可以改變,而且掉電后數(shù)據(jù)保存不丟失,因此大量應(yīng)用在各種電子產(chǎn)品上。

我們這節(jié)課的例程,有點(diǎn)類似廣告屏。上電后,1602 的第一行顯示 EEPROM 從 0x20 地址開始的16個(gè)字符,第二行顯示 EERPOM 從 0x40 開始的16個(gè)字符。我們可以通過 UART 串口通信來改變 EEPROM 內(nèi)部的這個(gè)數(shù)據(jù),并且同時(shí)也改變了 1602 顯示的內(nèi)容,下次上電的時(shí)候,直接會(huì)顯示我們更新過的內(nèi)容。

這個(gè)程序所有的相關(guān)內(nèi)容,前面都已經(jīng)講過了。但是這個(gè)程序體現(xiàn)在了一個(gè)綜合應(yīng)用能力上。這個(gè)程序用到了 1602 液晶、UART 串口通信、EEPROM 讀寫操作等多個(gè)功能的綜合應(yīng)用。寫個(gè)點(diǎn)亮小燈好簡(jiǎn)單,但是我們想真正學(xué)好單片機(jī),必須得學(xué)會(huì)這種綜合程序的應(yīng)用,實(shí)現(xiàn)多個(gè)模塊同時(shí)參與工作。因此同學(xué)們,要認(rèn)認(rèn)真真的把工程建立起來,一行一行的把程序編寫起來,最終鞏固下來。

/*I2C.c 文件程序源代碼***/ (此處省略,可參考之前章節(jié)的代碼) /*Lcd1602.c 文件程序源代碼***/ (此處省略,可參考之前章節(jié)的代碼) /****eeprom.c 文件程序源代碼/ (此處省略,可參考之前章節(jié)的代碼) /Uart.c 文件程序源代碼*****/ (此處省略,可參考之前章節(jié)的代碼)

/*****************************main.c 文件程序源代碼******************************/
#include <reg52.h>
unsigned char T0RH = 0; //T0 重載值的高字節(jié)
unsigned char T0RL = 0; //T0 重載值的低字節(jié)

void InitShowStr();
void ConfigTimer0(unsigned int ms);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
extern void E2Read(unsigned char *buf, unsigned char addr, unsigned char len);
extern void E2Write(unsigned char *buf, unsigned char addr, unsigned char len);
extern void UartDriver();
extern void ConfigUART(unsigned int baud);
extern void UartRxMonitor(unsigned char ms);
extern void UartWrite(unsigned char *buf, unsigned char len);

void main(){
    EA = 1; //開總中斷
    ConfigTimer0(1); //配置 T0 定時(shí) 1ms
    ConfigUART(9600); //配置波特率為 9600
    InitLcd1602(); //初始化液晶
    InitShowStr(); //初始顯示內(nèi)容

    while (1){
        UartDriver(); //調(diào)用串口驅(qū)動(dòng)
    }
}
/* 處理液晶屏初始顯示內(nèi)容 */
void InitShowStr(){
    unsigned char str[17];

    str[16] = '\0';//在最后添加字符串結(jié)束符,確保字符串可以結(jié)束
    E2Read(str, 0x20, 16); //讀取第一行字符串,其 E2 起始地址為 0x20
    LcdShowStr(0, 0, str); //顯示到液晶屏
    E2Read(str, 0x40, 16); //讀取第二行字符串,其 E2 起始地址為 0x40
    LcdShowStr(0, 1, str); //顯示到液晶屏
}
/* 內(nèi)存比較函數(shù),比較兩個(gè)指針?biāo)赶虻膬?nèi)存數(shù)據(jù)是否相同,
ptr1-待比較指針 1,ptr2-待比較指針 2,len-待比較長(zhǎng)度
返回值-兩段內(nèi)存數(shù)據(jù)完全相同時(shí)返回 1,不同返回 0 */
bit CmpMemory(unsigned char *ptr1, unsigned char *ptr2, unsigned char len){
    while (len--){
        if (*ptr1++ != *ptr2++){ //遇到不相等數(shù)據(jù)時(shí)即刻返回 0
            return 0;
        }
    }
    return 1; //比較完全部長(zhǎng)度數(shù)據(jù)都相等則返回 1
}
/* 將一字符串整理成 16 字節(jié)的固定長(zhǎng)度字符串,不足部分補(bǔ)空格
out-整理后的字符串輸出指針,in-待整理字符串指針 */
void TrimString16(unsigned char *out, unsigned char *in){
    unsigned char i = 0;
    while (*in != '\0'){ //拷貝字符串直到輸入字符串結(jié)束
        *out++ = *in++;
        i++;
        if (i >= 16){ //當(dāng)拷貝長(zhǎng)度已達(dá)到 16 字節(jié)時(shí),強(qiáng)制跳出循環(huán)
            break;
        }
    }
    for ( ; i<16; i++){ //如不足 16 個(gè)字節(jié)則用空格補(bǔ)齊
        *out++ = ' ';
    }
    *out = '\0'; //最后添加結(jié)束符
}
/* 串口動(dòng)作函數(shù),根據(jù)接收到的命令幀執(zhí)行響應(yīng)的動(dòng)作
buf-接收到的命令幀指針,len-命令幀長(zhǎng)度 */
void UartAction(unsigned char *buf, unsigned char len){
    unsigned char i;
    unsigned char str[17];
    unsigned char code cmd0[] = "showstr1 "; //第一行字符顯示命令
    unsigned char code cmd1[] = "showstr2 "; //第二行字符顯示命令

    unsigned char code cmdLen[] = { //命令長(zhǎng)度匯總表
        sizeof(cmd0)-1, sizeof(cmd1)-1,
    };
    unsigned char code *cmdPtr[] = { //命令指針匯總表
        &cmd0[0], &cmd1[0],
    };
    for (i=0; i<sizeof(cmdLen); i++){ //遍歷命令列表,查找相同命令
        if (len >= cmdLen[i]){ //首先接收到的數(shù)據(jù)長(zhǎng)度要不小于命令長(zhǎng)度
            if (CmpMemory(buf, cmdPtr[i], cmdLen[i])){ //比較相同時(shí)退出循環(huán)
                break;
            }
        }
    }
    switch (i){ //根據(jù)比較結(jié)果執(zhí)行相應(yīng)命令
        case 0:
            buf[len] = '\0'; //為接收到的字符串添加結(jié)束符
            TrimString16(str, buf+cmdLen[0]); //整理成 16 字節(jié)固定長(zhǎng)度字符串
            LcdShowStr(0, 0, str); //顯示字符串 1
            E2Write(str, 0x20, sizeof(str)); //保存字符串 1,起始地址為 0x20
            break;
        case 1:
            buf[len] = '\0'; //為接收到的字符串添加結(jié)束符
            TrimString16(str, buf+cmdLen[1]); //整理成 16 字節(jié)固定長(zhǎng)度字符串
            LcdShowStr(0, 1, str); //顯示字符串 1
            E2Write(str, 0x40, sizeof(str)); //保存字符串 2,起始地址為 0x40
            break;
        default: //未找到相符命令時(shí),給上機(jī)發(fā)送“錯(cuò)誤命令”的提示
            UartWrite("bad command.\r\n", sizeof("bad command.\r\n")-1);
            return;
    }
    buf[len++] = '\r'; //有效命令被執(zhí)行后,在原命令幀之后添加
    buf[len++] = '\n'; //回車換行符后返回給上位機(jī),表示已執(zhí)行
    UartWrite(buf, len);
}
/* 配置并啟動(dòng) T0,ms-T0 定時(shí)時(shí)間 */
void ConfigTimer0(unsigned int ms){
    unsigned long tmp; //臨時(shí)變量
    tmp = 11059200 / 12; //定時(shí)器計(jì)數(shù)頻率
    tmp = (tmp * ms) / 1000; //計(jì)算所需的計(jì)數(shù)值
    tmp = 65536 - tmp; //計(jì)算定時(shí)器重載值
    tmp = tmp + 33; //補(bǔ)償中斷響應(yīng)延時(shí)造成的誤差

    T0RH = (unsigned char)(tmp>>8); //定時(shí)器重載值拆分為高低字節(jié)
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0; //清零 T0 的控制位
    TMOD |= 0x01; //配置 T0 為模式 1
    TH0 = T0RH; //加載 T0 重載值
    TL0 = T0RL;
    ET0 = 1; //使能 T0 中斷
    TR0 = 1; //啟動(dòng) T0
}
/* T0 中斷服務(wù)函數(shù),執(zhí)行串口接收監(jiān)控和蜂鳴器驅(qū)動(dòng) */
void InterruptTimer0() interrupt 1{
    TH0 = T0RH; //重新加載重載值
    TL0 = T0RL;
    UartRxMonitor(1); //串口接收監(jiān)控
}

我們?cè)趯W(xué)習(xí) UART 通信的時(shí)候,剛開始也是用的 IO 口去模擬 UART 通信過程,最終實(shí)現(xiàn)和電腦的通信,而后因?yàn)?STC89C52 內(nèi)部具備 UART 硬件通信模塊,所以我們直接可以通過配置寄存器就可以很輕松的實(shí)現(xiàn)單片機(jī)的 UART 通信。同樣的道理,這個(gè) I2C 通信,如果單片機(jī)內(nèi)部有硬件模塊的話,單片機(jī)可以直接自動(dòng)實(shí)現(xiàn) I2C 通信了,就不需要我們?cè)龠M(jìn)行 IO口模擬起始、模擬發(fā)送、模擬結(jié)束,配置好寄存器,單片機(jī)就會(huì)把這些工作全部做了。

不過我們的 STC89C52 單片機(jī)內(nèi)部不具備 I2C 的硬件模塊,所以我們使用 STC89C52 進(jìn)行 I2C 通信的話必須用 IO 口來模擬。使用 IO 口模擬 I2C 實(shí)際上更有利于我們徹底理解透徹 I2C 通信的實(shí)質(zhì)。當(dāng)然了,通過學(xué)習(xí) IO 口模擬通信,今后如果遇到內(nèi)部帶 I2C 模塊的單片機(jī),也應(yīng)該很輕松的搞定,使用內(nèi)部的硬件模塊,可以提高程序的執(zhí)行效率。