找回密码
 立即注册

QQ登录

只需一步,快速开始

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

STM8L驱动LCD1602液晶屏

[复制链接]
跳转到指定楼层
楼主
ID:145459 发表于 2016-11-1 00:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
由于上次诺基亚5110的液晶屏接触不良,所以没办法用在我要做的自平衡小车上面.我主要是想用液晶屏显示PID参数,用两个按键设置PID,方便平衡小车的调试.
我手中只剩下LCD1602这款液晶屏了,虽然一直很嫌弃它(驱动IO多,显示字符少)但也没办法.
本文使用四线驱动LCD1602的方法,主要是八线驱动太占用IO口.关于四线驱动,网上有很多例程可以参考,我也是参考网上的程序写的.但在编写LCD1602驱动程序时,还是经历了很多困难,时序问题就不提了.网上的很多程序都是没有判断忙标志位的,直接通过延时来实现.这样,延时时间多少合适成为一个问题,我改了好多次延时,但发现延时时间都比较长,写入一次数据的时间很长.这样的液晶屏用着很闹心,刷新一次时间那么,我的程序还有很多对时间要求比较苛刻的任务要执行呢,这样的速度可不行.
关于四线驱动如何去判断忙标志位,我也不懂,只好去网上搜,很少有这方面的例程,但最后还是找到了一个,照着写,总算解决了.

上图是单片机与LCD1602的接线图,DB0~DB7为8条并行数据线.VL是调节液晶屏的对比度的,外接一个电位器到地,如果显示不清晰,可以通过此电位器调节值最佳对比度.BLK,BLA接液晶背光.
除了8个数据线,和显示控制有关的还有RS,RW,E三个端口,上图是他们对应的功能.

通过向LCD1602写入命令和数据来控制显示.读状态是为了判断LCD1602此时是否处于忙的状态,如果忙,就只能等待不忙的时候再进行写操作.通过读状态时序,读到一个八位数据,最高位是忙标志位,此位为1说明此时忙,为了表示空闲.
大概没什么要讲的了,LCD1602的一些设置指令比较重要,手上也没找到详细的配置说明.


下图是LCD1602驱动芯片的显存,向对应的显存地址写入数据,就可以控制显示字符.由于LCD1602自带了一个ASCII码字库,所以一些常用的字符都可以直接显示,不需要自己去用软件生成字库了.


四线驱动时,写入的是0x28,八线驱动是写入的是0x38,如上图.

四线驱动的写命令写数据时序可以参考下面的例程.
本例程,使用STM8L的PB口驱动LCD1602,正好用完PB口的八个IO.高四位是数据接口,写入一字节数据时,先写高四位,再写第四位.

  1. /*硬件连接*/

  2. //    PB0     -->      RS

  3. //    PB1     -->      RW

  4. //    PB2     -->      E

  5. //    PB3     -->      A(背光正极)

  6. //    PB4     -->      D4

  7. //    PB5     -->      D5

  8. //    PB6     -->      D6

  9. //    PB7     -->      D7

  10. //    PD6     -->      按键+

  11. //    PD7     -->      按键-



  12. #define   RS_H       PB_ODR_ODR0=1

  13. #define   RS_L       PB_ODR_ODR0=0


  14. #define   RW_H       PB_ODR_ODR1=1

  15. #define   RW_L       PB_ODR_ODR1=0


  16. #define   EN_H       PB_ODR_ODR2=1

  17. #define   EN_L       PB_ODR_ODR2=0


  18. /****************************************************************************************

  19. *开发环境:IAR for stm8 v6.5.3

  20. *硬件平台:STM8L-DISCOVERY

  21. *功能说明:LCD1602四线驱动控制,检测忙标志位    第一行显示一串字符,第二行显示一个可以用按键改变大小的三位数字

  22. *作    者:茗风

  23. ****************************************************************************************/

  24. #include"iostm8l152c6.h"

  25. #include"stdbool.h"

  26. #include"stdint.h"

  27. const uint8_t Num_to_Char[10]="0123456789";


  28. /******************************************************************************************************

  29. *  名    称:void delay_100us(uint8_t x_us)

  30. *  功    能:延时100us

  31. *  入口参数:无

  32. *  出口参数:无

  33. *  说    明:

  34. *  范    例:无

  35. ******************************************************************************************************/

  36. void delay_100us(uint16_t x_us)

  37. {

  38.   uint8_t j;

  39.   while(x_us--)

  40.   {

  41.     for(j=0;j<33;j++);//2*40个指令周期

  42.   }

  43.   //delay_10ms共消耗 x_ms*2*255+2*x_ms个指令周期  

  44.   //*2*40+2*x_ms=80us+

  45.   //16M/8/2=1M 一个指令周期为1us

  46. }

  47. ///******************************************************************** **********************************

  48. //*  功  能   :LCD1602端口初始化函数

  49. //*  入口参数 :无

  50. //*  出口参数 :无

  51. //*  说  明   :对LCD1602用的IO端口进行初始化

  52. //*  范  例   :无

  53. //******************************************************************************************************/

  54. void LCD1602_GPIO_Init(void)

  55. {

  56.    

  57.   PB_DDR =0xFF;//PB设置为输出

  58.   PB_CR1 =0xFF;//PB设置为推挽输出

  59.   PB_CR2 =0xFF;//PB的IO输出速率为10MHz

  60.   PB_ODR =0x00;//PB输出高电平

  61.   PB_ODR |=0x08;

  62. }

  63. ///******************************************************************************************************

  64. //* 功    能        :LCD1602忙检测,若不忙则退出,忙则等待

  65. //* 入口参数        :无

  66. //* 出口参数        :无

  67. //* 说    明        :

  68. //* 编写日期  :2016年10月21日

  69. //* 作    者  :茗风

  70. //******************************************************************************************************/

  71. void LCD1602_Busy_Check(void)

  72. {

  73.   PB_CR1 &=0x7F;//浮空输入

  74.   PB_CR2 &=0x7F;//无中断能力

  75.   PB_DDR &=0x7F;

  76.   PB_ODR |=0x80;

  77.   RS_L;

  78.   RW_H;

  79.   EN_H;

  80.   while(PB_IDR&0x80);

  81.   PB_DDR |=0x80;//PB设置为输出

  82.   PB_CR1 |=0x80;//PB设置为推挽输出

  83.   PB_CR2 |=0x80;//PB的IO输出速率为10MHz

  84.   EN_L;

  85. }

  86. ///******************************************************************************************************

  87. //* 功    能        :LCD1602写命令函数

  88. //* 入口参数        :d 写入的一字节命令

  89. //* 出口参数        :无

  90. //* 说    明        :

  91. //* 编写日期  :2016年10月21日

  92. //* 作    者  :茗风

  93. //******************************************************************************************************/

  94. void LCD1602_Write_One_Byte_Cmd(uint8_t d)

  95. {

  96.   LCD1602_Busy_Check();

  97.   

  98.   RW_L;//写

  99.   RS_L;//命令

  100.        

  101.   PB_ODR &=0x0F;//清高四位

  102.   PB_ODR |=(d&0xF0);

  103.   EN_H;//

  104.   asm("nop");//200ns延时

  105.   EN_L;

  106.   asm("nop");//200ns延时

  107.   

  108.   d<<=4;        //低四位移到到高四位

  109.   PB_ODR &=0x0F;//清高四位

  110.   PB_ODR |=(d&0xF0);

  111.   EN_H;

  112.   asm("nop");//200ns延时

  113.   EN_L;

  114.   asm("nop");//200ns延时

  115. }

  116. ///******************************************************************************************************

  117. //* 功    能        :LCD1602写数据函数

  118. //* 入口参数        :d 写入的一字节数据

  119. //* 出口参数        :无

  120. //* 说    明        :

  121. //* 编写日期  :2016年10月21日

  122. //* 作    者  :茗风

  123. //******************************************************************************************************/

  124. void LCD1602_Write_One_Byte_Data(char d)

  125. {

  126.   LCD1602_Busy_Check();

  127.   RS_H;//数据

  128.   RW_L;//写

  129.   

  130.   PB_ODR &=0x0F;//清高四位

  131.   PB_ODR |=(d&0xF0);

  132.   EN_H;

  133.   asm("nop");

  134.   EN_L;

  135. //  asm("nop");

  136. //  delay_100us(1500);

  137.        

  138.   d<<=4;        //低四位移到到高四位

  139.   PB_ODR &=0x0F;//清高四位

  140.   PB_ODR |=(d&0xF0);

  141.   EN_H;

  142.   asm("nop");

  143.   EN_L;

  144.   asm("nop");

  145. //  delay_100us(1500);

  146. }

  147. ///******************************************************************************************************

  148. //* 功    能        :LCD1602一串字符函数

  149. //* 入口参数        :x  x轴坐标,取值范围(0~15)

  150. //*             y  y轴坐标,取值范围(0~1),一共两行

  151. //*             *s 一串字符

  152. //* 出口参数        :无

  153. //* 说    明        :

  154. //* 编写日期  :2016年10月21日

  155. //* 作    者  :茗风

  156. //******************************************************************************************************/

  157. uint8_t LCD1602_Display_String(uint8_t x,uint8_t y,uint8_t *s)

  158. {


  159.     if(y==1)

  160.     {

  161.       LCD1602_Write_One_Byte_Cmd(0xC0+x);//设置写入字符开始坐标  

  162.     }

  163.     else

  164.     {

  165.       LCD1602_Write_One_Byte_Cmd(0x80+x);//设置写入字符开始坐标  

  166.     }

  167.     while(*s != '\0')

  168.     {

  169.       LCD1602_Write_One_Byte_Data(*s++);

  170.     }

  171.     return 0;

  172. }

  173. ///******************************************************************************************************

  174. //* 功    能        :LCD1602显示两位数字

  175. //* 入口参数        :x  x轴坐标,取值范围(0~15)

  176. //*             y  y轴坐标,取值范围(0~1),一共两行

  177. //*             *s 一串字符

  178. //* 出口参数        :无

  179. //* 说    明        :

  180. //* 编写日期  :2016年10月22日

  181. //* 作    者  :茗风

  182. //******************************************************************************************************/

  183. void LCD1602_Display_Number(uint8_t x,uint8_t y,uint8_t number)

  184. {


  185.   if(y==1)

  186.   {

  187.     LCD1602_Write_One_Byte_Cmd(0xC0+x);//设置写入字符开始坐标  

  188.   }

  189.   else

  190.   {

  191.     LCD1602_Write_One_Byte_Cmd(0x80+x);//设置写入字符开始坐标  

  192.   }

  193.   if(number<10)

  194.   {

  195.      LCD1602_Write_One_Byte_Data(' ');

  196.      LCD1602_Write_One_Byte_Data(' ');

  197.      LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);

  198.   }

  199.   else if(number<100)

  200.   {

  201.      LCD1602_Write_One_Byte_Data(' ');

  202.      LCD1602_Write_One_Byte_Data(Num_to_Char[number/10]);

  203.      LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);

  204.   }

  205.   else

  206.   {

  207.      LCD1602_Write_One_Byte_Data(Num_to_Char[number/100]);

  208.      LCD1602_Write_One_Byte_Data(Num_to_Char[number%100/10]);

  209.      LCD1602_Write_One_Byte_Data(Num_to_Char[number%10]);

  210.   }

  211.   

  212. }

  213. ///******************************************************************************************************

  214. //* 功    能        :LCD1602初始化配置

  215. //* 入口参数        :无

  216. //* 出口参数        :无

  217. //* 说    明        :

  218. //* 编写日期  :2016年10月21日

  219. //* 作    者  :茗风

  220. //******************************************************************************************************/

  221. void LCD1602_init(void)

  222. {

  223.   LCD1602_GPIO_Init();

  224.   LCD1602_Write_One_Byte_Cmd(0x28);//四线驱动

  225.   LCD1602_Write_One_Byte_Cmd(0x01);//清屏

  226.         LCD1602_Write_One_Byte_Cmd(0x06);//这个是上面指令码是 000001NS的设

  227.   LCD1602_Write_One_Byte_Cmd(0x0C);//显示开及光标设置

  228. }

  229. ///******************************************************************************************************

  230. //* 功    能        :按键GPIO初始化配置

  231. //* 入口参数        :无

  232. //* 出口参数        :无

  233. //* 说    明        :

  234. //* 编写日期    :2016年10月21日

  235. //* 作    者    :茗风

  236. //******************************************************************************************************/

  237. void GPIO_Config(void)

  238. {

  239.   //PE7 LED控制引脚

  240.   PE_DDR_DDR7 =1;//输出

  241.   PE_CR1_C17 =1;//推挽输出

  242.   PE_CR2_C27 =1;//输出速率10M

  243.   

  244.   //配置阀门到位检测引脚PD6,PD7

  245.   PD_DDR_DDR6 =0;

  246.   PD_CR1_C16 =1;//带上拉电阻输入

  247.   PD_CR2_C26 =1;//使能外部中断

  248.   

  249.   PD_DDR_DDR7 =0;

  250.   PD_CR1_C17 =1;//带上拉电阻输入

  251.   PD_CR2_C27 =1;//使能外部中断

  252.   

  253.   EXTI_CR3_PDIS =2;//PD口上升沿中断

  254. /*00: Falling edge and low level

  255.   01: Rising edge only

  256.   10: Falling edge only

  257.   11: Rising and falling edge*/  

  258.   EXTI_CONF_PDHIS =1;//PD[7:4] are used for EXTID interrupt generation

  259.   

  260. //设置中断

  261. //CPU_CCR |=MASK_CPU_CCR_I1+MASK_CPU_CCR_I0;//启用硬件优先级,禁用软件优先级

  262. }

  263. uint8_t num=30;

  264. void main(void)

  265. {

  266.   GPIO_Config();

  267.   LCD1602_init();

  268.   LCD1602_Display_String(0,0,"nannan wo ai ni!");

  269.   LCD1602_Display_String(0,1,"NUM:");

  270.   asm("rim");               //enable interrupts

  271.   while(1)

  272.   {

  273.     LCD1602_Display_Number(4,1,num);

  274.     PE_ODR ^=0x80;

  275.     asm("wfi");

  276.     //delay_100us(10000);

  277.   }

  278. }


  279. #pragma vector=EXTID_vector

  280. __interrupt void EXTID_ISR(void)

  281. {

  282.   delay_100us(100);//10ms延时,暂时这么做

  283.   if(PD_IDR_IDR6==0)//加

  284.   {

  285.     if(num>256)

  286.       num=255;

  287.     else

  288.       num++;

  289.   }

  290.   else if(PD_IDR_IDR7==0)//减

  291.   {

  292.     if(num==0)

  293.       num=0;

  294.     else

  295.       num--;

  296.   }

  297.   EXTI_SR2_PDF =1;//They are cleared by writing a ‘1’ by software

  298. }
复制代码




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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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