呵呵,不用我說你們也知道為什么只需要4根線:因?yàn)樵塾昧?4hc595啊!因?yàn)?4HC595最近我手里一抓一大把。但是STC的單片機(jī)IO口緊缺。就算使用4線驅(qū)動(dòng)模式也要8個(gè)IO(還要算上背光PWM)。這一次我?guī)缀踝龅搅怂囊话搿H绻挥肞WM的話。大概只需要3個(gè)IO,如果需要PWM就四個(gè)羅。
MCU當(dāng)然是老掉牙的死特慘89C52羅~
也可以在595后面級聯(lián)類似三極管開關(guān)……繼電器之類的玩意。當(dāng)然友情提醒,別超過4個(gè)595.否則速度會(huì)慢的可怕。我現(xiàn)在1個(gè)595.寫1602都可以丟掉延時(shí)函數(shù)了。
這一次硬件設(shè)計(jì)的比較簡單,但是IO全反了。所以需要占用額外的CPU時(shí)間修正,但是畢竟方便洞洞板嘛。還有大家別看到我給A和B賦了好幾次值而去“優(yōu)化”代碼。如果您“優(yōu)化”的話,那么就根本驅(qū)動(dòng)不起來,因?yàn)?1的加法減法乘除都要經(jīng)過ACC和B,如果不去重新賦值的話,那么就會(huì)發(fā)生改變的現(xiàn)象。不過我這種位尋址軟件修正可比那種xx=xx & xx的效率高多了。如果我這么寫的話。恐怕刷一個(gè)屏幕沒1秒下不來啊。12T的51就這個(gè)速度……
不過這一次焊板子實(shí)在是太倉促了。對比度電位器焊在液晶下面,結(jié)果初始化成功了顯示兩排方塊。暈了半天。調(diào)試半天還是沒用。后來捅了一下背面就好了……暈……!
上代碼:
#include <stc89c5x.h>//STC89C52 //串行驅(qū)動(dòng)1602,powered by 595 #define LCD1602_BACKLIGHT P1_3//背光 #define LCD1602_SDA P1_0//數(shù)據(jù)輸入 #define LCD1602_SCK P1_1//移位時(shí)鐘,SHCP,11pin #define LCD1602_SCL P1_2//鎖存時(shí)鐘,STCP,12pin /* * 硬件連接: * 74HC595 Q7 - 1602 RS * GND - 1602 RW(595沒有輸入功能,所以判定忙只能*延時(shí),另外就是MCU的速度比較的慢。所以也可以直接去掉延時(shí)。但是在STC12系列上的表現(xiàn),相當(dāng)?shù)牟诲e(cuò) * 在傳統(tǒng)51上面。PWM占空比低于50%將會(huì)出現(xiàn)掃描線。12系列的,很高興的告訴大家。T0X12開了以后。不會(huì)有掃描線出現(xiàn)。但是如果一定要在傳統(tǒng)51上使用的話,請把10級調(diào)光改成4級。謝謝合作! * 74HC595 Q6 - 1602 EN * 74HC595 Q5~Q2 - 1602 D5~D7(這一次硬件設(shè)計(jì)不合理,才只能搞軟件修正了。不過好處就是直接就可以洞洞板上對著聯(lián),減少了燒壞595的概率。壞處就是CPU時(shí)間消耗的多了點(diǎn)。但是可以取消延時(shí)函數(shù)啦~ * 1602 D1~D4 直接懸空 * LCD_BACKLIGHT加一級PNP三極管射隨器加到液晶的A上,如果無需調(diào)光可以去掉這一部分電路和代碼 * 至于595的連接,只要不弄反SCL和SCK,就沒有問題啦~ */ __sbit __at 0xE0 A_0;//方便位操作,硬件設(shè)置真的是敗筆 - - __sbit __at 0xE1 A_1; __sbit __at 0xE2 A_2; __sbit __at 0xE3 A_3; __sbit __at 0xE4 A_4; __sbit __at 0xE5 A_5; __sbit __at 0xE6 A_6; __sbit __at 0xE7 A_7; __sbit __at 0xF1 B_1; __sbit __at 0xF2 B_2; __sbit __at 0xF3 B_3; __sbit __at 0xF4 B_4; __sbit __at 0xF5 B_5; __sbit __at 0xF6 B_6; __sbit __at 0xF7 B_7; unsigned char PWM_Cycle=0;//PWM占空比 unsigned char PWM_T=0;//PWM當(dāng)前所處周期 unsigned char OutBuf=0xff;//輸出緩沖 #define LCD_OFF lcd_wcmd(0x08) #define LCD_CUR lcd_wcmd(0x0E) #define LCD_FCUR lcd_wcmd(0x0F) void delay(unsigned int n) { unsigned int x,y; for(x=n;x>0;x--) for(y=100;y>0;y--); } void Send595() { unsigned char i,j; j=0x80; LCD1602_SCK=0; for(i=0;i<8;i++) { LCD1602_SDA=OutBuf & j; j=j>>1; LCD1602_SCK=1; LCD1602_SCK=0; } LCD1602_SDA=1; LCD1602_SCL=0; LCD1602_SCL=1; } void lcd_en() { //OutBuf=OutBuf|0x40;//E=1 B=OutBuf; B_6=1; OutBuf=B; Send595();//輸出數(shù)據(jù) B=OutBuf; B_6=0; OutBuf=B;//E=0 Send595(); } /**********************************************************/ void lcd_wcmd(unsigned char i) { //寫命令 B=OutBuf; B_7=0;//RS=0,RW=0; OutBuf=B; Send595(); //-------------- B=OutBuf; ACC=i; B_2=A_7;//D7=D7 B_3=A_6;//D6=D6 B_4=A_5;//D5=D5 B_5=A_4;//D4=D4 OutBuf=B; Send595(); lcd_en(); //================ ACC=i; B=OutBuf; B_2=A_3;//D7=D3 B_3=A_2;//D6=D2 B_4=A_1;//D5=D1 B_5=A_0;//D4=D0 OutBuf=B; Send595(); lcd_en(); } void lcd_wdat(unsigned char i) { //寫數(shù)據(jù) B=OutBuf; B_7=1;//RS=0,RW=0; OutBuf=B; Send595(); //-------------- B=OutBuf; ACC=i; B_2=A_7;//D7=D7 B_3=A_6;//D6=D6 B_4=A_5;//D5=D5 B_5=A_4;//D4=D4 OutBuf=B; Send595(); lcd_en(); //================ ACC=i; B=OutBuf; B_2=A_3;//D7=D3 B_3=A_2;//D6=D2 B_4=A_1;//D5=D1 B_5=A_0;//D4=D0 OutBuf=B; Send595(); lcd_en(); } void lcd_putchar(unsigned char addr,unsigned char ch) {//寫一個(gè)字 lcd_wcmd(0x80+addr); lcd_wdat(ch); } void lcd_display(unsigned char *l1,unsigned char *l2) {//寫一屏幕 unsigned char i=0; lcd_wcmd(0x80); //顯示地址設(shè)為80H(即00H,)上排第一位 for(i=0;i<16;i++) { lcd_wdat(l1[i]); } lcd_wcmd(0x80+0x40); //重新設(shè)定顯示地址為0xc0,即下排第1位 for(i=0;i<16;i++) { lcd_wdat(l2[i]); } } void lcd_cls() { lcd_wcmd(0x01); //清屏延時(shí)函數(shù)可以省略 } //米有讀函數(shù),但是功能可以由上面的函數(shù)擴(kuò)展哦~ void lcd_init() { OutBuf=0xff; Send595();//復(fù)位VIO,這段代碼必須加。否則MCU忽然RESET會(huì)導(dǎo)致液晶亂碼 lcd_wcmd(0x30);//復(fù)位1602,這段代碼必須加,同上 lcd_en();//喚醒 lcd_wcmd(0x20); lcd_en();//喚醒 lcd_wcmd(0x28); //四位,5x7 lcd_wcmd(0x0c); //開啟顯示屏,關(guān)光標(biāo),光標(biāo)不閃爍 lcd_wcmd(0x06); //顯示地址遞增,即寫一個(gè)數(shù)據(jù)后,顯示位置右移一位 lcd_wcmd(0x01); //清屏 //調(diào)試的時(shí)候被設(shè)計(jì)失誤的對比度電位器坑死了:就是兩排小方塊死都不顯示 //查了半天都不知道 //最后捅了下電位器就正常了…… } void lcd_print(unsigned char *str) { unsigned char addr=0x80,len=0; lcd_wcmd(addr); //顯示地址設(shè)為80H(即00H,)上排第一位 while(*str!='\0') {//等待末尾 if(len >= 16) { lcd_wcmd(0x80+0x40);//下排第一位,換行 len=0; } if(*str=='\n') { lcd_wcmd(0x80+0x40);//下排第一位,換行 } else { lcd_wdat(*str); } str++; len++; } }//寫字符串函數(shù) void PWM() __interrupt 1 __using 1 { ET0=0; TF0=0;//CLR TR0=0; EA=0; TH0=0xFC;TL0=0x00;//十級調(diào)光,頻率400Hz if(PWM_T>10) {PWM_T=0;} if(PWM_Cycle>PWM_T){ LCD1602_BACKLIGHT=0;} if(PWM_Cycle<PWM_T) {LCD1602_BACKLIGHT=1;} PWM_T++; TR0=1; ET0=1; EA=1; } void main() {//主函數(shù) TMOD = 0x01 ; TH0=0xFC;TL0=0x00; TR0=1;ET0=1; EA=1;//開中斷 //----------------- lcd_init(); PWM_Cycle=10;//背光100% //液晶初始化--------- while(1) { lcd_display(" Hello world! ","Serial mode 1602"); delay(2000); lcd_display("Drive by 74HC595","Design by rgwan "); delay(2000); lcd_display("Website address:"," www.rwzy.co.cc "); delay(2000); lcd_display("Backlight ctl by"," T0 PWM 400Hz "); delay(2000); } }
下面上圖片:
自己DIY的最小系統(tǒng),旁邊是串口轉(zhuǎn)接器。這個(gè)板子上有兩個(gè)晶振跳線選擇
外加一個(gè)外界晶振。現(xiàn)在這個(gè)晶振跳在內(nèi)置的11.0592上。