| 首先降低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 代码 |