從微控制器初學者到工程師的經驗之談

2021-04-03 18:34:21 字數 4484 閱讀 3362

下面讓我們揭開模組化神秘面紗,一窺其真面目。

c語言原始檔 *.c

提到c語言原始檔,大家都不會陌生。因為我們平常寫的程式**幾乎都在這個xx.c檔案裡面。

編譯器也是以此檔案來進行編譯並生成相應的目標檔案。作為模組化程式設計的組成基礎,我們所要實現的所有功能的源**均在這個檔案裡。理想的模組化應該可以看成是乙個黑盒子。

即我們只關心模組提供的功能,而不管模組內部的實現細節。好比我們買了一部手機,我們只需要會用手機提供的功能即可,不需要知曉它是如何把簡訊發出去的,如何響應我們按鍵的輸入,這些過程對我們使用者而言,就是是乙個黑盒子。

在大規模程式開發中,乙個程式由很多個模組組成,很可能,這些模組的編寫任務被分配到不同的人。而你在編寫這個模組的時候很可能就需要利用到別人寫好的模組的藉口,這個時候我們關心的是,它的模組實現了什麼樣的介面,我該如何去呼叫,至於模組內部是如何組織的,對於我而言,無需過多關注。而追求介面的單一性,把不需要的細節盡可能對外部遮蔽起來,正是我們所需要注意的地方。

c語言標頭檔案 *.h

談及到模組化程式設計,必然會涉及到多檔案編譯,也就是工程編譯。在這樣的乙個系統中,往往會有多個c檔案,而且每個c檔案的作用不盡相同。在我們的c檔案中,由於需要對外提供介面,因此必須有一些函式或者是變數提供給外部其它檔案進行呼叫。

假設我們有乙個lcd.c檔案,其提供最基本的lcd的驅動函式

lcdputchar(char cnewvalue) ; //在當前位置輸出乙個字元

而在我們的另外乙個檔案中需要呼叫此函式,那麼我們該如何做呢?

標頭檔案的作用正是在此。可以稱其為乙份介面描述檔案。其檔案內部不應該包含任何實質性的函式**。

我們可以把這個標頭檔案理解成為乙份說明書,說明的內容就是我們的模組對外提供的介面函式或者是介面變數。同時該檔案也包含了一些很重要的巨集定義以及一些結構體的資訊,離開了這些資訊,很可能就無法正常使用介面函式或者是介面變數。但是總的原則是:

不該讓外界知道的資訊就不應該出現在標頭檔案裡,而外界呼叫模組內介面函式或者是介面變數所必須的資訊就一定要出現在標頭檔案裡,否則,外界就無法正確的呼叫我們提供的介面功能。因而為了讓外部函式或者檔案呼叫我們提供的介面功能,就必須包含我們提供的這個介面描述檔案----即標頭檔案。同時,我們自身模組也需要包含這份模組標頭檔案(因為其包含了模組原始檔中所需要的巨集定義或者是結構體),好比我們平常所用的檔案都是一式

三份一樣,模組本身也需要包含這個標頭檔案。

下面我們來定義這個標頭檔案,一般來說,標頭檔案的名字應該與原始檔的名字保持一致,這樣我們便可以清晰的知道哪個標頭檔案是哪個原始檔的描述。

於是便得到了lcd.c的標頭檔案lcd.h 其內容如下。

#ifndef _lcd_h_

#define _lcd_h_

extern lcdputchar(char cnewvalue) ;

#endif

這與我們在原始檔中定義函式時有點類似。不同的是,在其前面新增了extern 修飾符表明其是乙個外部函式,可以被外部其它模組進行呼叫。

#ifndef _lcd_h_

#define _lcd_h_

#endif

這個幾條條件編譯和巨集定義是為了防止重複包含。假如有兩個不同原始檔需要呼叫lcdputchar(char cnewvalue)這個函式,他們分別都通過#include 「lcd.h」把這個標頭檔案包含了進去。

在第乙個原始檔進行編譯時候,由於沒有定義過 _lcd_h_ 因此 #ifndef _lcd_h_ 條件成立,於是定義_lcd_h_ 並將下面的宣告包含進去。在第二個檔案編譯時候,由於第乙個檔案包含時候,已經將_lcd_h_定義過了。因此#ifndef _lcd_h_ 不成立,整個標頭檔案內容就沒有被包含。

假設沒有這樣的條件編譯語句,那麼兩個檔案都包含了extern lcdputchar(char cnewvalue) ; 就會引起重複包含的錯誤。

不得不說的typedef

很多朋友似乎了習慣程式中利用如下語句來對資料型別進行定義

#define uint unsigned int

#define uchar unsigned char

然後在定義變數的時候直接這樣使用

uint g_ntimecounter = 0 ;

不可否認,這樣確實很方便,而且對於移植起來也有一定的方便性。但是考慮下面這種情況你還會這麼認為嗎?

#define pint unsigned int * //定義unsigned int 指標型別

pint g_nptimecounter, g_nptimestate ;

那麼你到底是定義了兩個unsigned int 型的指標變數,還是乙個指標變數,乙個整形變數呢?而你的初衷又是什麼呢,想定義兩個unsigned int 型的指標變數嗎?如果是這樣,那麼估計過不久就會到處抓狂找錯誤了。

慶幸的是c語言已經為我們考慮到了這一點。typedef 正是為此而生。為了給變數起乙個別名我們可以用如下的語句

typedef unsigned int uint16 ; //給指向無符號整形變數起乙個別名 uint16

typedef unsigned int * puint16 ; //給指向無符號整形變數指標起乙個別名 puint16

在我們定義變數時候便可以這樣定義了:

uint16 g_ntimecounter = 0 ; //定義乙個無符號的整形變數

puint16 g_nptimecounter ; //定義乙個無符號的整形變數的指標在我們使用51微控制器的c語言程式設計的時候,整形變數的範圍是16位,

而在基於32的微處理下的整形變數是32位。倘若我們在8位微控制器下編寫的一些**想要移植到32位的處理器上,那麼很可能我們就需要在原始檔中到處修改變數的型別定義。這是一件龐大的工作,為了考慮程式的可移植性,在一開始,我們就應該養成良好的習慣,用變數的別名進行定義。

如在8位微控制器的平台下,有如下乙個變數定義

uint16 g_ntimecounter = 0 ;

如果移植32微控制器的平台下,想要其的範圍依舊為16位。

可以直接修改uint16 的定義,即

typedef unsigned short int uint16 ;

這樣就可以了,而不需要到原始檔處處尋找並修改。

將常用的資料型別全部採用此種方法定義,形成乙個標頭檔案,便於我們以後程式設計直接呼叫。

檔名 macroandconst.h

其內容如下:

#ifndef _macro_and_const_h_

#define _macro_and_const_h_

typedef unsigned int uint16;

typedef unsigned int uint;

typedef unsigned int uint;

typedef unsigned int uint16;

typedef unsigned int word;

typedef unsigned int word;

typedef int int16;

typedef int int16;

typedef unsigned long uint32;

typedef unsigned long uint32;

typedef unsigned long dword;

typedef unsigned long dword;

typedef longint32;

typedef longint32;

typedef signed char int8;

typedef signed char int8;

typedef unsigned char byte;

typedef unsigned char byte;

typedef unsigned char uchar;

typedef unsigned char uint8;

typedef unsigned char uint8;

typedef unsigned char bool;

#endif

至此,似乎我們對於原始檔和標頭檔案的分工以及模組化程式設計有那麼一點概念了。那麼讓我們趁熱打鐵,將上一章的我們編寫的led閃爍函式進行模組劃分並重新組織進行編譯。

在上一章中我們主要完成的功能是p0口所驅動的led以1hz的頻率閃爍。其中用到了定時器,以及led驅動模組。因而我們可以簡單的將整個工程分成三個模組,定時器模組,led模組,以及主函式對應的檔案關係如下

main.c

timer.c --?timer.h

led.c --?led.h

在開始重新編寫我們的程式之前,先給大家講一下如何在keil中建立工程模板吧,這個模板是我一直沿用至今。希望能夠給大家一點啟發。

下面的內容就主要以**為主了。同時輔以少量文字說明。

致微控制器初學者的話

我經常想,什麼樣的51學習板才真正適合初學的朋友,是否如 大賣家所言,得有繼電器,得有ad da,得有彩屏 得有點陣 電機,外面最好還配個箱子。因為靠近大學城,我身邊有很多如現在正在看此文章的您一樣的朋友,你們需要的到底是一塊什麼樣的板子?我有個朋友是教師,每年都能接幾個專案做做,全是c 51為主控...

微控制器初學者幾個不易掌握的概念

一 匯流排 我們知道,乙個電路總是由元器件通過電線連線而成的,在模擬電路中,連連線並不成為乙個問題,因為各器件間一般是序列關係,各器件之間的連線並不很多,但計算機電路卻不一樣,它是以微處理器為核心,各器件都要與微處理器相連,各器件之間的工作必須相互協調?所以就需要的連線就很多了,如果仍如同模擬電路一...

和初學者談談如何學好微控制器程式設計技術

當今時代,是乙個新技術層出不窮的時代。在電子領域,尤其是自動化智慧型控制領域,傳統的分立元件或數字邏輯電路構成的控制系統正以前所未見的速度被微控制器智慧型控制系統所取代。大部分的高等工科學校都已開設了微控制器課程。微控制器具有體積小 功能強 成本低 應用面廣等優點,可以說,智慧型控制與自動控制的核心...