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驅動程序,提供一個可以在液晶屏上最多顯示六位數字的接口的程序,讀者可以調用此程序,顯示任意六位以內的數字.

 

/****************************************************************************************

*開發環境:IAR for stm8 v6.5.3

*硬件平臺:STM8L-DISCOVERY

*功能說明:使用STM8L-DISCOVERY液晶屏顯示一串6位數字

*作    者:茗風

****************************************************************************************/

#include"iostm8l152c6.h"

#include"stdint.h"

/*  =========================================================================

                                 LCD MAPPING

    =========================================================================

            A

     _  ----------

COL |_| |\   |J  /|

       F| H  |  K |B

     _  |  \ | /  |

COL |_| --G-- --M--

        |   /| \  |

       E|  Q |  N |C

     _  | /  |P  \|   

DP  |_| -----------  

            D      

*/


#define a 0x01

#define b 0x02

#define c 0x04

#define d 0x08

#define e 0x10

#define f 0x20

#define g 0x40

#define m 0x80


const uint8_t LCD_Tab[10] = {

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

                b + c,                                        // Displays "1"

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

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

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

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

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

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

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

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


};


/******************************************************************************************************

*  名    稱:void LCD_Config(void)

*  功    能:配置DAC,禁用DMA,不使用TIM4觸發,也不用軟件觸發,寫入DHR的數據被立即送入DOR寄存器,

*            立即輸出對應電壓

*  入口參數:無

*  出口參數:無

*  說    明:STM8L152C6屬於中等容量MCU,只有一路DAC輸出,輸出引腳爲PF0

*  範    例:無

******************************************************************************************************/

void LCD_Config(void)

{ 

//------打開LCD/RTC時鐘------

  CLK_PCKENR2_PCKEN22=1;//打開RTC時鐘,LCD刷新頻率與此時鐘有關

  CLK_PCKENR2_PCKEN23=1;//打開LCD時鐘,讀寫LCD寄存器用到此時鐘

  

//---選擇LSE作爲RTC時鐘---

  CLK_CRTCR_RTCSEL0=0;

  CLK_CRTCR_RTCSEL1=0;

  CLK_CRTCR_RTCSEL2=0;

  CLK_CRTCR_RTCSEL3=1;

/* 0000: No clock selected

   0001: HSI clock used as RTC clock source

   0010: LSI clock used as RTC clock source

   0100: HSE clock used as RTC clock source

   1000: LSE clock used as RTC clock sourc*/

  

//----設置RTC時鐘分頻值----

  CLK_CRTCR_RTCDIV0=0;

  CLK_CRTCR_RTCDIV1=0;

  CLK_CRTCR_RTCDIV2=0;

/*000: RTC clock source/1

  001: RTC clock source /2

  010: RTC clock source /4

  011: RTC clock source /8

  100: RTC clock source /16

  101: RTC clock source /32

  110: RTC clock source /64

  111: RTC clock source /128*/

  

//----設置LCD預分頻值----  

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

  LCD_FRQ_PS1=0;//分頻值爲1

  LCD_FRQ_PS2=0;

  LCD_FRQ_PS3=0;

  

//----設置LCD分頻值----  

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

  LCD_FRQ_DIV1=1;//分頻值爲15+16=31

  LCD_FRQ_DIV2=1;

  LCD_FRQ_DIV3=1;  



//以上分頻值的設置,最爲了得到適合的LCD的刷新頻率,如果增大分頻值,會導致

//LCD刷新頻率變低,會看到LCD顯示出現閃爍

//比如,我們將PS[3:0]設置爲0011,會看到液晶閃爍  

  

//----1/4 duty----  

  LCD_CR1_DUTY0=1;//1/4 duty

  LCD_CR1_DUTY1=1;

/* Duty ratio selection

   00: Static duty

   01: 1/2 duty

   10: 1/3 duty

   11: 1/4 duty      */


//----1/3 bias----     

  LCD_CR1_B2=0;//1/3 bias

/* 0: 1/3 bias

   1: 1/2 bias  */


//----內部電壓源----   

  LCD_CR2_VSEL=0;

  

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

// LCD_PM0=0xFF;//頭文件這個地方定義錯誤,無法直接向LCD_PM0寫入數據

// LCD_PM1=0xFF;//PM0寄存器定義錯誤,導致PM1也無法直接寫入

// LCD_PM2=0xFF;//PM0寄存器定義錯誤,導致PM2也無法直接寫入

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

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

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

  

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

  LCD_CR2_CC0=0;//對比度

  LCD_CR2_CC1=1;

  LCD_CR2_CC2=0;

/*  000: VLCD0  2.6V

    001: VLCD1  2.7V

    010: VLCD2  2.8V

    011: VLCD3  2.9V

    100: VLCD4  3.0V

    101: VLCD5  3.1V

    110: VLCD6  3.2V

    111: VLCD7    */

        

//----Dead time 0----         

  LCD_CR3_DEAD0=0;//no dead time

  LCD_CR3_DEAD1=0;  

  LCD_CR3_DEAD2=0;

//----LCD_PulseOnDuration_1----

  LCD_CR2_PON0=1; 

  LCD_CR2_PON1=0;  

  LCD_CR2_PON2=0;          

/*  000: 0 CLKps pulses

    001: 1 CLKps pulses

    010: 2 CLKps pulses

    011: 3 CLKps pulses

    100: 4 CLKps pulses

    101: 5 CLKps pulses

    110: 6 CLKps pulses

    111: 7 CLKps pulses  */

        

//----Enable LCD peripheral----        

  LCD_CR3_LCDEN=1;

}


/******************************************************************************************************

*  名          稱:LCD_DisplayNum(uint8_t number)

*  功            能:控制段式液晶屏的數字顯示部分

*  入口參數:number:要顯示的數字

*  出口參數:無

*  說          明:根據數字的長度,判斷要顯示的長度,長度大於6位,只顯示後六位

*  範          例:無

******************************************************************************************************/

void LCD_DisplayNum(uint32_t number)

{

  uint8_t cnts=0,tmp=0;

  

  if(number<10)cnts=1;

  else if(number<100)cnts=2;

  else if(number<1000)cnts=3;

  else if(number<10000)cnts=4;

  else if(number<100000)cnts=5;

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

  else cnts=6;


  //判斷需要顯示數字的長度,確定在LCD屏上需要的位數

  switch(cnts)

  {

    case 6:

           tmp = LCD_Tab[number%1000000/100000];

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

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

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

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

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

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

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

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

    case 5:

           tmp = LCD_Tab[number%100000/10000];

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

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

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

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

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

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

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

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

           

    case 4:

           tmp = LCD_Tab[number%10000/1000];


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

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

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

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

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

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

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

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

    case 3:

           tmp = LCD_Tab[number%1000/100];

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

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

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

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

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

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

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

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


   case 2:

           tmp = LCD_Tab[number%100/10];

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

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

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

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

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

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

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

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


   case 1: 

           tmp = LCD_Tab[number%10];

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

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

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

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

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

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

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

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

    break;


    default:break;

  }

}

void main(void)

{

  LCD_Config();

  LCD_DisplayNum(201609);

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

  while(1)

  {

    asm("wfi");

  }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章