专栏中心

EEPW首页 > 专栏 > 原代码:ZRTOS的任务篇LCD

原代码:ZRTOS的任务篇LCD

发布人:a181633697 时间:2009-07-31 来源:工程师 发布文章

1、问题综述:
在嵌入式系统中有许多LCD装置,信息的显示往往是由控制芯片向LCD写入byte stream来实现的,如果一次写得太多,LCD装置的buffer放不下,同时也会影响系统的实时性能。合理地选用适当的优先级的任务来对LCD编程,可以收到很好的效果。在下面的程序中,当嵌入式系统需要LCD显示信息时,那些任务将要显示的信息先写入一个ring buffer(lcd_data),然后由另一个任务(lcd_send)将这些数据显示在LCD屏幕上。以下是部分原代码:

#define _LCD_DATA_TO_SENT (3)

typedef struct {
  U8 data[_LCD_DATA_TO_SENT];  //3 bytes are the basic data unit for
} SYN_SCI_SD_SMALL_TYPE;           //a LCD (汉字图形点阵液晶显示模块)

#define LCD_BUFFER_SIZE 64 //32 is too small!    

typedef struct {
  U8 head;
  U8 tail;    
  SYN_SCI_SD_SMALL_TYPE lcd_rcv[LCD_BUFFER_SIZE]; 
} LCD_DATA_TYPE; 

static LCD_DATA_TYPE lcd_data;    //ring buffer to hold all data/byte stream
static RTOS_SEM_ID semrenew;      //semaphone to wake up task lcd_send()
static long sm_timeout;           //time out or period of task lcd_send()

void lcd_Init(void) //initialization of LCD
{
  SYN_SCI_SD_SMALL_TYPE reg; //initialized command to LCD

  semrenew = rtos_semBCreate(0, SEM_EMPTY);//create a semaphone
  sm_timeout = 5;//wait 5 tick or 50 ms;

  lcd_data.head = lcd_data.tail = 0; //clear the ring buffer
  
  rtos_taskSpawn(RTOS_PEND_FOREVER_PRI+1, (RTOS_FUNCPTR) lcd_send, 0);
  //spawn a task (lcd_send) to handle LCD data sending
 
  reg.data[0] = LCD_WRITE_CMD;//this is a LCD write command
 
  fill_a_byte(&reg.data[1],0x30);//fill a byte to the command
  add2send(&reg); //fill the command into the ring buffer
  //other command here ...  
}

static void add2send(SYN_SCI_SD_SMALL_TYPE * reg)//subroutine to put data
{                                                //into the ring buffer
  U8 m = lcd_data.tail+1;
  int n;
 
  if (m == LCD_BUFFER_SIZE) {//the buffer ring over
    m = 0;
  } 
 
  for(n = 0; n < _LCD_DATA_TO_SENT; n++) //always allow new data in
    lcd_data.lcd_rcv[lcd_data.tail].data[n] = reg->data[n];

  if (m == lcd_data.head) { //the ring buffer is full, push the old one out
    if (++lcd_data.head == LCD_BUFFER_SIZE) lcd_data.head = 0;
  } //

  lcd_data.tail = m; //all "in" data shall result in tail growing or
                     //all "producing" is about to go to tail in the
                     //comsumer/product relationship

  if (sm_timeout == (long) WAIT_FOREVER) {//lcd_send task in idle
    sm_timeout = 1; //set the period of lcd_send task, 1 tick or 10 ms
    rtos_semGive(semrenew);//wake up the lcd_send
  }
 
}

static void send_a_byte(U8 byte) //synchronous serial communication for a LCD
{                                //which does not comply with SPI interface
  U8 n;
  U8 bit = 0x80;
 
  for(n = 0; n < 8; n++) {
    LCD_SID(byte&bit); //synchronous serial sending a bit
    bit >>= 1;
  }
}

static void lcd_send(void) //task to handle LCD data sending
{
  U8 n;
  long results = rtos_semTake(semrenew, sm_timeout);//may pended here till time out
    
  if (lcd_data.head == lcd_data.tail || results == (long) OK) {
    return;//the ring buffer is empty or it is not a time out
  }        
  sm_timeout = 1;//set the period of lcd_send task, 1 tick or 10 ms

  LCD_CE_ON(1); //CE enable
  LCD_SCLK(0);
   
  for(n = 0; n < _LCD_DATA_TO_SENT; n++) { //send byte by byte
    send_a_byte(lcd_data.lcd_rcv[lcd_data.head].data[n]);
  }
 
  LCD_CE_ON(0); //CE disable
  lcd_data.head++;
   
  if (lcd_data.head == LCD_BUFFER_SIZE) {
    lcd_data.head = 0;
  }
   
   
  if (lcd_data.head == lcd_data.tail) {
    //continue to send till the buffer is empty
    sm_timeout = WAIT_FOREVER;//pended the task
  }
}

void displaySpeedInLCD(U8 speed) //displacy vehicle speed value on
{                                //LCD screen
  U8 speed_display[] = {//unicode chinese character "speed"
    0xCB,0xD9,0xB6,0xC8,0x3A,
    0,0,0
  };
 
  fill_a_few_100(&speed_display[5],speed); //fill the speed value into storage
                                           //speed_display[]
  fill_block(speed_display,0x93,8);    //fill the speed_display[] into screen
}

static void fill_block(U8* data, U8 loc, U8 size) //fill a block data into
{                                                 //LCD screen
  SYN_SCI_SD_SMALL_TYPE reg;//LCD command form
  U8 n; //index
 
  reg.data[0] = LCD_WRITE_CMD; //LCD write command command
  fill_a_byte(&reg.data[1],loc); //location
  add2send(&reg);//put data into ring buffer/product queue

  reg.data[0] = LCD_WRITE_DATA;//LCD write data command
 
  for(n = 0; n < size; n++) {//fill all data
    fill_a_byte(&reg.data[1],data[n]); //data
    add2send(&reg);
  }
}


2、结论
从上述的例子我们可以看到,在嵌入式系统中,其实是可以用很简单的方法来达到很令人满意的结果的。在教科书中,本例是个经典的生产者-消费者(Comsumer - productor) 问题,有大量的因素(race conditions等)要考虑。在vxWorks等RTOS中通常用MessageQueue类的LinkList的方式来对应。但这样做有如下问题:i)因为嵌入式系统的资源很少,一但LinkList出问题,就会造成严重后果,(这也解释为什么大多数工程师在编程时,将需要的RAM事先安排好);ii)嵌入式系统所面对的是各式各样的硬件设备,MessageQueue类的东东很难有效甚至不能成功地完成任务。比如,在本例中,对LCD而言,10毫秒的间隔是个不错的间隔,但对其他设备可能就不合适;间隔太小会造成硬件的操作失败,间隔太大又造成实时性能差和数据丢失。
在本例中,定义了一个环形数组(ring buffer)所有的products(产品)go to “tail”,而所有的comsumer(消费者)using "head", 当tail将要等于head时,ring buffer is full,此时设计者有以下三种选择:i)把最老的数据推出ring buffer(就像本例中做的那样);ii)拒绝新的数据;iii)接收或拒绝数据并同时通知caller with a return value;
另外,由于使用的是ZRTOS,本例中完全没有race condition问题出现。

专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们

关键词:

相关推荐

nokia3310显示屏的中文说明

与中国不可分割的联系:为什么战略脱离不是一种选择

国际视野 2025-07-08

Applied Materials:为半导体带来更清洁的能源

中国先进制造业的并购热潮受到技术趋势的推动

ST7920c20_中文字库的液晶模块

先进半导体封装材料与加工市场规模与预测(2025-2034年)

见面礼!

powercxz 2003-07-04

触摸屏原理

AI驱动的机器人加速半导体研发,实现绿色能源

亚利桑那州州立大学柔性显示器中心开发第一个触摸屏柔性显示器

模拟信号处理

论模拟电路的人才培养之道(沙龙纪实)

msp430f135驱动1621芯片的段码液晶

三星电子的半导体困境:HBM苦苦挣扎,竞争对手表现出色

大联大品佳推出基于Microchip的3.3KW双向图腾柱PFC逆变电源方案

关税纠缠不清环境中半导体的逆向机遇

EDA/PCB 2025-07-08

RIGOL发布多通道波形发生器及先进计算解决方案

采用实时时钟芯片DS1302+AT89C2051的红外遥控LED电子钟

模拟电路教学心得

全球半导体湿化学品市场到2031年达17亿美元

EDA/PCB 2025-07-08

模拟电子教学方法的改进

更多 培训课堂
更多 焦点
更多 视频

技术专区