找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2078|回复: 13
打印 上一主题 下一主题
收起左侧

单片机+LCD1602只有背光,没有显示,求解决

  [复制链接]
跳转到指定楼层
楼主
酒精测试仪,实物制作完成后导入程序,液晶屏只亮灯,不显示,问了师兄说是时序问题,很苦恼,求解决

单片机源程序如下:
  1. //程序头函数
  2. #include <stc15.h>
  3. #include <intrins.h>
  4. #define uint unsigned int
  5. #define uchar unsigned char
  6. #define LCD1602 P0
  7. #define key_S 3                                        //宏定义按键短按(约15ms)
  8. #define key_L key_S*35                        //宏定义按键长按(约500ms)
  9. #define key_I key_S*27                        //宏定义长按连+/-间隔(约120ms)
  10. //宏定义ADC的操作命令
  11. #define ADC_POWER   0x80                        //ADC power control dit (宏定义ADC电源控制位)1000 0000
  12. #define ADC_START   0x08                        //ADC start control dit (宏定义ADC启动控制位)0000 1000
  13. #define ADC_FLAG    0x10                        //ADC complete flag (宏定义ADC完成标志位)    0001 0000
  14. #define ADC_SPEEDLL 0x00                        //420 clocks (宏定义420时钟)速度控制         0000 0000
  15. //宏定义ISP的操作命令
  16. #define CMD_IDLE    0               //空闲模式
  17. #define CMD_READ    1               //IAP字节读命令
  18. #define CMD_PROGRAM 2               //IAP字节编程命令
  19. #define CMD_ERASE   3               //IAP扇区擦除命令
  20. #define ENABLE_IAP  0x82            //CPU的等待时间
  21. #define IAP_ADDRESS 0x0800                                //保存地址
  22. //管脚声明
  23. #define LCD1602 P0
  24. sbit LED_R= P2^2; //红指示灯
  25. sbit LED_G= P2^0; //绿色指示灯
  26. sbit FENG = P2^5; //蜂鸣器
  27. sbit LCD_RS=P2^3;        //液晶屏RS口
  28. sbit LCD_EN=P2^1;        //液晶屏EN口
  29. sbit Key1=P2^6;        //检测/复位
  30. sbit Key2=P2^7;   //设置
  31. sbit Key3=P3^6;         //加
  32. sbit Key4=P3^7;   //减
  33. //变量定义
  34. uchar table[] ="ALCOHOL:   mg";        //第一行"酒精"
  35. uchar table1[]="WARNING H000 L00";//第二行"警告"
  36. uchar data dis_buf[]="000H000L000";
  37. bit flashing;                //闪烁标志
  38. bit Rev_Stop;                //启动/停止标志
  39. bit preset;                        //预置标志
  40. uchar KeySec;                        //键值
  41. uchar set;          //设置标志位
  42. uint TheH,TheL;        //浓度高/浓度低参考值
  43. uint num,num1;                //计数变量
  44. uchar ADCP,PH;                //AD转换值
  45. uchar WARNING;         // 初始报警值
  46. uchar i;
  47. //函数声明
  48. void Timer0Init();                                        //定时器0初始化声明
  49. void Timer2Init();                                        //定时器2初始化声明
  50. void Delay1ms();                                                //延时子程序声明
  51. void key_scan();                                                //按键扫描声明
  52. void ADC_Init();                                                //初始化ADC子程序声明
  53. uchar Read(uchar CHA);                                //ADC转换子程序声明
  54. void detection();
  55. void IapIdle();                                                //关闭IAP/EEPROM
  56. void init_eeprom();
  57. uchar IapReadByte(uint addr);                //读取EEPROM数据
  58. void IapProgramByte(uint addr, uchar dat);//写入EEPROM数据
  59. void IapEraseSector(uint addr);        //擦除EEPROM数据
  60. void write_com(uchar com);                        //1602液晶屏写指令程序
  61. void write_date(uchar date);                //1602液晶屏写数据程序
  62. void LCD_init();                                                //1602液晶屏初始化程序
  63. void display();                                                //显示函数
  64. void alarm();                                                        //报警函数
  65. void Buzzer_second();
  66. //主函数
  67. void main()
  68. {
  69.         P0M0 = 0x00;
  70.         P0M1 = 0x00;
  71.         P1M1 = 0x01;                                         //设置P1.0高阻ADC输入
  72.         P1M0 = 0x00;                                         //设置P1.0高阻ADC输入
  73.         P2M0 = 0x00;
  74.         P2M1 = 0x00;
  75.         P3M0 = 0x00;
  76.         P3M1 = 0x00;
  77.         P4M0 = 0x00;
  78.         P4M1 = 0x00;
  79.         P5M0 = 0x00;
  80.         P5M1 = 0x00;
  81.         P6M0 = 0x00;
  82.         P6M1 = 0x00;
  83.         P7M0 = 0x00;
  84.         P7M1 = 0x00;

  85.         Timer0Init();                                        //定时器0初始化
  86.         Timer2Init();                                        //定时器2初始化
  87.         ADC_Init();                                                //初始化ADC
  88.         LCD_init();                                 //初始化液晶屏
  89.         init_eeprom();                                  //读取eeprom初始数据      

  90.         while(1)//主循环
  91.         {
  92.                 key_scan();//按键扫描
  93.                 if(num==0 && preset==1)//自动保存设置
  94.                 {
  95.                         IapEraseSector(IAP_ADDRESS);
  96.                         IapProgramByte(IAP_ADDRESS, TheH);
  97.                         IapProgramByte(IAP_ADDRESS+1, TheL);
  98.                         preset=0;
  99.                         KeySec=0;
  100.                 }
  101.                 detection();//检测酒精浓度
  102.                 display();//刷新LCD
  103. //                alarm();//报警函数
  104. //                Buzzer_second();
  105.         }
  106. }

  107. /*---------------------------------------------
  108.   定时器0初始化,时钟12T、16位重载模式
  109. ----------------------------------------------*/
  110. void Timer0Init(void)                //50毫秒@11.0592MHz
  111. {
  112.         AUXR &= 0x7F;                //定时器时钟12T模式
  113.         TMOD &= 0xF0;                //设置定时器模式
  114.         TL0 = 0x00;                //设置定时初始值
  115.         TH0 = 0x4C;                //设置定时初始值
  116.         TF0 = 0;                //清除TF0标志
  117.         TR0 = 1;                //定时器0开始计时
  118.         EA  = 1;                //开总中断
  119.         ET0 = 1;
  120. }
  121. /*---------------------------------------------
  122.   定时器2初始化,时钟12T、16位重载模式
  123. ----------------------------------------------*/
  124. void Timer2Init()                                        //250微秒@11.0592MHz
  125. {
  126.         AUXR &= 0xFB;                                        //定时器时钟12T模式
  127.         T2L = 0x1A;                                                //设置定时初值
  128.         T2H = 0xFF;                                                //设置定时初值
  129. //        AUXR |= 0x10;                                        //定时器2开始计时

  130.         IE2 |=0x04;                                            //允许中断
  131. }
  132. /*****************************
  133.         蜂鸣器间歇鸣响
  134. *****************************/
  135. /*
  136. void Buzzer_second()
  137. {
  138.         if(flashing && WARNING>0)        //计时周期1s        
  139.         {
  140.                 WARNING--;                                //蜂鸣器间歇鸣次数变量自-1
  141.                 AUXR |= 0x10;                        //定时器2开,蜂鸣器响一下
  142.         }
  143. }*/
  144. /*-------------------------------------------
  145.   定时器2中断服务程序  200微秒 驱动无源蜂鸣器
  146. --------------------------------------------*/
  147. void timer2() interrupt 12
  148. {
  149.         static uint i=0;                        //中断计数变量
  150.         i++;                                                        //中断计数变量count3自+1
  151.         FENG=~FENG;                                        //蜂鸣器端口取反
  152.         if(i>=500)                                        //0.1秒时间到500
  153.         {
  154.                 i=0;                                                //计数清0
  155.                 FENG=1;                                        //蜂鸣器端口清0
  156.                 AUXR &= 0xef;                        //定时器2关闭
  157.         }
  158. }

  159. void  time0_int(void) interrupt 1 //定时器中断0
  160. {
  161.         static int count=0;
  162.         if(++count>=20)
  163.         {
  164.                 count=0;
  165.                 flashing=~flashing;
  166.         }
  167.         if(num>0)num--;
  168.         if(num1>0)num1--;
  169. //加入报警时长代码
  170. }

  171. void write_com(uchar com)//1602液晶屏写指令程序
  172. {
  173.         LCD_EN=0;        //初始设置LCD_EN低电平
  174.         LCD_RS=0;        //允许写指令
  175.         P0=com;                //传递指令
  176.         Delay1ms();        //延时1ms
  177.         LCD_EN=1;        //使能写入
  178.         Delay1ms();        //延时1ms
  179.         LCD_EN=0;        //低跳变执行
  180. }

  181. void write_date(uchar date)//1602液晶屏写数据程序
  182. {
  183. //        LCD_EN=0;        //初始设置LCD_EN低电平
  184.         LCD_RS=1;        //允许写数据
  185.         P0 =date;        //传递数据
  186.         Delay1ms();        //延时1ms
  187.         LCD_EN=1;        //使能写入
  188.         Delay1ms();        //延时1ms
  189.         LCD_EN=0;        //低跳变执行
  190. }

  191. void LCD_init()//1602液晶屏初始化程序
  192. {
  193.         uchar i;
  194.         LCD_EN=0;                 //初始设置LCD_EN低电平
  195.         write_com(0x38);//设置16*2显示,5*7点阵,8位数据接口
  196.         write_com(0x01);//显示清零,数据指针清零
  197. //        write_com(0x0f);//设置开显示,显示光标,光标闪烁
  198. //        write_com(0x0e);//设置开显示,显示光标,光标不闪
  199.         write_com(0x0c);//设置开显示,不显光标
  200.         write_com(0x06);//设置写一个字符后地址指针加1
  201. //        write_com(0x07);//设置写一个字符后整屏左移

  202.         write_com(0x80+1);//显示固定字符
  203.         for(i=0;i<13;i++)
  204.                 write_date(table[i]);
  205.         write_com(0xc0);
  206.         for(i=0;i<16;i++)
  207.                 write_date(table1[i]);
  208. }
  209. /*-----------------------------------------------------------------------------
  210.   InitADC 初始化ADC
  211. -----------------------------------------------------------------------------*/
  212. void ADC_Init()
  213. {
  214.         P1ASF=0x01;                                                //设置P1的0通道端口作为模拟输入
  215.         ADC_RES=0;                                                //清除ADC_RES存储器以前的结果
  216. //        ADC_RESL=0;
  217.         ADC_CONTR=ADC_POWER|ADC_SPEEDLL;//ADC 开启电源、转换速度 1000 0000
  218.         Delay1ms();                                                //上电延时1ms                                                                                       
  219. }
  220. /*----------------------------------------------------------------------------
  221. Get ADC Result(获取ADC结果)
  222. ----------------------------------------------------------------------------*/
  223. uchar Read(uchar CHA)                                //获取ADC结果
  224. {
  225.         ADC_CONTR=ADC_POWER|ADC_SPEEDLL|CHA|ADC_START;//启动转换1000 1000
  226.     _nop_();                        //延时确保正确读到ADC_CONTR寄存器的值
  227.     _nop_();
  228.     _nop_();
  229.     _nop_();
  230.         while(!(ADC_CONTR & ADC_FLAG));        //等待ADC转换完成标志置位 1001 1000
  231.         ADC_CONTR &=~ADC_FLAG;                        //关闭ADC
  232. //        return (ADC_RES<<2)|ADC_RESL;        //返回10位ADC结果
  233.         return ADC_RES;        //返回8位ADC结果
  234. }

  235. void key_scan()//按键扫描
  236. {
  237.         static uint time=0;
  238.         if(!Key1||!Key2)
  239.         {
  240.                 time++;
  241.                 if(time>key_L)//长按有效
  242.                         time=key_I;//连+/-间隔

  243.                 if(time==key_S)//短按消抖
  244.                 {
  245.                         if(!Key1)
  246.                         {
  247.                                 Rev_Stop=~Rev_Stop;
  248.                                 if(Rev_Stop) num1=100;
  249.                                 PH=0;
  250.                                 AUXR |= 0x10;//蜂鸣器提示音"滴"
  251.                         }
  252.                         if(!Key2)
  253.                         {
  254.                                 KeySec++;
  255.                                 if(KeySec>3) KeySec=0;
  256.                                 AUXR |= 0x10;//蜂鸣器提示音"滴"
  257.                         }
  258.                 }
  259.                 if(time==key_S||time==key_L)//短按消抖或长按连+/-
  260.                 {
  261.                         if(!Key3 && KeySec>1)
  262.                         {
  263.                                 preset=1;
  264.                                 switch(KeySec)
  265.                                 {
  266.                                         case 1: if(TheH<255)TheH++; break;
  267.                                         case 2: if(TheL<TheH-1)TheL++; break;
  268.                                 }
  269.                                 AUXR |= 0x10;//蜂鸣器提示音"滴"
  270.                                 num=100;//自复位变量赋值(5秒)
  271.                         }
  272.                         if(!Key4 && KeySec>1)
  273.                         {
  274.                                 preset=1;
  275.                                 switch(KeySec)
  276.                                 {
  277.                                         case 1: if(TheH>TheL+1)TheH--; break;
  278.                                         case 2: if(TheL>0)TheL--; break;
  279.                                 }
  280.                                 AUXR |= 0x10;//蜂鸣器提示音"滴"
  281.                                 num=100;//自复位变量赋值(5秒)
  282.                         }
  283.                 }
  284.         }
  285.         else time=0;
  286. }
  287. void detection()
  288. {
  289.         uchar Pt;
  290.         if(Rev_Stop)
  291.         {               
  292.                 Pt=Read(0);
  293. //                ADCP=Pt + - * / ;//按实际要求换算PH值
  294. //                if(PH<ADCP)//保留最大值
  295. //                        PH=ADCP;

  296.                 dis_buf[0]=Pt/100%10+'0';
  297.                 dis_buf[1]=Pt/10%10+'0';
  298.                 dis_buf[2]=Pt%10+'0';
  299. //                dis_buf[3]='H';
  300.                 dis_buf[4]=TheH/100%10+'0';
  301.                 dis_buf[5]=TheH/10%10+'0';
  302.                 dis_buf[6]=TheH%10+'0';
  303. //                dis_buf[7]='L';
  304.                 dis_buf[8]=TheL/100%10+'0';
  305.                 dis_buf[9]=TheL/10%10+'0';
  306.                 dis_buf[10]=TheL%10+'0';
  307.         }
  308. /*        else //清空缓存
  309.         {
  310.                 dis_buf[0]=' ';
  311.                 dis_buf[1]=' ';
  312.                 dis_buf[2]=' ';        
  313.                 dis_buf[3]=' ';
  314.                 dis_buf[4]=' ';
  315.                 dis_buf[5]=' ';        

  316.         }*/
  317. }
  318. /*-------------------------------
  319.   1ms延时子程序(11.0592MHz 1T)
  320. -------------------------------*/
  321. void Delay1ms()                //@11.0592MHz
  322. {
  323.         unsigned char i, j;
  324.         _nop_();
  325.         _nop_();
  326.         _nop_();
  327.         i = 11;
  328.         j = 190;
  329.         do
  330.         {
  331.                 while (--j);
  332.         } while (--i);
  333. }

  334. /*----------------------------
  335.         关闭IAP功能
  336. ----------------------------*/
  337. void IapIdle()
  338. {
  339.     IAP_CONTR = 0;                  //关闭IAP功能
  340.     IAP_CMD = 0;                    //清除命令寄存器
  341.     IAP_TRIG = 0;                   //清除触发寄存器
  342.     IAP_ADDRH = 0x80;               //将地址设置到非IAP区域
  343.     IAP_ADDRL = 0;
  344. }
  345. /*----------------------------
  346. 从ISP/IAP/EEPROM区域读取一字节
  347. ----------------------------*/
  348. uchar IapReadByte(uint addr)
  349. {
  350.     uchar dat;                      //数据缓冲区
  351.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  352.     IAP_CMD = CMD_READ;             //设置IAP命令
  353.     IAP_ADDRL = addr;               //设置IAP低地址
  354.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  355.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  356.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  357.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  358.     dat = IAP_DATA;                 //读ISP/IAP/EEPROM数据
  359.     IapIdle();                      //关闭IAP功能
  360.     return dat;                     //返回
  361. }
  362. /*-------------------------------
  363. 写一字节数据到ISP/IAP/EEPROM区域
  364. --------------------------------*/
  365. void IapProgramByte(uint addr, uchar dat)
  366. {
  367.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  368.     IAP_CMD = CMD_PROGRAM;          //设置IAP命令
  369.     IAP_ADDRL = addr;               //设置IAP低地址
  370.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  371.     IAP_DATA = dat;                 //写ISP/IAP/EEPROM数据
  372.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  373.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  374.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  375.     IapIdle();                      //关闭IAP功能
  376. }
  377. /*----------------------------
  378. ISP/IAP/EEPROM扇区擦除
  379. ----------------------------*/
  380. void IapEraseSector(uint addr)
  381. {
  382.     IAP_CONTR = ENABLE_IAP;         //使能IAP
  383.     IAP_CMD = CMD_ERASE;            //设置IAP命令
  384.     IAP_ADDRL = addr;               //设置IAP低地址
  385.     IAP_ADDRH = addr >> 8;          //设置IAP高地址
  386.     IAP_TRIG = 0x5a;                //写触发命令(0x5a)
  387.     IAP_TRIG = 0xa5;                //写触发命令(0xa5)
  388.     _nop_();                        //等待ISP/IAP/EEPROM操作完成
  389.     IapIdle();                      //关闭IAP功能
  390. }
  391. void init_eeprom()
  392. {
  393.         TheH=IapReadByte(IAP_ADDRESS);
  394.         TheL=IapReadByte(IAP_ADDRESS+1);
  395.         if((TheL<1||TheL>=TheH)||(TheH>254||TheH<=TheL))//首次上电初始化数据
  396.         {
  397.                 TheL=20;
  398.                 TheH=80;
  399.                 IapEraseSector(IAP_ADDRESS);
  400.                 IapProgramByte(IAP_ADDRESS, TheH);
  401.                 IapProgramByte(IAP_ADDRESS+1, TheL);
  402.         }
  403. }
  404. void display()
  405. {
  406.         uchar i;
  407.         write_com(0x80+9);//显示第一行数字
  408.         for(i=0;i<3;i++)
  409.                 write_date(dis_buf[i]);
  410.         write_com(0xc0+8);//显示第二行数字
  411.         for(i=0;i<9;i++)
  412.                 write_date(dis_buf[i+3]);        
  413. }
  414. /*
  415. void alarm()
  416. {
  417.         if(PH<TheL)
  418.         {
  419.                 LED_R= 1; //红指示灯
  420.                 LED_G= 1; //绿色指示灯
  421.         }
  422.         if(PH>=TheL && PH<TheH)
  423.         {
  424.                 LED_R= 1; //红指示灯
  425.                 LED_G= 0; //绿色指示灯
  426.         }
  427.         if(PH>=TheH)
  428.         {
  429.                 LED_R= 0; //红指示灯
  430.                 LED_G= 1; //绿色指示灯
  431.         }
  432.         WARNING=25;
  433. }*/
复制代码


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:301191 发表于 2022-1-13 23:21 | 只看该作者
顶一下
回复

使用道具 举报

板凳
ID:262 发表于 2022-1-13 23:21 | 只看该作者
来看一下51hei论坛里面解决此问题的痛苦经历吧:
51hei搜索框输入"1602 方块"或者"1602 黑块"或者"1602 白块"或者"1602 格":

这个是io口设置问题,最终搞定了:http://www.51hei.com/bbs/dpj-199732-1.html
http://www.51hei.com/bbs/dpj-168643-1.html
http://www.51hei.com/bbs/dpj-208189-1.html
http://www.51hei.com/bbs/dpj-210690-1.html

既有可能是软件问题也有硬件问题
http://www.51hei.com/bbs/dpj-187378-1.html
http://www.51hei.com/bbs/dpj-160754-1.html
回复

使用道具 举报

地板
ID:999060 发表于 2022-1-13 23:53 | 只看该作者
heicad 发表于 2022-1-13 23:21
来看一下51hei论坛里面解决此问题的痛苦经历吧:
51hei搜索框输入"1602 方块"或者"1602 黑块"或者"1602 白 ...

好的我看看谢谢
回复

使用道具 举报

5#
ID:35873 发表于 2022-1-14 02:05 | 只看该作者
伙计 你程序里没有1602的读写控制操作 如何显示  这是什么1602   R/W读写控制应该还是有的吧
回复

使用道具 举报

6#
ID:857072 发表于 2022-1-14 11:04 来自手机 | 只看该作者
应该是只写不读所以,r/w直接给了电平,调一下R?的值看是不是你的屏和电路上的对比度设置的参考值不一样。
回复

使用道具 举报

7#
ID:945127 发表于 2022-1-14 13:31 来自手机 | 只看该作者
1602的3脚的其中一个电阻变为可变电阻,再调一下就有字出来了
回复

使用道具 举报

8#
ID:517466 发表于 2022-1-14 18:49 | 只看该作者
LCD1602的读写有时序问题,注意你的MCU的晶振频率,以及读写LCD1602的时序。时序不对(脉冲高低电平的持续时间,及指令、数据发出后的中间停顿时间),会导致指令、数据不能被正常传递给1602,造成不显示。
回复

使用道具 举报

9#
ID:230742 发表于 2022-1-14 23:55 | 只看该作者
P0口要接上拉电阻吧。 89C52是要接上拉的,要不1602不会亮,STC15F2K的我没试过。
回复

使用道具 举报

10#
ID:453974 发表于 2022-1-18 20:46 | 只看该作者
实物的话,建议你换个液晶屏试一试,看是不是屏幕坏了
回复

使用道具 举报

11#
ID:956918 发表于 2022-1-18 23:09 | 只看该作者
可以搜搜1602的对比度,这个也是很重要的
回复

使用道具 举报

12#
ID:924572 发表于 2022-2-18 20:56 | 只看该作者
请问1602 有3.3V供电 和5V供电 有什么办法分辨吗?
回复

使用道具 举报

13#
ID:255377 发表于 2022-2-19 00:08 来自手机 | 只看该作者
第1连接的线路检查  第2 1602初始化延时按照技术规格书搞  第3写1602和读1602数据的时序不断调整
回复

使用道具 举报

14#
ID:254046 发表于 2022-2-19 21:03 | 只看该作者
读写时序不对,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表