亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C語言嵌入式系統編程之屏幕操作

2019-11-17 05:39:50
字體:
來源:轉載
供稿:網友

  漢字處理

  現在要解決的問題是,嵌入式系統中經常要使用的并非是完整的漢字庫,往往只是需要提供數量有限的漢字供必要的顯示功能。例如,一個微波爐的LCD上沒有必要提供顯示"電子郵件"的功能;一個提供漢字顯示功能的空調的LCD上不需要顯示一條"短消息",諸如此類。但是一部手機、小靈通則通常需要包括較完整的漢字庫。

  假如包括的漢字庫較完整,那么,由內碼計算出漢字字模在庫中的偏移是十分簡單的:漢字庫是按照區位的順序排列的,前一個字節為該漢字的區號,后一個字節為該字的位號。每一個區記錄94個漢字,位號則為該字在該區中的位置。因此,漢字在漢字庫中的具體位置計算公式為:94*(區號-1)+位號-1。減1是因為數組是以0為開始而區號位號是以1為開始的。只需乘上一個漢字字模占用的字節數即可,即:(94*(區號-1)+位號-1)*一個漢字字模占用字節數,以16*16點陣字庫為例,計算公式則為:(94*(區號-1)+(位號-1))*32。漢字庫中從該位置起的32字節信息記錄了該字的字模信息。

  對于包含較完整漢字庫的系統而言,我們可以以上述規則計算字模的位置。但是假如僅僅是提供少量漢字呢?譬如幾十至幾百個?最好的做法是:

  定義宏:

  

  # define EX_FONT_CHAR(value)

  # define EX_FONT_UNICODE_VAL(value) (value),

  # define EX_FONT_ANSI_VAL(value) (value),

  定義結構體:

  

  typedef strUCt _wide_unicode_font16x16

  {

   Word value; /* 內碼 */

   BYTE data[32]; /* 字模點陣 */

  }Unicode;

  #define CHINESE_CHAR_NUM … /* 漢字數量 */

  字模的存儲用數組:

  

  Unicode chinese[CHINESE_CHAR_NUM] =

  {

  {

  EX_FONT_CHAR("業")

  EX_FONT_UNICODE_VAL(0x4e1a)

  {0x04, 0x40, 0x04, 0x40, 0x04, 0x40, 0x04, 0x44, 0x44, 0x46, 0x24, 0x4c, 0x24, 0x48, 0x14, 0x50, 0x1c, 0x50, 0x14, 0x60, 0x04, 0x40, 0x04, 0x40, 0x04, 0x44, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00}

  },

  {

  EX_FONT_CHAR("中")

  EX_FONT_UNICODE_VAL(0x4e2d)

  {0x01, 0x00, 0x01, 0x00, 0x21, 0x08, 0x3f, 0xfc, 0x21, 0x08, 0x21, 0x08, 0x21, 0x08, 0x21, 0x08, 0x21, 0x08,

  0x3f, 0xf8, 0x21, 0x08, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00}

  },

  {

  EX_FONT_CHAR("云")

  EX_FONT_UNICODE_VAL(0x4e91)

  {0x00, 0x00, 0x00, 0x30, 0x3f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0xff, 0xfe, 0x03, 0x00, 0x07, 0x00,

  

  0x06, 0x40, 0x0c, 0x20, 0x18, 0x10, 0x31, 0xf8, 0x7f, 0x0c, 0x20, 0x08, 0x00, 0x00}

  },

  {

  EX_FONT_CHAR("件")

  EX_FONT_UNICODE_VAL(0x4ef6)

  {0x10, 0x40, 0x1a, 0x40, 0x13, 0x40, 0x32, 0x40, 0x23, 0xfc, 0x64, 0x40, 0xa4, 0x40, 0x28, 0x40, 0x2f, 0xfe,

  

  0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40, 0x20, 0x40}

  }

  }

  要顯示特定漢字的時候,只需要從數組中查找內碼與要求漢字內碼相同的即可獲得字模。假如前面的漢字在數組中以內碼大小順序排列,那么可以以二分查找法更高效的查找到漢字的字模。

  這是一種很有效的組織小漢字庫的方法,它可以保證程序有很好的結構。

  系統時間顯示

  從NVRAM中可以讀取系統的時間,系統一般借助NVRAM產生的秒中斷每秒讀取一次當前時間并在LCD上顯示。關于時間的顯示,有一個效率問題。因為時間有其非凡性,那就是60秒才有一次分鐘的變化,60分鐘才有一次小時變化,假如我們每次都將讀取的時間在屏幕上完全重新刷新一次,則浪費了大量的系統時間。

  一個較好的辦法是我們在時間顯示函數中以靜態變量分別存儲小時、分鐘、秒,只有在其內容發生變化的時候才更新其顯示。

  

  extern void DisplayTime(…)

  {

   static BYTE byHour,byMinute,bySecond;

   BYTE byNewHour, byNewMinute, byNewSecond;

   byNewHour = GetSysHour();

   byNewMinute = GetSysMinute();

   byNewSecond = GetSysSecond();

   

   if(byNewHour!= byHour)

   {

    … /* 顯示小時 */

    byHour = byNewHour;

   }

   if(byNewMinute!= byMinute)

   {

    … /* 顯示分鐘 */

    byMinute = byNewMinute;

   }

   if(byNewSecond!= bySecond)

   {

    … /* 顯示秒鐘 */

    bySecond = byNewSecond;

   }

  }

  這個例子也可以順便作為C語言中static要害字強大威力的證實。當然,在C++語言里,static具有了更加強大的威力,它使得某些數據和函數脫離"對象"而成為"類"的一部分,正是它的這一特點,成就了軟件的無數優秀設計。
  動畫顯示

  動畫是無所謂有,無所謂無的,靜止的畫面走的路多了,也就成了動畫。隨著時間的變更,在屏幕上顯示不同的靜止畫面,即是動畫之本質。所以,在一個嵌入式系統的LCD上欲顯示動畫,必須借助定時器。沒有硬件或軟件定時器的世界是無法想像的:

  (1) 沒有定時器,一個操作系統將無法進行時間片的輪轉,于是無法進行多任務的調度,于是便不再成其為一個多任務操作系統;

  (2) 沒有定時器,一個多媒體播放軟件將無法運作,因為它不知道何時應該切換到下一幀畫面;

 ?。?) 沒有定時器,一個網絡協議將無法運轉,因為其無法獲知何時包傳輸超時并重傳之,無法在特定的時間完成特定的任務。

  因此,沒有定時器將意味著沒有操作系統、沒有網絡、沒有多媒體,這將是怎樣的黑暗?所以,合理并靈活地使用各種定時器,是對一個軟件人的最基本需求!

  在80186為主芯片的嵌入式系統中,我們需要借助硬件定時器的中斷來作為軟件定時器,在中斷發生后變更畫面的顯示內容。在時間顯示"xx:xx"中讓冒號交替有無,每次秒中斷發生后,需調用ShowDot:

  

  void ShowDot()

  {

   static BOOL bShowDot = TRUE; /* 再一次領略static要害字的威力 */

   if(bShowDot)

   {

    showChar(’:’,XPos,yPos);

   }

   else

   {

    showChar(’ ’,xPos,yPos);

   }

   bShowDot = ! bShowDot;

  }

  菜單操作

  無數人為之絞盡腦汁的問題終于出現了,在這一節里,我們將看到,在C語言中哪怕用到一丁點的面向對象思想,軟件結構將會有何等的改觀!

  筆者曾經是個笨蛋,被菜單搞暈了,給出這樣的一個系統:

  


  
C語言嵌入式系統編程之屏幕操作(圖一)



  


  要求以鍵盤上的"← →"鍵切換菜單焦點,當用戶在焦點處于某菜單時,若敲擊鍵盤上的OK、CANCEL鍵則調用該焦點菜單對應之處理函數。我曾經傻傻地這樣做著:

  

  /* 按下OK鍵 */

  void onOkKey()

  {

   /* 判定在什么焦點菜單上按下Ok鍵,調用相應處理函數 */

   Switch(currentFocus)

   {

    case MENU1:

     menu1OnOk();

     break;

    case MENU2:

     menu2OnOk();

     break;

    …

   }

  }

  /* 按下Cancel鍵 */

  void onCancelKey()

  {

   /* 判定在什么焦點菜單上按下Cancel鍵,調用相應處理函數 */

   Switch(currentFocus)

   {

    case MENU1:

     menu1OnCancel();

     break;

    case MENU2:

     menu2OnCancel();

     break;

    …

   }

  }

  終于有一天,我這樣做了:

  

  /* 將菜單的屬性和操作"封裝"在一起 */

  typedef struct tagSysMenu

  {

   char *text; /* 菜單的文本 */

   BYTE xPos; /* 菜單在LCD上的x坐標 */

   BYTE yPos; /* 菜單在LCD上的y坐標 */

   void (*onOkFun)(); /* 在該菜單上按下ok鍵的處理函數指針 */

   void (*onCancelFun)(); /* 在該菜單上按下cancel鍵的處理函數指針 */

  }SysMenu, *LPSysMenu;

  當我定義菜單時,只需要這樣:

  

  static SysMenu menu[MENU_NUM] =

  {

   {

    "menu1", 0, 48, menu1OnOk, menu1OnCancel

   }

   ,

   {

    " menu2", 7, 48, menu2OnOk, menu2OnCancel

   }

   ,

   {

    " menu3", 7, 48, menu3OnOk, menu3OnCancel

   }

   ,

   {

    " menu4", 7, 48, menu4OnOk, menu4OnCancel

   }

   …

  };

  OK鍵和CANCEL鍵的處理變成:

  

  /* 按下OK鍵 */

  void onOkKey()

  {

   menu[currentFocusMenu].onOkFun();

  }

  /* 按下Cancel鍵 */

  void onCancelKey()

  {

   menu[currentFocusMenu].onCancelFun();

  }

  程序被大大簡化了,也開始具有很好的可擴展性!我們僅僅利用了面向對象中的封裝思想,就讓程序結構清楚,其結果是幾乎可以在無需修改程序的情況下在系統中添加更多的菜單,而系統的按鍵處理函數保持不變。

  面向對象,真神了!
  模擬MessageBox函數

  MessageBox函數,這個Windows編程中的超級猛料,不知道是多少入門者第一次用到的函數。還記得我們第一次在Windows中利用MessageBox輸出 "Hello,World!"對話框時新奇的感覺嗎?無法統計,這個世界上究竟有多少程序員學習Windows編程是從MessageBox("Hello,World!",…)開始的。在我本科的學校,廣泛流傳著一個詞匯,叫做"’Hello,World’級程序員",意指入門級程序員,但似乎"’Hello,World’級"這個說法更搞笑而形象。

  


  
C語言嵌入式系統編程之屏幕操作(圖二)


  


  圖2給出了兩種永恒經典的Hello,World對話框,一種只具有"確定",一種則包含"確定"、"取消"。是的,MessageBox的確有,而且也應該有兩類!這完全是由特定的應用需求決定的。

  嵌入式系統中沒有給我們提供MessageBox,但是鑒于其功能強大,我們需要模擬之,一個模擬的MessageBox函數為:

  

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

  /* 函數名稱: MessageBox

  /* 功能說明: 彈出式對話框,顯示提醒用戶的信息

  /* 參數說明: lpStr --- 提醒用戶的字符串輸出信息

  /* TYPE --- 輸出格式(ID_OK = 0, ID_OKCANCEL = 1)

  /* 返回值: 返回對話框接收的鍵值,只有兩種 KEY_OK, KEY_CANCEL

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

  typedef enum TYPE { ID_OK,ID_OKCANCEL }MSG_TYPE;

  extern BYTE MessageBox(LPBYTE lpStr, BYTE TYPE)

  {

   BYTE keyValue = -1;

  

   ClearScreen(); /* 清除屏幕 */

   DisplayString(xPos,yPos,lpStr,TRUE); /* 顯示字符串 */

   /* 根據對話框類型決定是否顯示確定、取消 */

   switch (TYPE)

   {

    case ID_OK:

     DisplayString(13,yPos+High+1, " 確定 ", 0);

     break;

    case ID_OKCANCEL:

     DisplayString(8, yPos+High+1, " 確定 ", 0);

     DisplayString(17,yPos+High+1, " 取消 ", 0);

     break;

    default:

     break;

   }

   DrawRect(0, 0, 239, yPos+High+16+4); /* 繪制外框 */

   /* MessageBox是模式對話框,阻塞運行,等待按鍵 */

   while( (keyValue != KEY_OK)    (keyValue != KEY_CANCEL) )

   {

    keyValue = getSysKey();

   }

   /* 返回按鍵類型 */

   if(keyValue== KEY_OK)

   {

    return ID_OK;

   }

   else

   {

    return ID_CANCEL;

   }

  }

  上述函數與我們平素在VC++等中使用的MessageBox是何等的神似啊?實現這個函數,你會看到它在嵌入式系統中的妙用是無窮的。

  總結

  本篇是本系列文章中技巧性最深的一篇,它提供了嵌入式系統屏幕顯示方面一些很巧妙的處理方法,靈活使用它們,我們將不再被LCD上凌亂不堪的顯示內容所困擾。

  屏幕乃嵌入式系統生存之重要輔助,面目可憎之顯示將另用戶逃之夭夭。屏幕編程若處理不好,將是軟件中最不系統、最混亂的部分,筆者曾深受其害。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲男人7777| 成人性生交xxxxx网站| 国产免费一区二区三区在线观看| 91免费欧美精品| 亚洲最大福利视频| 欧美在线免费观看| 色偷偷噜噜噜亚洲男人| 国产成人精品久久久| 91伊人影院在线播放| 亚洲一区二区三区成人在线视频精品| 欧美最顶级丰满的aⅴ艳星| 国内成人精品一区| 欧美在线欧美在线| 精品在线观看国产| 欧美成人黑人xx视频免费观看| 在线视频国产日韩| 日本免费一区二区三区视频观看| 精品亚洲国产成av人片传媒| 亚洲级视频在线观看免费1级| 亚洲视频视频在线| 精品久久久中文| 91久久久久久国产精品| 国内精品伊人久久| 在线国产精品播放| 91精品国产91久久久久久久久| 欧美一区二粉嫩精品国产一线天| 最近中文字幕2019免费| 在线亚洲国产精品网| 日韩av在线高清| 91久久国产综合久久91精品网站| 欧美日韩国产丝袜美女| 中文字幕av一区二区三区谷原希美| 91精品国产自产91精品| 欧美黑人性猛交| 亚洲午夜未满十八勿入免费观看全集| 77777亚洲午夜久久多人| 亚洲一区二区三区乱码aⅴ| 少妇av一区二区三区| 岛国精品视频在线播放| 亚洲人成电影网站色www| 日韩中文字幕免费看| 国产成人精彩在线视频九色| 欧美激情综合亚洲一二区| 欧美日韩国产在线| 91久久精品视频| www.日韩av.com| 亚洲激情视频网站| 久久久国产一区二区三区| 亚洲欧美日本另类| 人人爽久久涩噜噜噜网站| 亚洲欧洲一区二区三区在线观看| 亚洲成人黄色网址| 欧美尺度大的性做爰视频| 一本一本久久a久久精品牛牛影视| 久久久久久久一区二区| 亚洲免费av片| 亚洲国产高清自拍| 亚洲一区二区久久久久久久| 高跟丝袜一区二区三区| 青青草一区二区| 国产99久久精品一区二区 夜夜躁日日躁| 日本高清不卡在线| 日韩电影免费观看在线| 亚洲最新av在线网站| 亚洲第一精品夜夜躁人人爽| 成人免费看黄网站| 国产成人一区二区三区小说| 国产精品久久久久久亚洲影视| 亚洲三级 欧美三级| 91av在线播放视频| 久久久噜噜噜久久中文字免| 久久精品国产精品亚洲| 亚洲国产成人精品久久| 亚洲天堂网在线观看| 久久久视频在线| 久久人人爽国产| 亚洲欧美激情视频| 精品一区二区三区三区| 亚洲国产欧美一区二区三区同亚洲| 日韩欧美成人精品| 91美女福利视频高清| 色播久久人人爽人人爽人人片视av| 欧美性在线观看| 欧美肥老太性生活视频| 欧美性开放视频| 国产91成人video| 国产精品入口日韩视频大尺度| 日韩精品视频免费在线观看| 中文字幕亚洲精品| 97在线视频一区| 九九综合九九综合| 欧美性xxxxx极品娇小| 日韩精品亚洲元码| 国产日韩中文在线| 国产日韩欧美成人| 蜜月aⅴ免费一区二区三区| 亚洲深夜福利在线| 国产精品私拍pans大尺度在线| 精品国产一区二区三区久久久狼| 欧美精品在线免费| 欧美日韩国产123| 欧美性猛交xxxx富婆| 日韩欧美在线视频日韩欧美在线视频| 国产一区二区三区视频在线观看| 国产精品自拍偷拍| 日韩中文娱乐网| 91久久久亚洲精品| 亚洲精品日韩欧美| 中日韩午夜理伦电影免费| 欧美成人激情在线| 久久综合五月天| 最近2019年好看中文字幕视频| 欧美成人免费网| 久久6精品影院| 8050国产精品久久久久久| 国产精品日韩欧美综合| 中文字幕亚洲综合久久| 亚洲一区二区国产| 欧美激情中文字幕乱码免费| 亚洲在线视频观看| 日韩欧美中文在线| 亚洲综合视频1区| 全色精品综合影院| 亚洲欧美日韩中文在线| 欧美国产日韩视频| 久久久国产精彩视频美女艺术照福利| 欧美日韩aaaa| 日韩网站免费观看| 久久久精品2019中文字幕神马| 久久亚洲成人精品| 欧美午夜性色大片在线观看| 午夜精品一区二区三区在线视| 成人综合网网址| 国产在线观看91精品一区| 亚洲精品狠狠操| 国产一区二区三区在线观看网站| 超碰91人人草人人干| 久久夜色精品国产亚洲aⅴ| 久久久久久12| 欧美二区乱c黑人| 正在播放国产一区| 日韩欧美成人网| 日本国产欧美一区二区三区| 日韩电影中文字幕一区| 日韩最新免费不卡| 精品国产一区久久久| 中文字幕在线亚洲| 欧美激情网友自拍| 欧美精品在线第一页| 国产一区二区激情| 上原亚衣av一区二区三区| 九九久久精品一区| 国产精品久久久久久久久久尿| 亚洲国产精品电影在线观看| 国产精品欧美亚洲777777| 国外成人免费在线播放| 亚洲国产成人久久综合一区| 亚洲精选一区二区| 日韩大片免费观看视频播放| 中文字幕精品网| 亚洲成人黄色在线观看| 国产亚洲精品久久久久久| 日本亚洲欧洲色α| 日韩高清欧美高清|