標(biāo)題: STM8L的LCD接口詳解及驅(qū)動(dòng)程序 [打印本頁]

作者: 51hei小林    時(shí)間: 2016-10-10 00:04
標(biāo)題: STM8L的LCD接口詳解及驅(qū)動(dòng)程序
STM8L部分型號(hào)集成了段式液晶驅(qū)動(dòng)器,可以驅(qū)動(dòng)4*28=112個(gè)液晶段.段式液晶屏為低功耗顯示器件,功耗根據(jù)屏的大小和顯示段數(shù)會(huì)有所不同,通常功耗在10ua左右.生活中,數(shù)字電子表,數(shù)字萬用表,數(shù)顯溫度計(jì)等,使用的都是段式液晶屏,通常一顆紐扣電池可以保證設(shè)備間隔不斷顯示數(shù)字兩年或更久.


大家比較熟悉的液晶屏1602模塊其實(shí)也是段式液晶,是一個(gè)有很多段的點(diǎn)組成的,由于點(diǎn)比較多,所以1602模塊集成了驅(qū)動(dòng)芯片,我們只需給1602送數(shù)據(jù),就可以控制1602進(jìn)行顯示了.液晶本身不會(huì)發(fā)光,1602之所以會(huì)發(fā)光是因?yàn)槭褂昧薒ED背光板.
段式液晶驅(qū)動(dòng)器,通常會(huì)含有一個(gè)電壓泵,一個(gè)頻率分頻器.電壓泵用來提供驅(qū)動(dòng)液晶段的電壓,電壓的高低決定著顯示的清晰度,也就是決定著液晶的對(duì)比度.提供給LCD驅(qū)動(dòng)器的頻率決定著,刷新段式液晶的頻率,如果提供給LCD的頻率太低,會(huì)看到顯示時(shí)的頻閃.

從上圖可以看到,除了分頻器和電壓泵部分,還有顯存.所有液晶屏都會(huì)有顯存,每個(gè)顯存控制著對(duì)應(yīng)的引腳,對(duì)于STM8L的八位顯存,可以控制8個(gè)引腳和一個(gè)COM引腳,比如STM8L的RAM0控制著COM0對(duì)應(yīng)的S0~S7引腳.
當(dāng)我們需要驅(qū)動(dòng)一塊液晶屏?xí)r,首先要拿到這種液晶屏的引腳對(duì)應(yīng)顯示段的圖紙.如下圖,由于STM8L152C6的RAM0控制著COM0對(duì)應(yīng)的S0~S7引腳,如果要顯示下圖的"元",那么我們只需要向RAM0寫入數(shù)據(jù)0x01.
本例程的硬件平臺(tái)仍然是ST官方的開發(fā)板STM8L-DISCOVERY.在ST官網(wǎng)的編號(hào)為UM0970這份文檔中,有對(duì)開發(fā)板上液晶屏的介紹.

這份資料,并不是十分直觀.找到顯存對(duì)應(yīng)的液晶屏上的段,對(duì)寫程序來說很重要.

本例程,參考ST提供的例程,根據(jù)自己的理解,編寫了LCD驅(qū)動(dòng)程序,提供一個(gè)可以在液晶屏上最多顯示六位數(shù)字的接口的程序,讀者可以調(diào)用此程序,顯示任意六位以內(nèi)的數(shù)字.


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

  2. *開發(fā)環(huán)境:IAR for stm8 v6.5.3

  3. *硬件平臺(tái):STM8L-DISCOVERY

  4. *功能說明:使用STM8L-DISCOVERY液晶屏顯示一串6位數(shù)字

  5. *作    者:茗風(fēng)

  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觸發(fā),也不用軟件觸發(fā),寫入DHR的數(shù)據(jù)被立即送入DOR寄存器,

  47. *            立即輸出對(duì)應(yīng)電壓

  48. *  入口參數(shù):無

  49. *  出口參數(shù):無

  50. *  說    明:STM8L152C6屬于中等容量MCU,只有一路DAC輸出,輸出引腳為PF0

  51. *  范    例:無

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

  53. void LCD_Config(void)

  54. {

  55. //------打開LCD/RTC時(shí)鐘------

  56.   CLK_PCKENR2_PCKEN22=1;//打開RTC時(shí)鐘,LCD刷新頻率與此時(shí)鐘有關(guān)

  57.   CLK_PCKENR2_PCKEN23=1;//打開LCD時(shí)鐘,讀寫LCD寄存器用到此時(shí)鐘

  58.   

  59. //---選擇LSE作為RTC時(shí)鐘---

  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. //----設(shè)置RTC時(shí)鐘分頻值----

  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. //----設(shè)置LCD預(yù)分頻值----  

  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. //----設(shè)置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. //以上分頻值的設(shè)置,最為了得到適合的LCD的刷新頻率,如果增大分頻值,會(huì)導(dǎo)致

  95. //LCD刷新頻率變低,會(huì)看到LCD顯示出現(xiàn)閃爍

  96. //比如,我們將PS[3:0]設(shè)置為0011,會(huì)看到液晶閃爍  

  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. //----內(nèi)部電壓源----   

  111.   LCD_CR2_VSEL=0;

  112.   

  113. //----打開引腳的SEG功能----     

  114. // LCD_PM0=0xFF;//頭文件這個(gè)地方定義錯(cuò)誤,無法直接向LCD_PM0寫入數(shù)據(jù)

  115. // LCD_PM1=0xFF;//PM0寄存器定義錯(cuò)誤,導(dǎo)致PM1也無法直接寫入

  116. // LCD_PM2=0xFF;//PM0寄存器定義錯(cuò)誤,導(dǎo)致PM2也無法直接寫入

  117.   *((uint8_t *)0x5404)=0xFF;//直接向LCD_PM0寄存器的地址寫入數(shù)據(jù)

  118.   *((uint8_t *)0x5405)=0xFF;//直接向LCD_PM1寄存器的地址寫入數(shù)據(jù)

  119.   *((uint8_t *)0x5406)=0xFF;//直接向LCD_PM2寄存器的地址寫入數(shù)據(jù)

  120.   

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

  122.   LCD_CR2_CC0=0;//對(duì)比度

  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. *  功            能:控制段式液晶屏的數(shù)字顯示部分

  157. *  入口參數(shù):number:要顯示的數(shù)字

  158. *  出口參數(shù):無

  159. *  說          明:根據(jù)數(shù)字的長度,判斷要顯示的長度,長度大于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.   //判斷需要顯示數(shù)字的長度,確定在LCD屏上需要的位數(shù)

  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. }
復(fù)制代碼





作者: IdeaMing    時(shí)間: 2018-4-24 17:23
謝謝分享,發(fā)現(xiàn)最難的就是對(duì)應(yīng)顯存。不知道有什么規(guī)則。
作者: wlsdtiankong    時(shí)間: 2018-11-5 10:58
為什么我這里會(huì)報(bào)錯(cuò)
作者: lixianshen    時(shí)間: 2019-3-29 19:28
大師,我用你的lcd程序和你的adc程序調(diào)試stm8ldiscouer套件時(shí)發(fā)現(xiàn),stm8l152c 6t6的adc測(cè)電壓時(shí),電壓從0伏調(diào)到2.99伏,lcd輸出顯示正常 ,電壓從2.99到1伏正常,電壓從1伏到0.99伏時(shí),顯示1.99伏,電壓從1伏調(diào)到0伏,顯示就從1伏到1.99到1.0,就可以要多顯示1伏,而在電腦上的調(diào)試程序中顯示的電壓確是正常的,而單片機(jī)輸入電壓是用萬用表和示波器看的,電壓沒有跳躍,不知道是那里的問題?感覺好像跟中斷觸發(fā)有關(guān)系。
作者: huang_hzl    時(shí)間: 2019-12-20 13:32
本帖最后由 huang_hzl 于 2019-12-20 14:55 編輯


你好,我按你的LCD配置,依然無法點(diǎn)亮LCD,請(qǐng)問,是哪里的問題呢  ?
仿真時(shí),可以看到LCD_RAM0~LCDRAM13,已經(jīng)被寫入了數(shù)據(jù)。

作者: stphen    時(shí)間: 2020-1-13 16:03
huang_hzl 發(fā)表于 2019-12-20 13:32
你好,我按你的LCD配置,依然無法點(diǎn)亮LCD,請(qǐng)問,是哪里的問題呢  ?
仿真時(shí),可以看到LCD_RAM0~LCDRAM13 ...

你好,我現(xiàn)在遇到跟你一樣的問題,請(qǐng)問你的點(diǎn)亮了嘛
作者: stphen    時(shí)間: 2020-1-13 18:36
huang_hzl 發(fā)表于 2019-12-20 13:32
你好,我按你的LCD配置,依然無法點(diǎn)亮LCD,請(qǐng)問,是哪里的問題呢  ?
仿真時(shí),可以看到LCD_RAM0~LCDRAM13 ...

你好,我用的也是STM8L系列的LCD型芯片,遇到了跟你一樣的問題,可以回復(fù)我或則加我qq為我解除一下疑惑嘛,非常感謝!




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1