[Cortex-M0技术交流] [求助]关于LCD1602的问题

[复制链接]
 楼主| chinacn1989 发表于 2014-6-3 19:54 | 显示全部楼层 |阅读模式
本帖最后由 chinacn1989 于 2014-6-3 20:09 编辑

用的芯片是NUC120的片子(就是以前HOT大叔的开发板),用来驱动1602,看电平状态貌似都正常,时序也反复对应了的。就是没任何反应!

接口对应关系 :
PC7-1602EN
PC6-1602RW
PC15-RS
宏定义1602.h:
  1. #define LCD1602_RS        GPIOC->DOUT.DOUT15
  2. #define LCD1602_RW        GPIOC->DOUT.DOUT6
  3. #define LCD1602_EN        GPIOC->DOUT.DOUT7


  4. #define LCD1602_W(x)        (GPIOA->u32DOUT        &= (x<<2) | 0XFFFFFC03)
  5. #define LCD1602_R                        ((GPIOA->u32PIN>>2) & 0xff)


  6. void        Lcd1602Init(void);
  7. void Lcd1602DisChar(uint8_t row,uint8_t line,uint8_t data);
1602.c文件
  1. #include"lcd1602.h"
  2. #include"drvsys.h"
  3. #include"init.h"
  4. void delay(int8_t i)
  5.         {
  6.         while(i--);
  7.         }
  8. uint8_t Lcd1602Busy(void)
  9.         {
  10.         uint8_t                Busy;
  11.         LCD1602_RS                = 0;
  12.         LCD1602_RW                = 1;
  13.         delay(2);
  14.         LCD1602_EN                = 1;
  15.         delay(8);
  16.         LCD1602_EN                = 0;
  17.         delay(1);
  18.         Busy        = LCD1602_R;

  19.         if(Busy & 0x80)
  20.                 return 1;
  21.         else
  22.                 return 0;               
  23.         }
  24. void Lcd1602WriteCmd(uint8_t        cmd)
  25.         {
  26.         LCD1602_RS                = 0;                                //Ö¸Áî
  27.         LCD1602_RW                = 0;                                //дÈë
  28.         LCD1602_W(cmd);
  29.         delay(2);
  30.         LCD1602_EN                = 1;                                //1602ʹÄÜ
  31.         delay(8);
  32.         LCD1602_EN                = 0;
  33.         delay(2);
  34.         }
  35. void Lcd1602WriteData(uint8_t        cmd)
  36.         {
  37.         LCD1602_RS                = 1;                                //дÊý¾Ý
  38.         LCD1602_RW                = 0;                                //дÈë
  39.         LCD1602_W(cmd);
  40.         delay(2);
  41.         LCD1602_EN                = 1;                                //1602ʹÄÜ
  42.         delay(6);
  43.         LCD1602_EN                = 0;
  44.         delay(2);
  45.         }
  46. void        Lcd1602Init()
  47.         {
  48.         Lcd1602WriteCmd(0x38);
  49.         Delay10ms(1);
  50.         Lcd1602WriteCmd(0x38);
  51.         Delay10ms(1);
  52.         Lcd1602WriteCmd(0x38);
  53.         Delay10ms(1);
  54.         
  55.         Lcd1602WriteCmd(0x38);
  56.         while(Lcd1602Busy());
  57.         
  58.         Lcd1602WriteCmd(0x08);
  59.         while(Lcd1602Busy());
  60.         
  61.         Lcd1602WriteCmd(0x01);
  62.         while(Lcd1602Busy());
  63.                
  64.         Lcd1602WriteCmd(0x06);
  65.         while(Lcd1602Busy())
  66.                
  67.         Lcd1602WriteCmd(0x0c);
  68.         while(Lcd1602Busy());
  69.         }
  70. void Lcd1602DisChar(uint8_t row,uint8_t line,uint8_t data)
  71.         {
  72.         uint8_t addr;
  73.         addr                = 0x80+(row-1)*0x40+line;
  74.         
  75.         Lcd1602WriteCmd(addr);
  76.         while(Lcd1602Busy())
  77.                 DrvSYS_Delay(100);
  78.                
  79.         Lcd1602WriteData(data);
  80.         while(Lcd1602Busy())
  81.                 DrvSYS_Delay(100);
  82.                
  83.         }

最开始的时候没有加delay延时,都是用检测忙的命令。但是去百度了下,发现延时的比较多。然后就加了一些延时!!
程序有什么需要优化建议希望大家多喷哈!
谢谢...


PS:
关于1602的时序相关资料
LCD1602的读写时序
       LCD1602字符点阵液晶现在已经很常用了。自己学习LCD1602中遇到了很多的问题,但是最主要的还是对1602写命令字,写数据,以及读状态时的时序控制不理解。看看了开发板自带的示例程序,人家写的程序烧到片子里就能运行,而自己写的就不行。很是纳闷啊,仔细研究了他们写的源程序,发现还是自己时序控制的不对。把他们写的程序拿出来和1602的时序操作顺序图一对照,才发现人家看似毫无章法的延时其实都是严格按照1602的时序来写的。
       所谓1602指的是现实的内容位16*2,即可以显示两行,每行两个字符。目前市面上的液晶大部分都是基于HD44780控制器的。又14或者16个引脚。HD44780内置了DDRAM(80字节),CGRAM(64字节,用来存放用户自定义字符,每个字符需要用到8个字节,所以以一共可以存放8个用户自定义字符),CGROM(内存了160个字符,包括了标准的ASCII码表上的字符和一些日文假名什么的)。
写操作时序:

读操作时序:


时序操作参数:


       图上第一条竖线画面在了RS和R/W上,也就是说首先应该从这里开始,即先将RS设为高或低(高表示数据读或写,低表示指令读或写),而R/W的高低代表是读还是写,上一张图是写时序图,所时是低的。
       接着就是先把使能信号E置底,然后可以延时一小会儿(自己买的开发板自带的示例程序上都带有延时,可是根据操作时序图上面画出来的时序,这个地方根本不需要延时的,不过延时也不会出错,就把它理解成为是数据线上电平的变化也是需要时间的);
       然后数据线上送数据,从上图的写操作时序图上可以看出,数据线上送完数据后需要延时tsp2(称之为数据建立时间)的时间后才能把E拉高,注意Tsp2的最小时间要求是40ns,最大时间没有要求;
      接下来一步就是把E置高电平,并且至少保持Tpw(E脉冲宽度)的时间(150ns,也是很小的);
      延时完成后再把E置为低电平就可以把数据写入1602了。最后不需要延时就行。
      最后还有一点需要注意的问题就是,时序操作参数表中的各参数的单位都是ns,时间是很短的,而对于51系列单片机如果晶振采用12MHz的话,每个机器周期就有1us,大大超过了参数要求的延时时间,所以有时候就算没有严格按照时序来编写程序,还是能够驱动1602,。但是如果对于那些采用高晶振的高性能单片机来说就不行了。所以最好还是按照时序一步一步来操作,这样才是万无一失的。
     下面是对LCD1602进行操作的时候常用到的几个函数:
  1. bit lcd_busy()                               //忙检测函数
  2. {
  3. bit result;
  4. RS=0;
  5. RW=1;
  6. EN=0;
  7. _nop_();
  8. EN=1;
  9. _nop_();                                  //按照技术手册上的说明此处只需要延时150ns以上即可,但是经过proteus仿真反复验
  10. _nop_();                                 //延 时至少四个机器周期,为什么呢?

  11. _nop_();
  12. _nop_();
  13. result=(bit)(P0&0x80);
  14. _nop_();
  15. EN=0;
  16. return result;
  17. }
  18. 写命令函数:
  19. void lcd_wcmd(unsigned char cmd)
  20. {
  21. while(lcd_busy());
  22. RS=0;
  23. RW=0;
  24. EN=0;
  25. P0=cmd;
  26. _nop_();                                       //此处至少延时1个周期,最好也延时两到四个周期

  27. EN=1;                                       //此处延时至少四个周期
  28. _nop_();
  29. _nop_();
  30. _nop_();
  31. _nop_();
  32. EN=0;
  33. }
  34. 写数据函数:
  35. void lcd_wdat(unsigned char dat)
  36. {
  37. while(lcd_busy());
  38. RS=1;
  39. RW=0;
  40. EN=0;
  41. P0=dat;
  42. _nop_();                                   //此处至少延时1个周期,最好也延时两到四个周期

  43. EN=1;
  44. _nop_();                                  //此处至少延时四个周期
  45. _nop_();
  46. _nop_();
  47.     _nop_();
  48. EN=0;
  49. }






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| chinacn1989 发表于 2014-6-3 19:58 | 显示全部楼层
板凳拿到手!
时序我对了几次,没发现什么问题啊....
关于电平我已经把大叔nuc120的开发板修改成5V供电的,所以不会是3.3V电压的影响!
 楼主| chinacn1989 发表于 2014-6-4 13:02 | 显示全部楼层
问题已解决...
结果发现是我的IO控制没有写好,就是我的lcd1602.H文件有点问题
修改后的为:
lcd1602.h
  1. #define LCD1602_RS        GPIOC->DOUT.DOUT15
  2. #define LCD1602_RW        GPIOC->DOUT.DOUT6
  3. #define LCD1602_EN        GPIOC->DOUT.DOUT7

  4. #define        RXDATA_EN                (GPIOA->u32PMD        &= 0xFFF0000F        )                //
  5. #define        TXDATA_EN                (GPIOA->u32PMD         = 0x55550 | (GPIOA->u32PMD&0xFFF0000F))

  6. #define LCD1602_W(x)        (GPIOA->u32DOUT        = (x<<2) | (GPIOA->u32DOUT&0XFFFFFC03))
  7. #define LCD1602_R                        ((GPIOA->u32PIN>>2) & 0xff)

  8. void        Lcd1602Init(void);
  9. void Lcd1602DisChar(uint8_t row,uint8_t line,uint8_t data);
这只是其中一个问题,还有一个问题就是单片机有个IO出问题了,不能拉低。仿真是低电平。但是用万用表去看却是高电平!!所以我写的数据完全就是超出范围了。然后我都是直接把其中一个数据引脚直接GND。然后显示了一个字符。至少显示成功了!!
themahsu 发表于 2014-10-28 11:41 | 显示全部楼层
請問:目前程式,資料位元是8位元,為了節省連接線與連接阜,如何改成4位元模式呢?
非常謝謝。
 楼主| chinacn1989 发表于 2014-10-28 15:45 来自手机 | 显示全部楼层
用一个串口转并口的芯片就行了!
74系列的
595可以
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:努力奋斗,努力学! 努力学习,努力帖! 学=学习;帖=发帖! 学习好了,就发帖和大家分享! 共同学习...

6

主题

272

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部