zoukankan      html  css  js  c++  java
  • 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. //------打开LCD/RTC时钟------
    55.   CLK_PCKENR2_PCKEN22=1;//打开RTC时钟,LCD刷新频率与此时钟有关
    56.   CLK_PCKENR2_PCKEN23=1;//打开LCD时钟,读写LCD寄存器用到此时钟
    57.   
    58. //---选择LSE作为RTC时钟---
    59.   CLK_CRTCR_RTCSEL0=0;
    60.   CLK_CRTCR_RTCSEL1=0;
    61.   CLK_CRTCR_RTCSEL2=0;
    62.   CLK_CRTCR_RTCSEL3=1;
    63. /* 0000: No clock selected
    64.    0001: HSI clock used as RTC clock source
    65.    0010: LSI clock used as RTC clock source
    66.    0100: HSE clock used as RTC clock source
    67.    1000: LSE clock used as RTC clock sourc*/
    68.   
    69. //----设置RTC时钟分频值----
    70.   CLK_CRTCR_RTCDIV0=0;
    71.   CLK_CRTCR_RTCDIV1=0;
    72.   CLK_CRTCR_RTCDIV2=0;
    73. /*000: RTC clock source/1
    74.   001: RTC clock source /2
    75.   010: RTC clock source /4
    76.   011: RTC clock source /8
    77.   100: RTC clock source /16
    78.   101: RTC clock source /32
    79.   110: RTC clock source /64
    80.   111: RTC clock source /128*/
    81.   
    82. //----设置LCD预分频值----  
    83.   LCD_FRQ_PS0=0;// 2^PS[3:0]
    84.   LCD_FRQ_PS1=0;//分频值为1
    85.   LCD_FRQ_PS2=0;
    86.   LCD_FRQ_PS3=0;
    87.   
    88. //----设置LCD分频值----  
    89.   LCD_FRQ_DIV0=1;//DIV[3:0]+16
    90.   LCD_FRQ_DIV1=1;//分频值为15+16=31
    91.   LCD_FRQ_DIV2=1;
    92.   LCD_FRQ_DIV3=1;  
    93. //以上分频值的设置,最为了得到适合的LCD的刷新频率,如果增大分频值,会导致
    94. //LCD刷新频率变低,会看到LCD显示出现闪烁
    95. //比如,我们将PS[3:0]设置为0011,会看到液晶闪烁  
    96.   
    97. //----1/4 duty----  
    98.   LCD_CR1_DUTY0=1;//1/4 duty
    99.   LCD_CR1_DUTY1=1;
    100. /* Duty ratio selection
    101.    00: Static duty
    102.    01: 1/2 duty
    103.    10: 1/3 duty
    104.    11: 1/4 duty      */
    105. //----1/3 bias----     
    106.   LCD_CR1_B2=0;//1/3 bias
    107. /* 0: 1/3 bias
    108.    1: 1/2 bias  */
    109. //----内部电压源----   
    110.   LCD_CR2_VSEL=0;
    111.   
    112. //----打开引脚的SEG功能----     
    113. // LCD_PM0=0xFF;//头文件这个地方定义错误,无法直接向LCD_PM0写入数据
    114. // LCD_PM1=0xFF;//PM0寄存器定义错误,导致PM1也无法直接写入
    115. // LCD_PM2=0xFF;//PM0寄存器定义错误,导致PM2也无法直接写入
    116.   *((uint8_t *)0x5404)=0xFF;//直接向LCD_PM0寄存器的地址写入数据
    117.   *((uint8_t *)0x5405)=0xFF;//直接向LCD_PM1寄存器的地址写入数据
    118.   *((uint8_t *)0x5406)=0xFF;//直接向LCD_PM2寄存器的地址写入数据
    119.   
    120. //----To set contrast to mean value----   
    121.   LCD_CR2_CC0=0;//对比度
    122.   LCD_CR2_CC1=1;
    123.   LCD_CR2_CC2=0;
    124. /*  000: VLCD0  2.6V
    125.     001: VLCD1  2.7V
    126.     010: VLCD2  2.8V
    127.     011: VLCD3  2.9V
    128.     100: VLCD4  3.0V
    129.     101: VLCD5  3.1V
    130.     110: VLCD6  3.2V
    131.     111: VLCD7    */
    132.         
    133. //----Dead time 0----         
    134.   LCD_CR3_DEAD0=0;//no dead time
    135.   LCD_CR3_DEAD1=0;  
    136.   LCD_CR3_DEAD2=0;
    137. //----LCD_PulseOnDuration_1----
    138.   LCD_CR2_PON0=1; 
    139.   LCD_CR2_PON1=0;  
    140.   LCD_CR2_PON2=0;          
    141. /*  000: 0 CLKps pulses
    142.     001: 1 CLKps pulses
    143.     010: 2 CLKps pulses
    144.     011: 3 CLKps pulses
    145.     100: 4 CLKps pulses
    146.     101: 5 CLKps pulses
    147.     110: 6 CLKps pulses
    148.     111: 7 CLKps pulses  */
    149.         
    150. //----Enable LCD peripheral----        
    151.   LCD_CR3_LCDEN=1;
    152. }
    153. /******************************************************************************************************
    154. *  名          称:LCD_DisplayNum(uint8_t number)
    155. *  功            能:控制段式液晶屏的数字显示部分
    156. *  入口参数:number:要显示的数字
    157. *  出口参数:无
    158. *  说          明:根据数字的长度,判断要显示的长度,长度大于6位,只显示后六位
    159. *  范          例:无
    160. ******************************************************************************************************/
    161. void LCD_DisplayNum(uint32_t number)
    162. {
    163.   uint8_t cnts=0,tmp=0;
    164.   
    165.   if(number<10)cnts=1;
    166.   else if(number<100)cnts=2;
    167.   else if(number<1000)cnts=3;
    168.   else if(number<10000)cnts=4;
    169.   else if(number<100000)cnts=5;
    170.   else if(number<(uint32_t) 1000000)cnts=6;
    171.   else cnts=6;
    172.   //判断需要显示数字的长度,确定在LCD屏上需要的位数
    173.   switch(cnts)
    174.   {
    175.     case 6:
    176.            tmp = LCD_Tab[number%1000000/100000];
    177.            ((tmp&m)==0)?(LCD_RAM0&=~0x02):(LCD_RAM0 |=0x02) ;
    178.            ((tmp&e)==0)?(LCD_RAM0&=~0x01):(LCD_RAM0 |=0x01) ;
    179.            ((tmp&g)==0)?(LCD_RAM2&=~0x80):(LCD_RAM2 |=0x80) ;
    180.            ((tmp&b)==0)?(LCD_RAM2&=~0x40):(LCD_RAM2 |=0x40) ;
    181.            ((tmp&f)==0)?(LCD_RAM6&=~0x08):(LCD_RAM6 |=0x08) ;
    182.            ((tmp&a)==0)?(LCD_RAM6&=~0x04):(LCD_RAM6 |=0x04) ;
    183.            ((tmp&c)==0)?(LCD_RAM3&=~0x20):(LCD_RAM3 |=0x20) ;
    184.            ((tmp&d)==0)?(LCD_RAM3&=~0x10):(LCD_RAM3 |=0x10) ;                      
    185.     case 5:
    186.            tmp = LCD_Tab[number%100000/10000];
    187.            ((tmp&m)==0)?(LCD_RAM0&=~0x08):(LCD_RAM0 |=0x08) ;
    188.            ((tmp&e)==0)?(LCD_RAM0&=~0x04):(LCD_RAM0 |=0x04) ;
    189.            ((tmp&g)==0)?(LCD_RAM2&=~0x20):(LCD_RAM2 |=0x20) ;
    190.            ((tmp&b)==0)?(LCD_RAM2&=~0x10):(LCD_RAM2 |=0x10) ;
    191.            ((tmp&f)==0)?(LCD_RAM6&=~0x02):(LCD_RAM6 |=0x02) ;
    192.            ((tmp&a)==0)?(LCD_RAM6&=~0x01):(LCD_RAM6 |=0x01) ;
    193.            ((tmp&c)==0)?(LCD_RAM3&=~0x80):(LCD_RAM3 |=0x80) ;
    194.            ((tmp&d)==0)?(LCD_RAM3&=~0x40):(LCD_RAM3 |=0x40) ;           
    195.            
    196.     case 4:
    197.            tmp = LCD_Tab[number%10000/1000];
    198.            ((tmp&m)==0)?(LCD_RAM0&=~0x20):(LCD_RAM0 |=0x20) ;
    199.            ((tmp&e)==0)?(LCD_RAM0&=~0x10):(LCD_RAM0 |=0x10) ;
    200.            ((tmp&g)==0)?(LCD_RAM2&=~0x08):(LCD_RAM2 |=0x08) ;
    201.            ((tmp&b)==0)?(LCD_RAM2&=~0x04):(LCD_RAM2 |=0x04) ;
    202.            ((tmp&f)==0)?(LCD_RAM5&=~0x80):(LCD_RAM5 |=0x80) ;
    203.            ((tmp&a)==0)?(LCD_RAM5&=~0x40):(LCD_RAM5 |=0x40) ;
    204.            ((tmp&c)==0)?(LCD_RAM4&=~0x02):(LCD_RAM4 |=0x02) ;
    205.            ((tmp&d)==0)?(LCD_RAM4&=~0x01):(LCD_RAM4 |=0x01) ;           
    206.     case 3:
    207.            tmp = LCD_Tab[number%1000/100];
    208.            ((tmp&m)==0)?(LCD_RAM0&=~0x80):(LCD_RAM0 |=0x80) ;
    209.            ((tmp&e)==0)?(LCD_RAM0&=~0x40):(LCD_RAM0 |=0x40) ;
    210.            ((tmp&g)==0)?(LCD_RAM2&=~0x02):(LCD_RAM2 |=0x02) ;
    211.            ((tmp&b)==0)?(LCD_RAM2&=~0x01):(LCD_RAM2 |=0x01) ;
    212.            ((tmp&f)==0)?(LCD_RAM5&=~0x20):(LCD_RAM5 |=0x20) ;
    213.            ((tmp&a)==0)?(LCD_RAM5&=~0x10):(LCD_RAM5 |=0x10) ;
    214.            ((tmp&c)==0)?(LCD_RAM4&=~0x08):(LCD_RAM4 |=0x08) ;
    215.            ((tmp&d)==0)?(LCD_RAM4&=~0x04):(LCD_RAM4 |=0x04) ;
    216.    case 2:
    217.            tmp = LCD_Tab[number%100/10];
    218.            ((tmp&m)==0)?(LCD_RAM1&=~0x02):(LCD_RAM1 |=0x02) ;
    219.            ((tmp&e)==0)?(LCD_RAM1&=~0x01):(LCD_RAM1 |=0x01) ;
    220.            ((tmp&g)==0)?(LCD_RAM1&=~0x80):(LCD_RAM1 |=0x80) ;
    221.            ((tmp&b)==0)?(LCD_RAM1&=~0x40):(LCD_RAM1 |=0x40) ;
    222.            ((tmp&f)==0)?(LCD_RAM5&=~0x08):(LCD_RAM5 |=0x08) ;
    223.            ((tmp&a)==0)?(LCD_RAM5&=~0x04):(LCD_RAM5 |=0x04) ;
    224.            ((tmp&c)==0)?(LCD_RAM4&=~0x20):(LCD_RAM4 |=0x20) ;
    225.            ((tmp&d)==0)?(LCD_RAM4&=~0x10):(LCD_RAM4 |=0x10) ;
    226.    case 1: 
    227.            tmp = LCD_Tab[number%10];
    228.            ((tmp&m)==0)?(LCD_RAM1&=~0x08):(LCD_RAM1 |=0x08) ;
    229.            ((tmp&e)==0)?(LCD_RAM1&=~0x04):(LCD_RAM1 |=0x04) ;
    230.            ((tmp&g)==0)?(LCD_RAM1&=~0x20):(LCD_RAM1 |=0x20) ;
    231.            ((tmp&b)==0)?(LCD_RAM1&=~0x10):(LCD_RAM1 |=0x10) ;
    232.            ((tmp&f)==0)?(LCD_RAM5&=~0x02):(LCD_RAM5 |=0x02) ;
    233.            ((tmp&a)==0)?(LCD_RAM5&=~0x01):(LCD_RAM5 |=0x01) ;
    234.            ((tmp&c)==0)?(LCD_RAM4&=~0x80):(LCD_RAM4 |=0x80) ;
    235.            ((tmp&d)==0)?(LCD_RAM4&=~0x40):(LCD_RAM4 |=0x40) ;
    236.     break;
    237.     default:break;
    238.   }
    239. }
    240. void main(void)
    241. {
    242.   LCD_Config();
    243.   LCD_DisplayNum(201609);
    244. //  asm("rim");               //enable interrupts
    245.   while(1)
    246.   {
    247.     asm("wfi");
    248.   }
    249. }
    复制代码
  • 相关阅读:
    CSharp Oracle 登陆
    Oracle基本流程语句
    数据库设计三大范式
    自己总结一些操作数据库的方法
    常用数据库取得前几行的方法
    Intellij idea创建javaWeb以及Servlet简单实现
    idea发布到tomcat缺少jar
    回调函数
    spring笔记
    动态代理
  • 原文地址:https://www.cnblogs.com/nimadi/p/12192724.html
Copyright © 2011-2022 走看看