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

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

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

2019-11-17 05:39:52
字體:
來源:轉載
供稿:網友
漢字處理

  現在要解決的問題是,嵌入式系統中經常要使用的并非是完整的漢字庫,往往只是需要提供數量有限的漢字供必要的顯示功能。例如,一個微波爐的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上欲顯示動畫,必須借助定時器。沒有硬件或軟件定時器的世界是無法想像的:

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

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

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

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

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

void ShowDot()
{
 static BOOL bShowDot = TRUE; /* 再一次領略static要害字的威力 */
 if(bShowDot)
 {
  showChar(’:’,XPos,yPos);
 }
 else
 {
  showChar(’ ’,xPos,yPos);
 }
 bShowDot = ! bShowDot;
}
  菜單操作

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

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

C語言嵌入式系統編程修煉之屏幕操作(圖一)
圖1 菜單范例

  要求以鍵盤上的"← →"鍵切換菜單焦點,當用戶在焦點處于某菜單時,若敲擊鍵盤上的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語言嵌入式系統編程修煉之屏幕操作(圖二)  C語言嵌入式系統編程修煉之屏幕操作(圖三)
圖2 經典的Hello,World!

  圖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
欧美精品精品精品精品免费| 国产偷亚洲偷欧美偷精品| 青青草一区二区| 国产精品久久久久秋霞鲁丝| 色婷婷久久av| 国产在线观看91精品一区| 在线日韩欧美视频| 国产欧亚日韩视频| 日本电影亚洲天堂| 日韩精品www| 亚洲色图av在线| 精品无人区太爽高潮在线播放| 91成人国产在线观看| 国产精品狼人色视频一区| 久久久久久亚洲精品中文字幕| 久久综合免费视频| 欧美精品18videos性欧美| 超碰精品一区二区三区乱码| 日韩精品极品视频免费观看| 伊人久久大香线蕉av一区二区| 日韩成人网免费视频| 日本a级片电影一区二区| 国产精品免费看久久久香蕉| 亚洲欧美日韩中文视频| 久久这里有精品视频| 日韩有码视频在线| 日韩动漫免费观看电视剧高清| 91亚洲精品一区二区| 亚洲japanese制服美女| 欧美国产日韩一区二区在线观看| 97精品一区二区三区| 国产精品免费一区二区三区都可以| 韩国三级电影久久久久久| 国产69精品99久久久久久宅男| 日韩av网站电影| 97久久精品人人澡人人爽缅北| 国产精品18久久久久久首页狼| 欧美—级a级欧美特级ar全黄| 国产精品久久久精品| 欧美亚州一区二区三区| 日韩电影大全免费观看2023年上| 久久久亚洲福利精品午夜| 国产精品一区二区三区毛片淫片| 中文字幕日韩欧美| 国产精品美乳在线观看| 亚洲午夜激情免费视频| 欧美老少做受xxxx高潮| 国产精品第一视频| 久久国产天堂福利天堂| 久久精品国产精品亚洲| 欧美电影免费观看网站| 欧美成人一二三| 欧美另类老女人| 97视频在线观看播放| 亚洲专区国产精品| 国产一区二区三区欧美| 精品国产区一区二区三区在线观看| 亚洲欧美一区二区三区久久| 2018中文字幕一区二区三区| 亚洲美女www午夜| 欧美综合第一页| 欧美激情视频一区二区| 国产精品视频导航| 亚洲国产小视频在线观看| 国产亚洲免费的视频看| 成人激情视频在线播放| 成人午夜黄色影院| 国内精品久久久久久久| 992tv成人免费视频| 91色视频在线观看| 亚洲成人1234| 亚洲sss综合天堂久久| 亚洲精品xxx| 欧美日韩亚洲系列| 欧美巨大黑人极品精男| 欧美性生交大片免网| 久久成人人人人精品欧| 国产精品久久久久国产a级| 日韩第一页在线| 成人信息集中地欧美| 亚洲男子天堂网| 影音先锋日韩有码| 久久久精品国产一区二区| 久久香蕉精品香蕉| 高跟丝袜一区二区三区| 奇米一区二区三区四区久久| 成人免费在线视频网址| 欧美成人免费一级人片100| 亚洲91精品在线观看| 欧美高清无遮挡| 久久久久久久久久久久av| 亚洲人成五月天| 91性高湖久久久久久久久_久久99| 欧美日韩中文字幕在线视频| 91亚洲精华国产精华| 日韩成人在线视频观看| 国产在线拍揄自揄视频不卡99| 日韩精品视频在线观看网址| 国内外成人免费激情在线视频网站| 日韩精品www| 国产日本欧美在线观看| 日韩成人在线电影网| 亚洲欧美日韩天堂| 亚洲在线观看视频网站| 精品国产成人av| 国产视频精品va久久久久久| 国自产精品手机在线观看视频| 久久在线免费视频| 91网站在线免费观看| 久久中国妇女中文字幕| 久久精品精品电影网| 亚洲精品电影在线观看| 亚洲欧美国产日韩中文字幕| 视频一区视频二区国产精品| 国产剧情日韩欧美| 国产精品99久久久久久www| 亚洲欧美在线免费| 精品国产精品自拍| 国产欧美日韩精品丝袜高跟鞋| 亚洲韩国欧洲国产日产av| 久久久久久高潮国产精品视| 国产精品第一区| 欧美成人精品在线视频| 韩国三级日本三级少妇99| 久久综合伊人77777| 亚洲人成网站色ww在线| 国产狼人综合免费视频| 亚洲自拍偷拍色片视频| 欧美国产精品日韩| 91精品国产99久久久久久| 性欧美视频videos6一9| 韩剧1988免费观看全集| 亚洲综合在线播放| 久久久久久久久久婷婷| 亚洲欧洲自拍偷拍| 精品久久中文字幕| 欧美电影免费在线观看| 欧美做受高潮电影o| 日韩av一区二区在线| 日韩女优人人人人射在线视频| 精品一区二区三区四区| 国产婷婷97碰碰久久人人蜜臀| 午夜精品久久久99热福利| 97视频在线观看成人| 成人黄色av网站| 欧美激情乱人伦一区| 92版电视剧仙鹤神针在线观看| 中文字幕免费精品一区| 中文字幕日韩电影| 亚洲天堂色网站| 国产精品视频一区二区三区四| 亚洲精品美女在线观看播放| 成人午夜在线观看| 国产丝袜一区二区三区免费视频| 久久国产加勒比精品无码| 欧美激情aaaa| 亚洲男人的天堂在线播放| 中文字幕综合在线| 伊人av综合网| 国产精品女人久久久久久| 精品久久久久久久中文字幕| 国产日韩欧美日韩大片| 91av视频在线免费观看| 欧美伦理91i|