java切入式編程顯示屏_C語言嵌入式系統編程修煉之四:屏幕操作

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

作者:宋寶華 ? 更新日期:2005-07-22

漢字處理

現在要解決的問題是,嵌入式系統中經常要使用的并非是完整的漢字庫,往往只是需要提供數量有限的漢字供必要的

顯示功能。例如,一個微波爐的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) 沒有定時器,一個多媒體播放軟件將無法運作,因為它不知道何時應該切換到下一幀畫面;

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

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

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

void ShowDot()

{

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

if(bShowDot)

{

showChar(’:’,xPos,yPos);

}

else

{

showChar(’ ’,xPos,yPos);

}

bShowDot = ! bShowDot;

}

菜單操作

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

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

c_optimise_516_1.jpg

圖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_optimise_516_2.jpg? 

c_optimise_516_3.jpg

圖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上凌亂不堪的顯示內容所困擾。

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

posted on 2005-09-21 17:32 小力力力 閱讀(978) 評論(1) ?編輯 ?收藏 所屬分類: C/C++

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/260275.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/260275.shtml
英文地址,請注明出處:http://en.pswp.cn/news/260275.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DIV的邊距屬性在Chrome和IE中的區別

突然間,在Chrome下看起來很整齊的布局,在IE下變成一團糟。為了找出原因,我改動了div的background-color屬性。最后,發現同一個DIV的寬度在IE和Chrome下卻不一樣。這大晚上的,真是怪嚇人滴! 之后&#xff0c…

算法之矩陣計算斐波那契數列

算法之矩陣計算斐波那契數列 本節內容 斐波那契介紹普通方式求解斐波那契矩陣概念矩陣求冪矩陣求解斐波那契1.斐波那契介紹 斐波那契數列有關十分明顯的特點,那是:前面相鄰兩項之和,構成了后一項。即f(n)f(n-1)f(n-2),f(0)0,f(1)f(2)1,推導下…

python中去除字符串中首尾空格的函數_Python中去除字符串首尾特定字符的函數:strip()...

Python中strip()函數的作用是去除一個字符串前導和尾部的特定字符,并返回結果字符串。Python中strip()函數默認是刪除字符串前導和尾部空格,通過設定參數,也可以去除字符串前導和尾部的其它特定字符。strip()函數的語法格式str.strip( [ char…

SeekBar和RatingBar

1. SeekBar的主要屬性 2. OnSeekBarChangeListener 3. RatingBar的主要屬性 4. OnRatingBarChangeListener 1. SeekBar的主要屬性 2. OnSeekBarChangeListener 1 <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"2 xmlns:tools&qu…

用“Web的思想”做PC客戶端

一直在想&#xff0c;用HTML搭建前端頁面這么方便&#xff0c;而且效果這么炫&#xff0c;為什么在PC端的軟件要如此麻煩呢&#xff1f;就連C#也是&#xff0c;更何況C了。 盡管C有DirectUI這樣優秀的圖形庫&#xff0c;但是開發起來仍然非常吃力。C#的WPF雖然工具鏈完善&#…

Java點擊按鈕div縮放_[Java教程]怎樣給div增加resize事件

[Java教程]怎樣給div增加resize事件0 2016-10-31 11:00:04當瀏覽器窗口被調整到一個新的高度或寬度時&#xff0c;就會觸發resize事件,這個事件在window上面觸發,那么如何給div元素增加resize事件&#xff0c;監聽div的高度或寬度的改變呢&#xff1f;某位大神用jquery實現的方…

python判斷題題庫大數據技術_智慧樹_大數據分析的python基礎_搜題公眾號

智慧樹_大數據分析的python基礎_搜題公眾號更多相關問題社會公眾可以查閱煙草專賣行政主管部門的監督檢查記錄。()公民、法人或者其他組織不得利用自動售貨機銷售煙草制品。()煙草廣告中不得有下列情形()。A、社會公益廣告B、遷址、換房、更名等啟事廣告C、表示吸煙有利人體健公…

Java并發中常用同步工具類

為什么80%的碼農都做不了架構師&#xff1f;>>> 同步工具類可以是任何一個對象&#xff0c;只要它根據其自身的狀態來協調線程控制流。阻塞隊列&#xff08;BlockingQueue&#xff09;可以作為同步工具類&#xff0c;其他類型的同步工具類還包括信號量&#xff08;…

Linux平臺Oracle多個實例啟動說明

環境說明:oracle實例1的SID為orcl(為默認啟動的實例),第二個實例的SID為orcl2 啟動步驟&#xff1a; 1&#xff09;啟動數據庫實例完成后&#xff0c;啟動數據庫監聽服務 #lsnrctl start 2&#xff09;切換到需要啟動的數據庫實例下&#xff0c;如下表示啟動的是orcl數據庫…

RTMP協議發送H.264編碼及AAC編碼的音視頻,實現攝像頭直播

RTMP協議發送H.264編碼及AAC編碼的音視頻&#xff0c;實現攝像頭直播 摘要: RTMP協議發送H.264編碼及AAC編碼的音視頻&#xff0c;實現攝像頭直播  RTMP&#xff08;Real Time Messaging Protocol&#xff09;是專門用來傳輸音視頻數據的流媒體協議&#xff0c;最初由Macrome…

java消息順序執行_Apache Flink:如何并行執行但保持消息順序?

請在下面找到使用側輸出和插槽組進行本地擴展的示例 .package org.example/** Licensed to the Apache Software Foundation (ASF) under one* or more contributor license agreements. See the NOTICE file* distributed with this work for additional information* regardi…

python的字符串定界符可以使用_使用Template格式化Python字符串的方法

對Python字符串&#xff0c;除了比較老舊的%&#xff0c;以及用來替換掉%的format&#xff0c;及在python 3.6中加入的f這三種格式化方法以外&#xff0c;還有可以使用Template對象來進行格式化。from string import Template&#xff0c;可以導入Template類。實例化Template類…

【ES實戰】ES6.7的tar包離線安裝幫助手冊

Elasticsearch6.7部署幫助手冊 校驗時間&#xff1a;2023年12月19日 文章目錄 Elasticsearch6.7部署幫助手冊安裝前準備安裝包安裝要求鎖定內存,修改最大文件描述符,最大線程數內核參數 部署規劃端口規劃用戶規劃目錄規劃 安裝步驟每個服務器配置JDK配置文件master角色node角色…

jenkins 部署文檔

Jenkins是一個非常出色的持續集成服務器&#xff0c;本文主要介紹在CentOS系統中Jenkins的基本安裝配置方法&#xff0c;供參考。一. 軟件包&#xff1a;1. 下載apache-maven-2.2.1-bin.tarhttp://www.apache.org/dyn/closer.cgi/maven/binaries/apache-maven-2.2.1-bin.tar.gz…

牛人,多看看他們寫的東西

計算機大師 Donald E. Knuth&#xff08;高德納&#xff09; 算法大師&#xff0c;我最崇拜的計算機科學家&#xff0c;沒有之一&#xff01;不認識高爺爺的人別說自己是學計算機的。《The Art of Computer Programming》絕對是計算機科學的圣經。對高爺爺的崇敬&#xff0c;對…

System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1)

System.Math.Min(System.Threading.Interlocked.Increment(i), i - 1) 在vb里面 等價于ii-1 在C#里面 等價于i-- 是有C#自動轉VB時轉換的轉載于:https://www.cnblogs.com/YaDi/archive/2012/11/08/2759802.html

java快速查找中位數_用QuickSort快速查找中位數(median)

中位數(median)是一個排好序的元素中中間位置的元素&#xff0c;如果元素個數為偶數&#xff0c;則是中間兩個元素的平均值。例如(3,1,5)的中位數是3&#xff0c;而(2,1,3,5)的中位數是2.5。查找中位數屬于SelectionAlgorithms的一種。用快速排序可以做到每次divide之后&#x…

python安裝mysql數據庫_windows10安裝mysql-8.0.13(zip安裝)~Python安裝mysql

windows10安裝mysql-8.0.13(zip安裝)安裝環境說明系統版本&#xff1a;windows10mysql版本&#xff1a;mysql-8.0.13-winx64.zip下載地址&#xff1a;http://mirrors.163.com/mysql/Downloads/MySQL-8.0/mysql-8.0.13-winx64.zip解壓安裝包解壓路徑&#xff1a;D:\develop\soft…

centos 下使用sublime

CentOS 之 Sublime text3 安裝及配置&#xff08;不支持中文輸入&#xff09; sublime text 的界面友好&#xff0c;自動補全功能也不錯。 &#xff08;本來用vimphp_function.txt的形式進行補全的&#xff0c;但是配置后的補全不太滿意&#xff0c;放棄了。 具體參見&#xff…

20121108團隊博客(蘇若)

PS&#xff1a;這本是屬于昨晚的帖子&#xff0c;對不住忠仔。現在補上。 忠仔&#xff0c;終于交給了我一個實實在在的任務&#xff0c;很是欣喜&#xff0c;也很是忐忑&#xff0c;生怕自己不能及時完成任務。 好了&#xff0c;廢話不多說&#xff0c;步入正題。 接下任務【畫…