![]() |
首先降低MCU的頻率試試,如果不亂碼了,說明是時鐘太快了,1602硬件無法響應。可以把程序里E脈沖后面適當加些延時,比如幾個nop語句,實在不行,加1us~2u延時。 |
有可能是時鐘的問題,協議出錯 |
hi等你 發表于 2024-4-8 09:00 他這個是用了一個IIC轉并口的轉換,屏跟單片機是IIC接口的 |
![]() 該程序可以顯示的,,,,,真機上,可能晶振不同,也許要調整一下延時。 |
關于LCD1602顯示屏的兩個文件: /****************************************************************************** * 文件: 頭文件 LCD1602.H * 說明: 關于LCD1602的驅動函數: 用于STC32G12K128 自制實驗板 * 編程: 浦曉明(浦江一水) 2023.10 * 特點: 經典實用/簡明扼要/便于移植 * 接口: 數據口-P0 指令-P4.5 讀寫-P2.7 使能-P2.6 ***************************************************************************** */ #include "STC32G.h" #ifndef __LCD1602_H_ #define __LCD1602_H_ /***************************************** LCD1602PIN口定義 (數據口和控制位說明) ******************************************/ #define LCD_DATAP P0 //P0數據口(8位) sbit LCD_RS =P4^5; //指令端 0:命令 1:數據 sbit LCD_RW=P2^7; //讀寫端 0;寫入 1:讀出(直接接地--只寫方式) sbit LCD_E =P2^6; //使能端 0:失能 1:使能 /***************************************** 函數聲明 ******************************************/ /*在11.0592MHz時鐘下的延時1ms毫秒函數*/ void LCD_Delay1ms(unsigned int ms); //誤差 0us /*LCD1602初始化子程序*/ void LCD_Init(void); /*LCD1602 清屏函數 */ void LCD_CLS(void); /*LCD1602寫入8位命令子函數*/ void LCD_COM(unsigned char com); /*LCD1602寫入8位數據子函數*/ void LCD_DAT(unsigned char dat); /*LCD1602指定坐標寫字符串函數 X:行(0/1) Y:列(0-15) */ void LCD_STR(unsigned char X,unsigned char Y,unsigned char * str); void LCD_SetXY(unsigned char,unsigned char); //定位 void LCD_Cursor(unsigned char mode); //控制光標 void LCD_Blink(unsigned char mode); //控制閃爍 #endif /****************************************************************************** * 文件: LCD1602.C * 說明: 關于LCD1602驅動函數的實現: 用于STC32G12K128 自制實驗板 * 編程: 浦曉明(浦江一水) 2023.10 * 特點: 經典實用/簡明扼要/便于移植 * 接口: 數據口-P0 指令-P4.5 讀寫-P2.7 使能-P2.6 ***************************************************************************** */ #include "LCD1602.H" /******************************************************************************* * 函 數 名 : LCD1602_Delay1ms * 函數功能 : 延時函數,延時1ms * 輸 入 : 無 * 輸 出 : 無 * 說 名 : 該函數是在11.0592MHZ晶振下,12分頻單片機的延時。//誤差 0us *******************************************************************************/ void Delay1ms() //@11.0592MHz { unsigned char i, j; i = 15; j = 90; do { while (--j); } while (--i); } void LCD_Delay1ms(unsigned int ms) { for (; ms>0; ms--)Delay1ms(); } /******************************************************************************* * 函 數 名 : LCD1602_COM(unsigned char com) * 函數功能 : 向LCD寫入一個字節的命令 * 輸 入 : com * 輸 出 : 無 *******************************************************************************/ void LCD_COM(unsigned char com) //八位/四位數據口寫入共用 { LCD_E = 0; Delay1ms(); LCD_RW= 0; Delay1ms(); //選擇寫入 LCD_RS= 0; Delay1ms(); //選擇發送命令 LCD_E = 0; Delay1ms(); //使能 LCD_DATAP= com; LCD_Delay1ms(2); //先發送命令字節高四位 LCD_E = 1; Delay1ms(); //寫入時序(脈沖) LCD_E = 0; Delay1ms(); } /******************************************************************************* * 函 數 名 : LCD1602_DAT(unsigned char dat); * 函數功能 : 向LCD寫入一個字節的數據 * 輸 入 : dat * 輸 出 : 無 *******************************************************************************/ void LCD_DAT(unsigned char dat) //寫入數據 { LCD_E = 0; Delay1ms(); LCD_RW= 0; Delay1ms(); //選擇寫入 LCD_RS= 1; Delay1ms(); //選擇輸入數據 LCD_E = 0; Delay1ms(); //清零使能 LCD_DATAP= dat; LCD_Delay1ms(2); //先發送數據字節高四位 LCD_E = 1; Delay1ms(); //寫入時序(脈沖) LCD_E = 0; Delay1ms(); } /******************************************************************************* * 函 數 名 : LCD1602_Init(void) * 函數功能 : 初始化LCD屏 * 輸 入 : 無 * 輸 出 : 無 *******************************************************************************/ void LCD_Init(void) //LCD初始化子程序 { LCD_COM(0x38); //開顯示 LCD_COM(0x38); //開顯示 LCD_COM(0x0C); //開顯示不顯示光標 LCD_COM(0x06); //寫一個指針加1 LCD_COM(0x01); //清屏 LCD_COM(0x80); //設置數據指針起點 } /******************************************************************************* * 函 數 名 : LCD1602_CLS(void) * 函數功能 : 清屏 *******************************************************************************/ void LCD_CLS(void) { LCD_COM(0x01); //清屏 LCD_COM(0x80); //設置數據指針起點 } /*LCD1602寫入字符串函數*/ //指定坐標函數 ( X:行[0-1] Y:列[0-15] ) void LCD_STR(unsigned char X,unsigned char Y,unsigned char * str) { unsigned char i = 0; LCD_COM(0x80+X*0x40+Y); while(str[i]!= 0x0)LCD_DAT(str[i++]); } //設定坐標函數 ( X:行[0-1] Y:列[0-15] ) void LCD_SetXY(unsigned char X,unsigned char Y) { if(X==0)LCD_COM(Y+0x80); if(X==1)LCD_COM(Y+0xC0); } //LCD定位顯示光標函數 mode=0:光標關閉 mode=1:光標顯示 void LCD_Cursor(unsigned char mode) { if(mode==0)LCD_COM(0x0C); if(mode==1)LCD_COM(0x0E); } //LCD定位顯示光標函數 mode=0:關閉閃動 mode=1:開啟閃動 void LCD_Blink(unsigned char mode) { if(mode==0)LCD_COM(0x0C); if(mode==1)LCD_COM(0x0D); } //*** END **************************************************************************** 管理 |
1602按下后會有亂碼的問題,其實根本上是硬件引起的。 某些最小系統板的復位電路沒做好,按下復位鍵后,就會產生亂碼 |
wwees 發表于 2024-4-7 22:40 點亮一個1602怎么這么多代碼?這是什么語言我也看不懂頭暈,匯編十條以內就點亮字符了 |
wwees 發表于 2024-4-7 22:40
|
具體得看程序,原理圖一般沒問題 |
典型的軟件故障,看原理圖沒用。 |
#include<reg51.h> //加載頭文件 #include<intrins.h> #define uchar unsigned char //宏定義 #define uint unsigned int #define AddWr 0x90 //PCF8591地址 #define LCD_DATA P0 //液晶數據口定義 #define RS_CLR LCD_RS=0 //液晶控制口宏定義 #define RS_SET LCD_RS=1 #define RW_CLR LCD_RW=0 #define RW_SET LCD_RW=1 #define EN_CLR LCD_EN=0 #define EN_SET LCD_EN=1 sbit LCD_RS=P2^7; //液晶控制口定義 sbit LCD_RW=P2^6; sbit LCD_EN=P2^5; sbit SCL=P2^2; //I2C時鐘-PCF8591 sbit SDA=P2^1; //I2C數據-PCF8591 sbit lamp=P2^3;//燈 sbit k1=P1^2;//按鈕 sbit k2=P1^3; int light=0; //光照度變量 uchar dis; //ADC用變量 uint limit=100;//光強 uint time=0; uint pwm=0,sec=0; bit ack; //應答標志位 void Delay_US(uchar t) //US延時函數 { while(--t); } void Delay_MS(uchar t) //MS延時函數 { while(t--) { Delay_US(245); Delay_US(245); } } void Lcd_W_Com(uchar com) //液晶寫指令函數 { RS_CLR; RW_CLR; LCD_DATA=com; Delay_MS(1); EN_SET; Delay_MS(1); EN_CLR; } void Lcd_W_Dat(uchar dat) //液晶寫數據函數 { RS_SET; RW_CLR; LCD_DATA=dat; Delay_MS(1); EN_SET; Delay_MS(1); EN_CLR; } void Lcd_Clr_Scr() //液晶清屏函數 { Lcd_W_Com(0x01); Delay_MS(5); } void Lcd_Show_String(uchar x,uchar y,uchar *s) //液晶顯示字符串函數 { if(y==0) Lcd_W_Com(0x80+x); //表示第一行 else Lcd_W_Com(0xC0+x); //表示第二行 while(*s) { Lcd_W_Dat(*s); s++; } } void Lcd_Show_Char(uchar x,uchar y,uchar dat) //液晶寫字符函數 { if(y==0) Lcd_W_Com(0x80+x); else Lcd_W_Com(0xC0+x); Lcd_W_Dat(dat); } void Lcd_Init() //液晶初始化函數 { Lcd_W_Com(0x38); //顯示模式設置 Lcd_W_Com(0x08); //顯示關閉 Lcd_W_Com(0x01); //顯示清屏 Lcd_W_Com(0x06); //顯示光標移動設置 Lcd_W_Com(0x0C); //顯示開及光標設置 } void IIC_Start() //總線啟動函數 { SDA=1; //發送起始條件的數據信號 _nop_(); SCL=1; _nop_(); //起始條件建立時間大于4.7us,延時 _nop_(); _nop_(); _nop_(); _nop_(); SDA=0; //發送起始信號 _nop_(); //起始條件鎖定時間大于4μs _nop_(); _nop_(); _nop_(); _nop_(); SCL=0; //鉗住I2C總線,準備發送或接收數據 _nop_(); _nop_(); } void IIC_Stop() //總線結束函數 { SDA=0; //發送結束條件的數據信號 _nop_(); //發送結束條件的時鐘信號 SCL=1; //結束條件建立時間大于4μs _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); SDA=1; //發送I2C總線結束信號 _nop_(); _nop_(); _nop_(); _nop_(); } void IIC_Send_Byte(uchar c) //IIC發送字節函數 { uchar i; for(i=0;i<8;i++) //要傳送的數據長度為8位 { if((c<<i)&0x80) SDA=1; //判斷發送位 else SDA=0; _nop_(); SCL=1; //置時鐘線為高,通知被控器開始接收數據位 _nop_(); _nop_(); //保證時鐘高電平周期大于4μs _nop_(); _nop_(); _nop_(); SCL=0; } _nop_(); _nop_(); SDA=1; //8位發送完后釋放數據線,準備接收應答位 _nop_(); _nop_(); SCL=1; _nop_(); _nop_(); _nop_(); if(SDA==1) ack=0; else ack=1; //判斷是否接收到應答信號 SCL=0; _nop_(); _nop_(); } uchar IIC_Receive_Byte() //IIC接收字節函數 { uchar retc=0,i; SDA=1; //置數據線為輸入方式 for(i=0;i<8;i++) { _nop_(); SCL=0; //置時鐘線為低,準備接收數據位 _nop_(); _nop_(); //時鐘低電平周期大于4.7μs _nop_(); _nop_(); _nop_(); SCL=1; //置時鐘線為高使數據線上數據有效 _nop_(); _nop_(); retc=retc<<1; if(SDA==1) retc=retc+1; //讀數據位,接收的數據位放入retc中 _nop_(); _nop_(); } SCL=0; _nop_(); _nop_(); return(retc); } void IIC_Ack(bit a) //IIC應答函數 { if(a==0) SDA=0; //在此發出應答或非應答信號 else SDA=1; //0為發出應答,1為非應答信號 _nop_(); _nop_(); _nop_(); SCL=1; _nop_(); _nop_(); //時鐘低電平周期大于4μs _nop_(); _nop_(); _nop_(); SCL=0; //清時鐘線,住I2C總線以便繼續接收 _nop_(); _nop_(); } bit Pcf_Send_Byte(uchar addr,uchar channel) //PCF8591寫一個控制指令 { //addr(器件地址),channel(轉換通道) IIC_Start(); //啟動總線 IIC_Send_Byte(addr); //發送器件地址 if(ack==0) return(0); IIC_Send_Byte(0x40|channel); //發送控制字節 if(ack==0) return(0); IIC_Stop(); //結束總線 return(1); } uchar Pcf_Receive_Byte(uchar addr) //PCF8591讀取一個轉換值 { uchar dat; IIC_Start(); //啟動總線 IIC_Send_Byte(addr+1); //發送器件地址 if(ack==0) return(0); dat=IIC_Receive_Byte(); //讀取數據0 IIC_Ack(1); //發送非應答信號 IIC_Stop(); //結束總線 return(dat); } //主函數 void main() { Lcd_Init(); //液晶初始化 Lcd_Clr_Scr(); //液晶清屏 Lcd_Show_String(1,0,"Light"); //液晶顯示固定字符 Lcd_Show_String(13,0,"lx"); Lcd_Show_String(1,1,"lim"); Lcd_Show_String(13,1,"lx"); TMOD|=0X01; TH0=0X3C; TL0=0XB0; ET0=1;//打開定時器0中斷允許 EA=1;//打開總中斷 TR0=1;//打開定時器 while(1) { if(!k1)//加 { limit++; while(!k1); } if(!k2)//減 { limit--; while(!k2); } //PWM if(sec<99) sec++; else sec=1; if(pwm<sec) lamp=1; else lamp=0; } } //定時器0中斷 void Timer0() interrupt 1 { if(time<10)//定時0.5s time++; else { time=0; Pcf_Send_Byte(AddWr,0); dis=Pcf_Receive_Byte(AddWr); //ADC0 模數轉換0 光敏電阻 light=-39*dis+10000; Lcd_Show_Char(7,0,light/10000+'0'); //光照度顯示 萬 Lcd_Show_Char(8,0,light%10000/1000+'0'); //千 Lcd_Show_Char(9,0,light%1000/100+'0'); //百 Lcd_Show_Char(10,0,light%100/10+'0'); //十 Lcd_Show_Char(11,0,light%10+'0'); // 個 Lcd_Show_Char(7,1,light%10000/1000+'0'); //千 Lcd_Show_Char(8,1,limit/100+0x30); // 百 Lcd_Show_Char(9,1,limit%100/10+0x30); // 十 Lcd_Show_Char(10,1,limit%10+0x30); // 個 if(light>limit)//功能1 { pwm=0; } else { pwm=99-light*100/limit;//輸出PWM占空比,光照強度越低,pwm占空比越大 } } TH0=0X3C; TL0=0XB0; } |
1 硬件 連接 2 代碼 |