新聞中心

        EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應用 > AT89S51I2C控制PCF8576段碼LCD模塊

        AT89S51I2C控制PCF8576段碼LCD模塊

        作者: 時間:2016-11-13 來源:網(wǎng)絡(luò) 收藏
        很長的一段時間的搗鼓,手上的這塊段碼屏、總算是可以按照我的要求顯示數(shù)字了.這塊小數(shù)碼屏在我手里已經(jīng)很久了,記得還是剛剛玩單片機時買的,當時在地攤上花了3元錢買了一只LCD1601模塊和這塊屏,當時并不知道如何才能點亮它,只是因為其背面的控制電路是標準的集成塊,型號齊全清晰,屏面成色尚可,當時地攤上也時常能見到一些小的顯示屏,但多數(shù)都是黑色樹脂封裝的電路模塊,我只選帶有型號的標準集成電路的買,因為我覺得,只要有型號,就可以在網(wǎng)上查到資料,事實證明,我是對的;隨著所學知識的增加,后來玩了一陣子LCD1601,玩明白以后就扔到一邊了,而這只模塊一直沒弄,前些時,在網(wǎng)上找到了這只模塊的集成電路資料,才知道這種PCF8576電路、竟然是自成系列的I2C總線控制電路,資料不算多,只有周立功的那兩篇文章和應用程序,而找到的C源代碼,也多為硬件I2C方式,而AT89S51模擬驅(qū)動的C程序也是常被一些網(wǎng)站封鎖不能下載,偶爾有見,也弄不懂,至于自己編程,我是無能為力的。后來找到了如下這段程序:

        MSP430F1121與液晶驅(qū)動芯片PCF8576的連接程序

        本文引用地址:http://www.104case.com/article/201611/316552.htm

        #i nclude "msp430x11x1.h"

        #define uint unsigned int
        #define uchar unsigned char

        //器件地址
        uchar PCF8576=0x70;

        //內(nèi)存數(shù)據(jù)定義
        uchar ByteCnt; //I2C 數(shù)據(jù)字節(jié)計數(shù)器
        uchar SlvAdr; //被控器地址
        uchar SubAdr; //被控器單元地址
        uchar XmtDat[5]; //發(fā)送數(shù)據(jù)緩沖區(qū)


        //uchar MODE1=0x45;
        uchar MODE2=0xCD; //
        uchar Bank_sel=0x78;

        uchar flag;

        uchar Digit[10];

        #define SDA BIT3 // P2.3 controls SDA line (pull-up used for logic
        1)
        #define SCL BIT4 // P2.4 controls SCL line (pull-up used for logic
        1)

        /******************************************************************************
        ; 子程序
        ;名稱:START
        ;描述:啟動I2C 總線子程序--發(fā)送I2C 起始條件
        ;;*****************************************************************************/
        void START(void)
        {
        P2OUT |= SDA; //SDA=1
        _NOP();
        P2OUT |= SCL; //SCL=1
        _NOP();
        P2OUT &= ~SDA; //SDA=0
        _NOP();
        P2OUT &= ~SCL; //SCL=0
        }

        /*--------------------------------------------------------------------------
        ;名稱:STOP
        ;描述:停止I2C 總線子程序--發(fā)送I2C 總線停止條件
        ;-------------------------------------------------------------------------*/
        void STOP(void)
        {
        P2OUT &= ~SDA; //SDA=0
        _NOP();
        P2OUT |= SCL;
        _NOP();
        P2OUT |= SDA;
        _NOP();
        P2OUT &= ~SCL;
        }

        void cack(void) /* 應答位檢查 */
        {
        P2OUT |= SDA;
        P2OUT |= SCL;

        P2DIR &= ~SDA;

        _NOP();
        P2OUT &= ~SCL;

        P2DIR |= SDA;

        }

        void delay(uchar time)
        {
        uchar i;

        do{
        for(i=100;i!=0;i--);

        } while(--time!=0);

        }

        /*----------------------------------------------------------------------
        ;名稱:SendByte
        ;描述:字節(jié)數(shù)據(jù)傳送子程序發(fā)送一個字節(jié)數(shù)據(jù)或地址給被控器PCF8576
        ;要發(fā)送的數(shù)據(jù)在ACC 中
        ;發(fā)送數(shù)據(jù)正常返回標志F0=0 F0=1 表示被控器無應答或損壞
        ;------------------------------------------------------------------------*/
        void SendByte(uchar Data)
        {
        uchar i=8;

        do
        {
        if((Data&0x80)==0x80)
        P2OUT |= SDA;
        else
        P2OUT &= ~SDA;

        P2OUT |= SCL;
        _NOP ();
        P2OUT &= ~SCL;

        Data=Data<<1;
        } while(--i!=0);

        cack();

        }

        /***********************************************************
        ;發(fā)送數(shù)據(jù)程序
        ;名稱:SendData
        ;描述:發(fā)送ByteCnt 個字節(jié)給被控器PCF8576
        ;被控器地址在SlvAdr 中單元地址在SubAdr 中
        ;所發(fā)送數(shù)據(jù)的字節(jié)數(shù)ByteCnt 在中發(fā)送的數(shù)據(jù)在XmtDat 緩沖區(qū)中
        ;發(fā)送數(shù)據(jù)正常返回標志F0=0 F0=1 表示被控器無應答或損壞
        ;**********************************************************/
        void Display_Data(void)
        {
        uchar i=0;
        uchar size=ByteCnt;

        START(); //發(fā)送I2C 總線起始條件

        SendByte(SlvAdr); //發(fā)送被控器總線地址

        SendByte(SubAdr); //發(fā)送單元地址

        // SendByte(0x73); //閃爍方式為正常,閃爍頻率為0.5Hz 的命令字送緩沖區(qū)首址,
        //如果不需要閃爍應將數(shù)#70H 送入緩沖區(qū)首址
        SendByte(0x70); //不閃爍


        do
        {
        SendByte(XmtDat[i]); //發(fā)送數(shù)據(jù)
        i++;
        } while(--size!=0);

        STOP();

        delay(100);
        }

        void ClearLcd(void)
        {
        uchar size=ByteCnt;

        START(); //啟動I2C 總線

        SendByte(SlvAdr); //送器件地址

        SendByte(SubAdr); //發(fā)送單元地址

        SendByte(0x70);

        do
        {
        SendByte(0x00); //發(fā)送數(shù)據(jù)
        } while(--size!=0);

        STOP();

        delay(200);
        }

        void PCF8576SET(void)
        {
        START();

        SendByte(SlvAdr); //送器件地址

        SendByte(MODE2); //取方式命令字

        SendByte(Bank_sel);

        STOP();
        }


        void main(void)
        {
        uint out_data;
        uint tmp_data;
        uchar i;
        uchar k;
        uchar tmp[5];

        P2DIR |= SDA; //SDA
        P2DIR |= SCL; //SCL

        P2OUT &= ~SDA;
        P2OUT &= ~SCL;

        WDTCTL = WDTPW+WDTHOLD;

        Digit[0]=0x7E; //0
        Digit[1]=0x18; //1
        Digit[2]=0xB6; //2
        Digit[3]=0xBC; //3
        Digit[4]=0xD8; //4
        Digit[5]=0xEC; //5
        Digit[6]=0xEE; //6
        Digit[7]=0x38; //7
        Digit[8]=0xFE; //8
        Digit[9]=0xFC; //9

        SubAdr=0x80;
        SlvAdr=PCF8576;
        ByteCnt=4;

        PCF8576SET();

        ClearLcd();

        out_data=0;

        while(1)
        {
        tmp_data=out_data;

        for(i=0;i {
        k=tmp_data%10;
        tmp_data=tmp_data/10;

        XmtDat[i]=Digit[k];
        tmp[i]=k;
        }

        XmtDat[2] |= 0x01;

        for(i=ByteCnt-1;i!=0;i--)
        {
        if( tmp[i] == 0 )
        XmtDat[i]=0x00;
        else
        break;
        }


        Display_Data();

        out_data++;

        }

        }
        這段程序網(wǎng)上轉(zhuǎn)載的最多,也不知道出處,好在其簡單易懂,配合PCF8576的PDF資料,總算是弄懂了這種兩線控制原件的控制方式,接下來,我剖拆了這個模塊,并測繪了其硬件電路圖,經(jīng)與資料比照,因其只有不到40段驅(qū)動位,只有一個背極,且其SA0腳接電源正極,從而確認其為靜態(tài)驅(qū)動方式,總線地址為0x72,工作指令字為0x49,不需閃爍時閃爍指令字為0x70,沒有用到存儲體選擇指令,沒有用到屏幕清零函數(shù)。由于這種I2C器件為單向器件,只送數(shù)據(jù),不讀數(shù)據(jù),送入數(shù)據(jù)的原理就是,不論多少數(shù)據(jù),都是利用“一位數(shù)據(jù)輸出函數(shù)”在時鐘脈沖的配合下,一位一位的送入器件,所以上述這段程序剛剛好用,比起哪些通用I2C程序簡單的多。事情往往就是這樣,一旦弄懂了原理,改編自己的應用程序就不是很難了。經(jīng)過改編,得到了自己的程序,這是一段演示程序,由它控制段碼屏在最右側(cè)一位累計加1,直到顯示99999時屏顯清零并重復,我是想,只要做到想在那個位置顯示,就能在那個位置顯示,也就可以了,至于其他的應用方式也就能夠?qū)崿F(xiàn)了,以下是我改編并測試通過的程序:

        /********************************************************************
        AT89S51驅(qū)動PCF8576演示5位計數(shù)顯示程序: WANNENGGONG改編 2010/4/25
        AT89S51的P0.1口做I2C的數(shù)據(jù)輸出口;P0.2做I2C的時鐘輸出口
        顯示效果為首先滿屏清零而后自動累加計數(shù)至顯示99999時清零后重復
        *********************************************************************/
        #include
        #include
        #define uchar unsigned char
        #define uint unsigned int
        #define PCF8576 0x72 //器件總線地址
        sbit SDA=P0^1; //定義模擬I2C數(shù)據(jù)傳送端口
        sbit SCL=P0^2; //定義模擬I2C時鐘控制端口
        bit ack; //定義應答標志位
        uchar ByteCnt; //I2C 數(shù)據(jù)字節(jié)計數(shù)器
        uchar SlvAdr; //被控器地址
        uchar SubAdr; //被控器單元地址
        uchar cnt[5]; //顯示數(shù)據(jù)寄存器
        uchar tmp[5]; //顯示數(shù)據(jù)緩沖區(qū)
        uchar MODE2=0x49; //工作方式命令字
        //uchar Bank_sel=0x7a; //存儲體選擇命令字(未定義)
        uchar Digit[]={0xd7,0x06,0xe3,0xa7,0x36,0xb5,0xf5,0x17,0xf7,0xb7,0xd7};
        //{0,1,2,3,4,5,6,7,8,9,0}字形碼;其定義方法參見硬件接線圖。
        //延時程序======延時2*t機器周期=====
        void delay(uchar t)
        {
        while(--t);
        }
        //延時程序======長延時=====
        void delay_long(uint time)
        {
        uchar i;
        do{
        for(i=100;i!=0;i--);
        } while(--time!=0);
        }
        /*********************************************************
        啟動總線函數(shù)
        名稱:START
        描述:啟動I2C 總線子程序--發(fā)送I2C 起始條件
        *********************************************************/
        void START(void)
        {
        SDA=1; SCL=1;
        delay(2); SDA=0;
        delay(2); SCL=0;
        }
        /*********************************************************
        停止總線函數(shù)
        名稱:STOP
        描述:停止I2C 總線子程序--發(fā)送I2C 總線停止條件
        *********************************************************/
        void STOP(void)
        {
        SDA=0; SCL=1;
        delay(2); SDA=1;
        delay(2); SCL=0;
        }
        void cack(void)
        {
        bit a;
        if(a==0)SDA=0; //在此發(fā)出應答或非應答信號
        else SDA=1;
        delay(2);
        SCL=1;
        delay(2); //時鐘低電平周期大于4μs
        SCL=0;
        delay(2); //清時鐘線,鉗住I2C總線以便繼續(xù)接收
        }
        /*********************************************************
        發(fā)送一個字節(jié)函數(shù)
        名稱:SendByte
        描述:字節(jié)數(shù)據(jù)傳送子程序發(fā)送一個字節(jié)數(shù)據(jù)或地址給被控器PCF8576
        要發(fā)送的數(shù)據(jù)在ACC中;
        發(fā)送數(shù)據(jù)正常返回標志F0=0 F0=1 表示被控器無應答或損壞
        *********************************************************/
        void SendByte(uchar Data)
        {
        uchar i=8;
        do
        {
        if((Data&0x80)==0x80)
        SDA=1;
        else
        SDA=0; SCL=1;SCL=0;
        Data=Data<<1;
        } while(--i!=0);
        cack();
        }
        /***********************************************************
        發(fā)送數(shù)據(jù)函數(shù)
        名稱:Display_Data
        描述:發(fā)送ByteCnt 個字節(jié)給被控器PCF8576
        被控器地址在SlvAdr 中單元地址在SubAdr 中
        所發(fā)送數(shù)據(jù)的字節(jié)數(shù)ByteCnt 在中發(fā)送的數(shù)據(jù)在tmp[ ] 緩沖區(qū)中
        發(fā)送數(shù)據(jù)正常返回標志F0=0 F0=1 表示被控器無應答或損壞
        **********************************************************/
        void Display_Data(void)
        {
        uchar i=0;
        uchar size=ByteCnt;
        START(); //發(fā)送I2C 總線起始條件
        SendByte(SlvAdr); //發(fā)送被控器總線地址
        SendByte(SubAdr); //發(fā)送單元地址
        SendByte(0x70); //不閃爍命令字
        do
        {
        SendByte(tmp[i]); //發(fā)送數(shù)據(jù)
        i++;
        } while(--size!=0);
        STOP();
        delay(100);
        }
        /*********************************************************
        清除屏顯函數(shù)(未采用)
        名稱:ClearLcd
        描述:在向顯示屏送數(shù)據(jù)前清除原有顯示內(nèi)容
        *********************************************************/
        /*********************************************************
        void ClearLcd(void)
        {
        uchar size=ByteCnt;
        START(); //啟動I2C 總線
        SendByte(SlvAdr); //送器件地址
        SendByte(SubAdr); //發(fā)送單元地址
        SendByte(0x70); //不閃爍命令字
        do
        {
        SendByte(0x00); //發(fā)送數(shù)據(jù)
        } while(--size!=0);
        STOP();
        delay(200);
        }
        *********************************************************/
        /*********************************************************
        器件總線初始化函數(shù)
        名稱:PCF8576SET
        描述:用于器件控制的重復操作的指令集和
        *********************************************************/
        void PCF8576SET(void)
        {
        START();
        SendByte(SlvAdr); //送器件地址
        SendByte(MODE2); //送方式命令字
        // SendByte(Bank_sel); //送存儲體選擇命令字
        STOP();
        }


        void main(void)
        {
        uchar i,k,m;
        uchar cnt[5];
        SubAdr=0x80; //為顯示緩沖區(qū)賦首地址
        SlvAdr=PCF8576; //賦器件總線地址
        ByteCnt=5; //顯示位數(shù)賦值
        PCF8576SET(); //總線初始化
        //ClearLcd(); //清除屏顯
        while(1)
        {
        for(m=1;m<11;m++) //0-9 10個數(shù)字計數(shù)
        {
        for(k=0;k<5;k++) //循環(huán)5次形成穩(wěn)定顯示
        {
        for(i=0;i<5;i++) //5位顯示
        {
        /***************************************************************************************
        以下的程序含義:
        顯示數(shù)據(jù)寄存器cnt[5]設(shè)定后,在沒有裝填前只是5個空位置,此時cnt[0]=0;cnt[1]=0---cnt[i]=0;
        在第一次執(zhí)行tmp[i]=Digit[cnt[i]];時,屏幕顯示5位全0,接下來執(zhí)行cnt[4]++;后cnt[4]=1
        此后在下一次執(zhí)行tmp[i]=Digit[cnt[i]];時tmp[0]=Digit[cnt[0]]=Digit[0]=0(0xd7)其它依次同上
        直至tmp[4]=Digit[cnt[4]]=Digit[1]=1(0x06);此時屏顯為00001;循環(huán)重復直至當?shù)谝蛔址焕塾?br />為9時屏顯為99999此后屏顯清0如上重復。
        ****************************************************************************************/
        tmp[i]=Digit[cnt[i]]; //顯示數(shù)據(jù)裝入顯示緩存區(qū)
        Display_Data(); //顯示
        delay_long(50); //通過延時控制顯示字符的變換速度
        }
        }
        /*********************************************************************
        以下的程序含義:
        首先在第5位累加,滿10進位1至99999時清0重復
        能力所限、終未能將下面單調(diào)的重復語句變?yōu)橐粋€算式模型。
        *********************************************************************/
        cnt[4]++;
        if(cnt[4]>9)
        {
        cnt[4]=0;
        cnt[3]++;
        }
        if(cnt[3]>9)
        {
        cnt[3]=0;
        cnt[2]++;
        }
        if(cnt[2]>9)
        {
        cnt[2]=0;
        cnt[1]++;
        }
        if(cnt[1]>9)
        {
        cnt[1]=0;
        cnt[0]++;
        }
        if(cnt[0]>9)
        break;
        }
        }
        }

        程序中0-9的數(shù)字編碼是根據(jù)實際測繪的硬件電路圖編制的,至于別人程序中或PDF資料中的編碼方式,是絕不可以照搬的,因為每一種模塊的內(nèi)部接線都不盡相同,編碼也就不同了,這種電路在控制時,最主要的一點就是,一定要根據(jù)段碼位數(shù)先建立一個數(shù)組(顯示數(shù)據(jù)存儲區(qū)),在數(shù)據(jù)顯示之前,先把顯示數(shù)據(jù)裝填到數(shù)組當中,再把它按位送入顯示緩沖區(qū)就OK了,至于開總線,關(guān)總線,送指令,送數(shù)據(jù)等等都是模式化操作,只要按規(guī)定做好即可,控制起來也沒什么太復雜的;因為只是玩玩,不求甚解,至此,這只模塊也就玩完了,如果日后需要數(shù)字顯示的話或許還能用到它,別的用途我就想不出來了,至于做時間顯示,我總覺得它土不土、洋不洋沒勁。這種器件已流傳很久了,或許已經(jīng)過時了,或許還有新出的我不知道,雖然我玩過了,但這些資料可能還會有人有用,所以就放在這里共享吧。還是老辦法,程序是在μV2編譯軟件窗口中粘貼過來的,若有用的話反向操作即可;如果用到了就知會一聲,可以共享可以轉(zhuǎn)載,但不可做為網(wǎng)站的登陸下載資源,發(fā)現(xiàn)必究,僅此而已,別無它求。

        附硬件電路圖:



        關(guān)鍵詞: AT89S51I2CPCF8576段碼LCD模

        評論


        技術(shù)專區(qū)

        關(guān)閉
        主站蜘蛛池模板: 曲沃县| 朝阳县| 新乡市| 苍溪县| 蕉岭县| 怀宁县| 类乌齐县| 防城港市| 嘉义市| 扎鲁特旗| 永丰县| 惠水县| 共和县| 旬阳县| 西畴县| 隆林| 岳普湖县| 亚东县| 柏乡县| 沙河市| 油尖旺区| 顺平县| 永寿县| 南漳县| 交口县| 剑川县| 瑞金市| 五台县| 三穗县| 翁牛特旗| 巧家县| 繁峙县| 天全县| 靖州| 永安市| 咸宁市| 嘉义县| 盘山县| 罗田县| 定安县| 荆门市|