日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

嵌入式编程之模块化编程

發(fā)布時間:2025/5/22 编程问答 9 豆豆
生活随笔 收集整理的這篇文章主要介紹了 嵌入式编程之模块化编程 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文出處:http://blog.csdn.net/wanruoqingkong/article/details/24286625

當你在一個項目小組做一個相對較復雜的工程時,意味著你不再獨自單干。你需要和你的小組成員分工合作,一起完成項目,這就要求小組成員各自負責一部分工程。比如你可能只是負責通訊或者顯示這一塊。這個時候,你就應該將自己的這一塊程序?qū)懗梢粋€模塊,單獨調(diào)試,留出接口供其它模塊調(diào)用。最后,小組成員都將自己負責的模塊寫完并調(diào)試無誤后,由項目組長進行組合調(diào)試。像這些場合就要求程序必須模塊化。模塊化的好處是很多的,不僅僅是便于分工,它還有助于程序的調(diào)試,有利于程序結(jié)構(gòu)的劃分,還能增加程序的可讀性和可移植性。

初學者往往搞不懂如何模塊化編程,其實它是簡單易學,而且又是組織良好程序結(jié)構(gòu)行之有效的方法之一.

本文將先大概講一下模塊化的方法和注意事項,最后將以初學者使用最廣的keil c編譯器為例,給出模塊化編程的詳細步驟。

模塊化程序設計應該理解以下概述:

(1) 模塊即是一個.c 文件和一個.h 文件的結(jié)合,頭文件(.h)中是對于該模塊接口的聲明;

這一條概括了模塊化的實現(xiàn)方法和實質(zhì):將一個功能模塊的代碼單獨編寫成一個.c文件,然后把該模塊的接口函數(shù)放在.h文件中.舉例:假如你用到液晶顯示,那么你可能會寫一個液晶驅(qū)動模塊,以實現(xiàn)字符、漢字和圖像的現(xiàn)實,命名為: led_device.c,該模塊的.c文件大體可以寫成:

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

* 液晶驅(qū)動模塊

*

* 文 件: lcd_device.c

* 編 寫 人: 小瓶蓋

* 描 述:液晶串行顯示驅(qū)動模塊,提供字符、漢字、和圖像的實現(xiàn)接口

* 編寫時間: 2009.07.03

* 版 本:1.2

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

#include …

//定義變量

?unsigned char value;//全局變量

//定義函數(shù)

//這是本模塊第一個函數(shù),起到延時作用,只供本模塊的函數(shù)調(diào)用,所以用到static關鍵字修飾

/********************延時子程序************************/

static void delay (uint us) //delay time

{}

//這是本模塊的第二個函數(shù),要在其他模塊中調(diào)用

/*********************寫字符程序**************************

** 功能:向LCD寫入字符

** 參數(shù):dat_comm 為1寫入的是數(shù)據(jù),為0寫入的是指令

content 為寫入的數(shù)字或指令

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

void wr_lcd (uchar dat_comm,uchar content)

{}

……

……

/***************************** END Files***********************************/

注:此處只寫出這兩個函數(shù),第一個延時函數(shù)的作用范圍是模塊內(nèi),第二個,它是其它模塊需要的。為了簡化,此處并沒有寫出函數(shù)體.

.h文件中給出模塊的接口.在上面的例子中,?向LCD寫入字符函數(shù):wr_lcd (uchar dat_comm,uchar content)就是一個接口函數(shù),因為其它模塊會調(diào)用它,那么.h文件中就必須將這個函數(shù)聲明為外部函數(shù)(使用extrun關鍵字修飾),另一個延時函數(shù):void delay (uint us)只是在本模塊中使用(本地函數(shù),用static關鍵字修飾),因此它是不需要放到.h文件中的。

.h文件格式如下:

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

* 液晶驅(qū)動模塊 頭文件

*

* 文 件: lcd_device.h

* 編 寫 人: 小瓶蓋

* 編寫時間: 2010.07.03

* 版 本:1.0

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

//聲明全局變量

extern unsigned char value;

//聲明接口函數(shù)

extern void wr_lcd (uchar dat_comm,uchar content); //向LCD寫入字符

……

/***************************** END Files***********************************/

這里注意三點:

1. 在keil 編譯器中,extern這個關鍵字即使不聲明,編譯器也不會報錯,且程序運行良好,但不保證使用其它編譯器也如此。強烈建議加上,養(yǎng)成良好的編程規(guī)范。

2. .c文件中的函數(shù)只有其它模塊使用時才會出現(xiàn)在.h文件中,像本地延時函數(shù)static void delay (uint us)即使出現(xiàn)在.h文件中也是在做無用功,因為其它模塊根本不去調(diào)用它,實際上也調(diào)用不了它(static關鍵字的限制作用)。

3.注意本句最后一定要加分號”;”,相信有不少同學遇到過這個奇怪的編譯器報錯: error C132: 'xxxx': not in formal parameter list,這個錯誤其實是.h的函數(shù)聲明的最后少了分號的緣故。

模塊的應用:假如需要在LCD菜單模塊lcd_menu.c中使用液晶驅(qū)動模塊lcd_device.c中的函數(shù)void wr_lcd (uchar dat_comm,uchar content),只需在LCD菜單模塊的lcd_menu.c文件中加入液晶驅(qū)動模塊的頭文件lcd_device.h即可.

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

* 液晶菜單模塊

*

* 文 件: lcd_menu.c

* 編 寫 人: 小瓶蓋

* 說 明:LCD菜單模塊,最多實現(xiàn)256級菜單,與硬件無關。

* 編寫時間: 2010.07.03

* 版 本:1.0

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

#include“l(fā)cd_device.h //包含液晶驅(qū)動程序頭文件,之后就可以在該.c文件中調(diào)用//lcd_device.h中的全局函數(shù),使用液晶驅(qū)動程序里的全局//變量(如果有的話)。

//調(diào)用向LCD寫入字符函數(shù)

wr_lcd (0x01,0x30);

//對全局變量賦值

value=0xff;

(2) 某模塊提供給其它模塊調(diào)用的外部函數(shù)及數(shù)據(jù)需在.h 中文件中冠以extern 關鍵字聲明;

這句話在上面的例子中已經(jīng)有體現(xiàn),即某模塊提供給其它模塊調(diào)用的外部函數(shù)和全局變量需在.h 中文件中冠以extern 關鍵字聲明,下面重點說一下全局變量的使用。使用模塊化編程的一個難點(相對于新手)就是全局變量的設定,初學者往往很難想通模塊與模塊公用的變量是如何實現(xiàn)的,常規(guī)的做法就是本句提到的,在.h文件中外部數(shù)據(jù)冠以extern關鍵字聲明。比如上例的變量value就是一個全局變量,若是某個模塊也使用這個變量,則和使用外部函數(shù)一樣,只需在使用的模塊.c文件中包含#include“l(fā)cd_device.h”即可。

另一種處理模塊間全局變量的方法來自于嵌入式操作系統(tǒng)uCOS-II,這個操作系統(tǒng)處理全局變量的方法比較特殊,也比較難以理解,但學會之后妙用無窮,這個方法只需用在頭文件中定義一次。方法為:

在定義所有全局變量(uCOS-II將所有全局變量定義在一個.h文件內(nèi))的.h頭文件中:

#ifdef xxx_GLOBALS

#define xxx_EXT

#else

#define xxx_EXT extern

#endif

.H 文件中每個全局變量都加上了xxx_EXT的前綴。xxx 代表模塊的名字。

該模塊的.C文件中有以下定義:

#define xxx_GLOBALS

#include "includes.h"

當編譯器處理.C文件時,它強制xxx_EXT(在相應.H文件中可以找到)為空,(因為xxx_GLOBALS已經(jīng)定義)。所以編譯器給每個全局變量分配內(nèi)存空間,而當編譯器處理其他.C 文件時,xxx_GLOBAL沒有定義,xxx_EXT 被定義為extern,這樣用戶就可以調(diào)用外部全局變量。為了說明這個概念,可以參見uC/OS_II.H,其中包括以下定義:

#ifdef OS_GLOBALS

#define OS_EXT

#else

#define OS_EXT extern

#endif

OS_EXT INT32U OSIdleCtr;

OS_EXT INT32U OSIdleCtrRun;

OS_EXT INT32U OSIdleCtrMax;

同時,uCOS_II.H 有中以下定義:

#define OS_GLOBALS

#include “includes.h”

當編譯器處理uCOS_II.C 時,它使得頭文件變成如下所示,因為OS_EXT 被設置為空。

INT32U OSIdleCtr;

INT32U OSIdleCtrRun;

INT32U OSIdleCtrMax;

這樣編譯器就會將這些全局變量分配在內(nèi)存中。當編譯器處理其他.C 文件時,頭文件變成了如下的樣子,因為OS_GLOBAL沒有定義,所以OS_EXT 被定義為extern。

extern INT32U OSIdleCtr;

extern INT32U OSIdleCtrRun;

extern INT32U OSIdleCtrMax;

在這種情況下,不產(chǎn)生內(nèi)存分配,而任何 .C文件都可以使用這些變量。這樣的就只需在 .H文件中定義一次就可以了。

(3) 模塊內(nèi)的函數(shù)和全局變量需在.c 文件開頭冠以static 關鍵字聲明;

這句話主要講述了關鍵字static的作用。Static是一個相當重要的關鍵字,他能對函數(shù)和變量做一些約束,而且可以傳遞一些信息。比如上例在LCD驅(qū)動模塊.c文件中定義的延時函數(shù)static void delay (uint us),這個函數(shù)冠以static修飾,一方面是限定了函數(shù)的作用范圍只是在本模塊中起作用,另一方面也給人傳達這樣的信息:該函數(shù)不會被其他模塊調(diào)用。下面詳細說一下這個關鍵字的作用,在C 語言中,關鍵字static 有三個明顯的作用:

1.在函數(shù)體,一個被聲明為靜態(tài)的變量在這一函數(shù)被調(diào)用過程中維持其值不變。

2.在模塊內(nèi)(但在函數(shù)體外),一個被聲明為靜態(tài)的變量可以被模塊內(nèi)所用函數(shù)訪問,但不能被模塊外其它函數(shù)訪問。它是一個本地的全局變

量。

3.在模塊內(nèi),一個被聲明為靜態(tài)的函數(shù)只可被這一模塊內(nèi)的其它函數(shù)調(diào)用。那就是,這個函數(shù)被限制在聲明它的模塊的本地范圍內(nèi)使用。

前兩個都比較容易理解,最后一個作用就是剛剛舉例中提到的延時函數(shù)(static void delay (uint us)),本地化函數(shù)是有相當好的作用的。

(4) 永遠不要在.h 文件中定義變量!

呵呵,似乎有點危言聳聽的感覺,但我想也不會有多少人會在.h文件中定義變量的。

比較一下代碼:

代碼一:

/*module1.h*/

int a = 5; /* 在模塊1 的.h 文件中定義int a */

/*module1 .c*/

#include "module1.h" /* 在模塊1 中包含模塊1 的.h 文件 */

/*module2 .c*/

#include "module1.h" /* 在模塊2 中包含模塊1 的.h 文件 */

/*module3 .c*/

#include "module1.h" /* 在模塊3 中包含模塊1 的.h 文件 */

以上程序的結(jié)果是在模塊1、2、3 中都定義了整型變量a,a 在不同的模塊中對應不同的地址元,這個世界上從來不需要這樣的程序。正確的做法是:

代碼二:

/*module1.h*/

extern int a; /* 在模塊1 的.h 文件中聲明int a */

/*module1 .c*/

#include "module1.h" /* 在模塊1 中包含模塊1 的.h 文件 */

int a = 5; /* 在模塊1 的.c 文件中定義int a */

/*module2 .c*/

#include "module1.h" /* 在模塊2 中包含模塊1 的.h 文件 */

/*module3 .c*/

#include "module1.h" /* 在模塊3 中包含模塊1 的.h 文件 */

這樣如果模塊1、2、3 操作a 的話,對應的是同一片內(nèi)存單元。

注:

一個嵌入式系統(tǒng)通常包括兩類(注意是兩類,不是兩個)模塊:

(1)硬件驅(qū)動模塊,一種特定硬件對應一個模塊;

(2)軟件功能模塊,其模塊的劃分應滿足低偶合、高內(nèi)聚的要求。

下面以keil C 編譯器為例,講一下模塊化編程的步驟。

下面這個程序分為三層,共7個模塊,共同為主程序服務(它們之間也會相互調(diào)用)。

程序的結(jié)構(gòu)圖如下所示:

程序主要模塊和功能簡介:

一. 底層驅(qū)動

1. 紅外鍵盤:程序通過紅外鍵盤進行操作。紅外鍵盤獨占定時器0和外部中斷0,以實現(xiàn)紅外解碼和鍵盤鍵值的識別。紅外鍵盤定義了五個按鍵,分別為上翻、下翻、左翻、右翻和確認鍵。

2. LCD液晶顯示:程序主要通過LCD顯示信息,LCD液晶顯示驅(qū)動提供顯示漢字、圖形和ASCII碼的函數(shù)接口。可以全屏、單行顯示漢字,任意位置顯示ASCII碼,還可以全屏、半屏顯示圖形。

二. 功能模塊

1. LCD菜單程序:菜單程序可以使人機交互更加方便、容易。本菜單程序的菜單級別深度受RAM大小的限制,每增加一級菜單將多消耗4字節(jié)的RAM。菜單程序主要完成菜單功能函數(shù)的調(diào)度,LCD顯示刷新。

2. 計算器程序:實現(xiàn)65536以內(nèi)的加、減、乘、除,超出范圍會出現(xiàn)溢出,溢出發(fā)生時,LCD顯示“錯誤:出現(xiàn)溢出”的錯誤提示,同時本次運算被忽略。對于負數(shù)會顯示“-”號,除數(shù)為零時LCD顯示“錯誤:除數(shù)為零”的錯誤提示。

3. 開機次數(shù)記憶程序:主要對基于IIC總線的EEPROM進行讀寫,單片機每次上電后,將開機次數(shù)寫入EEPROM.

4. 串口測試程序:進入該程序后,單片機向電腦發(fā)送字符串“Hello Word!”,發(fā)送數(shù)字24(以字符的形式顯示)。編寫此程序的目的是為了能夠方便的向電腦發(fā)送字符串和變量,便于程序的調(diào)試。串口占用串口資源,與頻率測量程序共享定時器1

5. 頻率測量:復用定時器1,占用外部中斷1,實現(xiàn)5~20KHZ頻率的測量.

三. 主程序

主程序主要完成程序的初始化,LCD菜單顯示,監(jiān)視鍵盤程序并根據(jù)鍵值更新菜單。

步驟為:

1.新建工程。

2.點擊File—New(或者點擊快捷圖標:),新建一個文檔。

3.點擊File—Save(或者點擊快捷圖標:),保存新建的文檔,在文件名后填寫LCD_device.c(液晶驅(qū)動模塊: LCD_device,提供顯示漢字、字符和圖像的接口),點擊確定。

在該文檔內(nèi)編寫LCD驅(qū)動程序。

4. 點擊File—New(或者點擊快捷圖標:),再新建一個文檔。

5. 點擊File—Save(或者點擊快捷圖標:),保存新建的文檔,在文件名后填寫LCD_device.h(液晶驅(qū)動模塊的頭文件,模塊的接口和全局變量在這里定義)。點擊確定。在該文檔中整理全局變量和接口函數(shù)。以上步驟之后的效果見下圖:

至此,液晶驅(qū)動模塊書寫完畢,可以對這個模塊單獨的調(diào)試。

6.重復以上步驟2~5,定義 紅外鍵盤模塊:key.c與key.h

菜單模塊:menu.c與menu.h

串口通信模塊:uart_.c與uart.h

計算器模塊:counter.c與counter.h

頻率測量模塊:mea_fre.c與mea_fre.h

開機次數(shù)記憶模塊:eepram.c與eepram.h

7.重復以上步驟2~3,定義主程序main.c

最終效果如下圖所示:

完成1~7個步驟后,有些小白就習慣性的點擊編譯按鈕了,這時候會出現(xiàn)兩個警告信息:

*** WARNING L1: UNRESOLVED EXTERNAL SYMBOL

*** WARNING L2: REFERENCE MADE TO UNRESOLVED EXTERNAL

這是因為你只是編寫好了程序模塊,卻沒有把他們加入到工程的緣故。

解決方法:在Project Workspace框中,右擊Source group 1文件夾,選擇Add Files to Group‘Source Group 1’,在彈出的對話框中添加你的.c文件即可。

遙想很久很久以前,我也對上面的兩個警告有過親身體會。那時候我還在大學,周圍有一大群的好哥們一起玩,想逃課逃課,想睡覺睡覺,現(xiàn)在…想起來只剩唏噓!!!

總結(jié)

以上是生活随笔為你收集整理的嵌入式编程之模块化编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 强伦人妻一区二区三区 | 一区二三区| 四季av在线一区二区三区 | 五月花成人网 | 国产成人宗合 | 欧美精品中文 | 无码人妻久久一区二区三区蜜桃 | 男女爱爱网站 | 无遮挡又爽又刺激的视频 | 91精品国产一区 | 天天草综合 | 亚洲一区二区三区在线看 | 99久久国产热无码精品免费 | 欧美激情免费在线 | 国产亚洲精品久久久久丝瓜 | 黄色小视频免费观看 | 久久婷婷五月综合色吧 | 亚洲国产一区二区a毛片 | 刘玥91精选国产在线观看 | 日韩色av| 小箩莉末发育娇小性色xxxx | 91tv在线观看| 69色综合| 美女黄色一级片 | 最新版天堂资源在线 | 国产精品成人99一区无码 | 亚洲加勒比在线 | 亚洲一区成人 | 久久久久人妻一区精品色欧美 | 午夜在线不卡 | 色婷婷色综合 | 日本青草视频 | 操综合 | 老熟女高潮喷水了 | 免费20分钟超爽视频 | 国产激情四射 | 在线免费观看污 | 韩国中文三级hd字幕 | 黄色免费在线播放 | 色吧av | 乱人伦中文字幕 | 最新欧美日韩 | 18欧美性xxxx极品hd | 欧美天堂在线视频 | 精品视频中文字幕 | 一级片久久 | 91丝袜美腿 | 中文字幕黑人 | 伊人www| 色又色| 伊人在线 | 无法忍受在线观看 | 欧美国产成人精品一区二区三区 | 国产宾馆自拍 | 国产精品爽爽久久久久久 | 午夜亚洲av永久无码精品 | 99午夜视频 | 日产欧产va高清 | 欧美不卡一区二区 | 亚洲色图 校园春色 | 诱人的乳峰奶水hd | 6996电视影片免费看 | 小视频在线观看 | 一区二区高清 | 一区二区不卡在线 | 美国黄色片网站 | 香蕉视频在线播放 | 国产欧美日韩三级 | 国产91精品一区二区麻豆亚洲 | 噜噜噜视频 | 久久婷婷一区二区 | 成年人精品视频 | 日韩黄色视屏 | 噼里啪啦动漫高清在线观看 | a级一级黄色片 | 国产八区 | 大尺度摸揉捏胸床戏视频 | 色综合影视 | 日韩av在线中文字幕 | 亚洲一区欧美 | 国产成人精品一区二区三区福利 | 国产精品久久久久久亚洲av | 我要看一级黄色片 | 久久中文字幕网 | 亚洲国产亚洲 | 亚洲一区二区三区不卡视频 | 亚洲激情 | 亚洲无套 | 日本黄色xxx | 女人夜夜春| 91av爱爱| 久久爱综合网 | 国产女主播在线观看 | 久草视频免费在线观看 | 日韩porn| www伊人 | 都市激情校园春色 | 毛片亚洲av无码精品国产午夜 | 国产丝袜在线 |