找回密码
 立即注册

QQ登录

只需一步,快速开始

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

STM8L的LCD接口详解及驱动程序

[复制链接]
跳转到指定楼层
楼主
STM8L部分型号集成了段式液晶驱动器,可以驱动4*28=112个液晶段.段式液晶屏为低功耗显示器件,功耗根据屏的大小和显示段数会有所不同,通常功耗在10ua左右.生活中,数字电子表,数字万用表,数显温度计等,使用的都是段式液晶屏,通常一颗纽扣电池可以保证设备间隔不断显示数字两年或更久.


大家比较熟悉的液晶屏1602模块其实也是段式液晶,是一个有很多段的点组成的,由于点比较多,所以1602模块集成了驱动芯片,我们只需给1602送数据,就可以控制1602进行显示了.液晶本身不会发光,1602之所以会发光是因为使用了LED背光板.
段式液晶驱动器,通常会含有一个电压泵,一个频率分频器.电压泵用来提供驱动液晶段的电压,电压的高低决定着显示的清晰度,也就是决定着液晶的对比度.提供给LCD驱动器的频率决定着,刷新段式液晶的频率,如果提供给LCD的频率太低,会看到显示时的频闪.

从上图可以看到,除了分频器和电压泵部分,还有显存.所有液晶屏都会有显存,每个显存控制着对应的引脚,对于STM8L的八位显存,可以控制8个引脚和一个COM引脚,比如STM8L的RAM0控制着COM0对应的S0~S7引脚.
当我们需要驱动一块液晶屏时,首先要拿到这种液晶屏的引脚对应显示段的图纸.如下图,由于STM8L152C6的RAM0控制着COM0对应的S0~S7引脚,如果要显示下图的"元",那么我们只需要向RAM0写入数据0x01.
本例程的硬件平台仍然是ST官方的开发板STM8L-DISCOVERY.在ST官网的编号为UM0970这份文档中,有对开发板上液晶屏的介绍.

这份资料,并不是十分直观.找到显存对应的液晶屏上的段,对写程序来说很重要.

本例程,参考ST提供的例程,根据自己的理解,编写了LCD驱动程序,提供一个可以在液晶屏上最多显示六位数字的接口的程序,读者可以调用此程序,显示任意六位以内的数字.


  1. /****************************************************************************************

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

  3. *硬件平台:STM8L-DISCOVERY

  4. *功能说明:使用STM8L-DISCOVERY液晶屏显示一串6位数字

  5. *作    者:茗风

  6. ****************************************************************************************/

  7. #include"iostm8l152c6.h"

  8. #include"stdint.h"

  9. /*  =========================================================================

  10.                                  LCD MAPPING

  11.     =========================================================================

  12.             A

  13.      _  ----------

  14. COL |_| |\   |J  /|

  15.        F| H  |  K |B

  16.      _  |  \ | /  |

  17. COL |_| --G-- --M--

  18.         |   /| \  |

  19.        E|  Q |  N |C

  20.      _  | /  |P  \|   

  21. DP  |_| -----------  

  22.             D      

  23. */


  24. #define a 0x01

  25. #define b 0x02

  26. #define c 0x04

  27. #define d 0x08

  28. #define e 0x10

  29. #define f 0x20

  30. #define g 0x40

  31. #define m 0x80


  32. const uint8_t LCD_Tab[10] = {

  33.                 a + b + c + d + e + f,                        // Displays "0"

  34.                 b + c,                                        // Displays "1"

  35.                 a + b + m + g + e + d,                        // Displays "2"

  36.                 a + b + m + g + c + d,                        // Displays "3"

  37.                 f + g + m + b + c,                        // Displays "4"

  38.                 a + f + g + m + c +d,                        // Displays "5"

  39.                 a + f + e + d + c + g + m ,                // Displays "6"

  40.                 a + b + c,                                // Displays "7"

  41.                 a + b + c + d + e + f + g + m,                // Displays "8"

  42.                 a + b + c + d + f + g + m                // Displays "9"


  43. };


  44. /******************************************************************************************************

  45. *  名    称:void LCD_Config(void)

  46. *  功    能:配置DAC,禁用DMA,不使用TIM4触发,也不用软件触发,写入DHR的数据被立即送入DOR寄存器,

  47. *            立即输出对应电压

  48. *  入口参数:无

  49. *  出口参数:无

  50. *  说    明:STM8L152C6属于中等容量MCU,只有一路DAC输出,输出引脚为PF0

  51. *  范    例:无

  52. ******************************************************************************************************/

  53. void LCD_Config(void)

  54. {

  55. //------打开LCD/RTC时钟------

  56.   CLK_PCKENR2_PCKEN22=1;//打开RTC时钟,LCD刷新频率与此时钟有关

  57.   CLK_PCKENR2_PCKEN23=1;//打开LCD时钟,读写LCD寄存器用到此时钟

  58.   

  59. //---选择LSE作为RTC时钟---

  60.   CLK_CRTCR_RTCSEL0=0;

  61.   CLK_CRTCR_RTCSEL1=0;

  62.   CLK_CRTCR_RTCSEL2=0;

  63.   CLK_CRTCR_RTCSEL3=1;

  64. /* 0000: No clock selected

  65.    0001: HSI clock used as RTC clock source

  66.    0010: LSI clock used as RTC clock source

  67.    0100: HSE clock used as RTC clock source

  68.    1000: LSE clock used as RTC clock sourc*/

  69.   

  70. //----设置RTC时钟分频值----

  71.   CLK_CRTCR_RTCDIV0=0;

  72.   CLK_CRTCR_RTCDIV1=0;

  73.   CLK_CRTCR_RTCDIV2=0;

  74. /*000: RTC clock source/1

  75.   001: RTC clock source /2

  76.   010: RTC clock source /4

  77.   011: RTC clock source /8

  78.   100: RTC clock source /16

  79.   101: RTC clock source /32

  80.   110: RTC clock source /64

  81.   111: RTC clock source /128*/

  82.   

  83. //----设置LCD预分频值----  

  84.   LCD_FRQ_PS0=0;// 2^PS[3:0]

  85.   LCD_FRQ_PS1=0;//分频值为1

  86.   LCD_FRQ_PS2=0;

  87.   LCD_FRQ_PS3=0;

  88.   

  89. //----设置LCD分频值----  

  90.   LCD_FRQ_DIV0=1;//DIV[3:0]+16

  91.   LCD_FRQ_DIV1=1;//分频值为15+16=31

  92.   LCD_FRQ_DIV2=1;

  93.   LCD_FRQ_DIV3=1;  



  94. //以上分频值的设置,最为了得到适合的LCD的刷新频率,如果增大分频值,会导致

  95. //LCD刷新频率变低,会看到LCD显示出现闪烁

  96. //比如,我们将PS[3:0]设置为0011,会看到液晶闪烁  

  97.   

  98. //----1/4 duty----  

  99.   LCD_CR1_DUTY0=1;//1/4 duty

  100.   LCD_CR1_DUTY1=1;

  101. /* Duty ratio selection

  102.    00: Static duty

  103.    01: 1/2 duty

  104.    10: 1/3 duty

  105.    11: 1/4 duty      */


  106. //----1/3 bias----     

  107.   LCD_CR1_B2=0;//1/3 bias

  108. /* 0: 1/3 bias

  109.    1: 1/2 bias  */


  110. //----内部电压源----   

  111.   LCD_CR2_VSEL=0;

  112.   

  113. //----打开引脚的SEG功能----     

  114. // LCD_PM0=0xFF;//头文件这个地方定义错误,无法直接向LCD_PM0写入数据

  115. // LCD_PM1=0xFF;//PM0寄存器定义错误,导致PM1也无法直接写入

  116. // LCD_PM2=0xFF;//PM0寄存器定义错误,导致PM2也无法直接写入

  117.   *((uint8_t *)0x5404)=0xFF;//直接向LCD_PM0寄存器的地址写入数据

  118.   *((uint8_t *)0x5405)=0xFF;//直接向LCD_PM1寄存器的地址写入数据

  119.   *((uint8_t *)0x5406)=0xFF;//直接向LCD_PM2寄存器的地址写入数据

  120.   

  121. //----To set contrast to mean value----   

  122.   LCD_CR2_CC0=0;//对比度

  123.   LCD_CR2_CC1=1;

  124.   LCD_CR2_CC2=0;

  125. /*  000: VLCD0  2.6V

  126.     001: VLCD1  2.7V

  127.     010: VLCD2  2.8V

  128.     011: VLCD3  2.9V

  129.     100: VLCD4  3.0V

  130.     101: VLCD5  3.1V

  131.     110: VLCD6  3.2V

  132.     111: VLCD7    */

  133.        

  134. //----Dead time 0----        

  135.   LCD_CR3_DEAD0=0;//no dead time

  136.   LCD_CR3_DEAD1=0;  

  137.   LCD_CR3_DEAD2=0;

  138. //----LCD_PulseOnDuration_1----

  139.   LCD_CR2_PON0=1;

  140.   LCD_CR2_PON1=0;  

  141.   LCD_CR2_PON2=0;         

  142. /*  000: 0 CLKps pulses

  143.     001: 1 CLKps pulses

  144.     010: 2 CLKps pulses

  145.     011: 3 CLKps pulses

  146.     100: 4 CLKps pulses

  147.     101: 5 CLKps pulses

  148.     110: 6 CLKps pulses

  149.     111: 7 CLKps pulses  */

  150.        

  151. //----Enable LCD peripheral----       

  152.   LCD_CR3_LCDEN=1;

  153. }


  154. /******************************************************************************************************

  155. *  名          称:LCD_DisplayNum(uint8_t number)

  156. *  功            能:控制段式液晶屏的数字显示部分

  157. *  入口参数:number:要显示的数字

  158. *  出口参数:无

  159. *  说          明:根据数字的长度,判断要显示的长度,长度大于6位,只显示后六位

  160. *  范          例:无

  161. ******************************************************************************************************/

  162. void LCD_DisplayNum(uint32_t number)

  163. {

  164.   uint8_t cnts=0,tmp=0;

  165.   

  166.   if(number<10)cnts=1;

  167.   else if(number<100)cnts=2;

  168.   else if(number<1000)cnts=3;

  169.   else if(number<10000)cnts=4;

  170.   else if(number<100000)cnts=5;

  171.   else if(number<(uint32_t) 1000000)cnts=6;

  172.   else cnts=6;


  173.   //判断需要显示数字的长度,确定在LCD屏上需要的位数

  174.   switch(cnts)

  175.   {

  176.     case 6:

  177.            tmp = LCD_Tab[number%1000000/100000];

  178.            ((tmp&m)==0)?(LCD_RAM0&=~0x02):(LCD_RAM0 |=0x02) ;

  179.            ((tmp&e)==0)?(LCD_RAM0&=~0x01):(LCD_RAM0 |=0x01) ;

  180.            ((tmp&g)==0)?(LCD_RAM2&=~0x80):(LCD_RAM2 |=0x80) ;

  181.            ((tmp&b)==0)?(LCD_RAM2&=~0x40):(LCD_RAM2 |=0x40) ;

  182.            ((tmp&f)==0)?(LCD_RAM6&=~0x08):(LCD_RAM6 |=0x08) ;

  183.            ((tmp&a)==0)?(LCD_RAM6&=~0x04):(LCD_RAM6 |=0x04) ;

  184.            ((tmp&c)==0)?(LCD_RAM3&=~0x20):(LCD_RAM3 |=0x20) ;

  185.            ((tmp&d)==0)?(LCD_RAM3&=~0x10):(LCD_RAM3 |=0x10) ;                     

  186.     case 5:

  187.            tmp = LCD_Tab[number%100000/10000];

  188.            ((tmp&m)==0)?(LCD_RAM0&=~0x08):(LCD_RAM0 |=0x08) ;

  189.            ((tmp&e)==0)?(LCD_RAM0&=~0x04):(LCD_RAM0 |=0x04) ;

  190.            ((tmp&g)==0)?(LCD_RAM2&=~0x20):(LCD_RAM2 |=0x20) ;

  191.            ((tmp&b)==0)?(LCD_RAM2&=~0x10):(LCD_RAM2 |=0x10) ;

  192.            ((tmp&f)==0)?(LCD_RAM6&=~0x02):(LCD_RAM6 |=0x02) ;

  193.            ((tmp&a)==0)?(LCD_RAM6&=~0x01):(LCD_RAM6 |=0x01) ;

  194.            ((tmp&c)==0)?(LCD_RAM3&=~0x80):(LCD_RAM3 |=0x80) ;

  195.            ((tmp&d)==0)?(LCD_RAM3&=~0x40):(LCD_RAM3 |=0x40) ;           

  196.            

  197.     case 4:

  198.            tmp = LCD_Tab[number%10000/1000];


  199.            ((tmp&m)==0)?(LCD_RAM0&=~0x20):(LCD_RAM0 |=0x20) ;

  200.            ((tmp&e)==0)?(LCD_RAM0&=~0x10):(LCD_RAM0 |=0x10) ;

  201.            ((tmp&g)==0)?(LCD_RAM2&=~0x08):(LCD_RAM2 |=0x08) ;

  202.            ((tmp&b)==0)?(LCD_RAM2&=~0x04):(LCD_RAM2 |=0x04) ;

  203.            ((tmp&f)==0)?(LCD_RAM5&=~0x80):(LCD_RAM5 |=0x80) ;

  204.            ((tmp&a)==0)?(LCD_RAM5&=~0x40):(LCD_RAM5 |=0x40) ;

  205.            ((tmp&c)==0)?(LCD_RAM4&=~0x02):(LCD_RAM4 |=0x02) ;

  206.            ((tmp&d)==0)?(LCD_RAM4&=~0x01):(LCD_RAM4 |=0x01) ;           

  207.     case 3:

  208.            tmp = LCD_Tab[number%1000/100];

  209.            ((tmp&m)==0)?(LCD_RAM0&=~0x80):(LCD_RAM0 |=0x80) ;

  210.            ((tmp&e)==0)?(LCD_RAM0&=~0x40):(LCD_RAM0 |=0x40) ;

  211.            ((tmp&g)==0)?(LCD_RAM2&=~0x02):(LCD_RAM2 |=0x02) ;

  212.            ((tmp&b)==0)?(LCD_RAM2&=~0x01):(LCD_RAM2 |=0x01) ;

  213.            ((tmp&f)==0)?(LCD_RAM5&=~0x20):(LCD_RAM5 |=0x20) ;

  214.            ((tmp&a)==0)?(LCD_RAM5&=~0x10):(LCD_RAM5 |=0x10) ;

  215.            ((tmp&c)==0)?(LCD_RAM4&=~0x08):(LCD_RAM4 |=0x08) ;

  216.            ((tmp&d)==0)?(LCD_RAM4&=~0x04):(LCD_RAM4 |=0x04) ;


  217.    case 2:

  218.            tmp = LCD_Tab[number%100/10];

  219.            ((tmp&m)==0)?(LCD_RAM1&=~0x02):(LCD_RAM1 |=0x02) ;

  220.            ((tmp&e)==0)?(LCD_RAM1&=~0x01):(LCD_RAM1 |=0x01) ;

  221.            ((tmp&g)==0)?(LCD_RAM1&=~0x80):(LCD_RAM1 |=0x80) ;

  222.            ((tmp&b)==0)?(LCD_RAM1&=~0x40):(LCD_RAM1 |=0x40) ;

  223.            ((tmp&f)==0)?(LCD_RAM5&=~0x08):(LCD_RAM5 |=0x08) ;

  224.            ((tmp&a)==0)?(LCD_RAM5&=~0x04):(LCD_RAM5 |=0x04) ;

  225.            ((tmp&c)==0)?(LCD_RAM4&=~0x20):(LCD_RAM4 |=0x20) ;

  226.            ((tmp&d)==0)?(LCD_RAM4&=~0x10):(LCD_RAM4 |=0x10) ;


  227.    case 1:

  228.            tmp = LCD_Tab[number%10];

  229.            ((tmp&m)==0)?(LCD_RAM1&=~0x08):(LCD_RAM1 |=0x08) ;

  230.            ((tmp&e)==0)?(LCD_RAM1&=~0x04):(LCD_RAM1 |=0x04) ;

  231.            ((tmp&g)==0)?(LCD_RAM1&=~0x20):(LCD_RAM1 |=0x20) ;

  232.            ((tmp&b)==0)?(LCD_RAM1&=~0x10):(LCD_RAM1 |=0x10) ;

  233.            ((tmp&f)==0)?(LCD_RAM5&=~0x02):(LCD_RAM5 |=0x02) ;

  234.            ((tmp&a)==0)?(LCD_RAM5&=~0x01):(LCD_RAM5 |=0x01) ;

  235.            ((tmp&c)==0)?(LCD_RAM4&=~0x80):(LCD_RAM4 |=0x80) ;

  236.            ((tmp&d)==0)?(LCD_RAM4&=~0x40):(LCD_RAM4 |=0x40) ;

  237.     break;


  238.     default:break;

  239.   }

  240. }

  241. void main(void)

  242. {

  243.   LCD_Config();

  244.   LCD_DisplayNum(201609);

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

  246.   while(1)

  247.   {

  248.     asm("wfi");

  249.   }

  250. }
复制代码




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

使用道具 举报

来自 4#
ID:466148 发表于 2019-3-29 19:28 来自手机 | 只看该作者
大师,我用你的lcd程序和你的adc程序调试stm8ldiscouer套件时发现,stm8l152c 6t6的adc测电压时,电压从0伏调到2.99伏,lcd输出显示正常 ,电压从2.99到1伏正常,电压从1伏到0.99伏时,显示1.99伏,电压从1伏调到0伏,显示就从1伏到1.99到1.0,就可以要多显示1伏,而在电脑上的调试程序中显示的电压确是正常的,而单片机输入电压是用万用表和示波器看的,电压没有跳跃,不知道是那里的问题?感觉好像跟中断触发有关系。
回复

使用道具 举报

沙发
ID:276663 发表于 2018-4-24 17:23 | 只看该作者
谢谢分享,发现最难的就是对应显存。不知道有什么规则。
回复

使用道具 举报

板凳
ID:419511 发表于 2018-11-5 10:58 | 只看该作者
为什么我这里会报错
回复

使用道具 举报

5#
ID:164100 发表于 2019-12-20 13:32 | 只看该作者
本帖最后由 huang_hzl 于 2019-12-20 14:55 编辑


你好,我按你的LCD配置,依然无法点亮LCD,请问,是哪里的问题呢  ?
仿真时,可以看到LCD_RAM0~LCDRAM13,已经被写入了数据。
回复

使用道具 举报

6#
ID:679630 发表于 2020-1-13 16:03 | 只看该作者
huang_hzl 发表于 2019-12-20 13:32
你好,我按你的LCD配置,依然无法点亮LCD,请问,是哪里的问题呢  ?
仿真时,可以看到LCD_RAM0~LCDRAM13 ...

你好,我现在遇到跟你一样的问题,请问你的点亮了嘛
回复

使用道具 举报

7#
ID:679630 发表于 2020-1-13 18:36 | 只看该作者
huang_hzl 发表于 2019-12-20 13:32
你好,我按你的LCD配置,依然无法点亮LCD,请问,是哪里的问题呢  ?
仿真时,可以看到LCD_RAM0~LCDRAM13 ...

你好,我用的也是STM8L系列的LCD型芯片,遇到了跟你一样的问题,可以回复我或则加我qq为我解除一下疑惑嘛,非常感谢!
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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