前言
最近空閑時(shí)間比較多,準(zhǔn)備說說STC8A8K64S4A12開發(fā)板。 實(shí)驗(yàn)做起來——先從GPIO點(diǎn)燈開始。
一、硬件電路原理
1.開發(fā)板指示燈硬件電路
LED(Light Emitting Diode)是發(fā)光二極管的簡稱,在很多設(shè)備上常用它來做為一種簡單的人機(jī)接口,如網(wǎng)卡、路由器等通過LED向用戶指示設(shè)備的不同工作狀態(tài)。所以,我們習(xí)慣把這種用于指示狀態(tài)的LED稱為LED指示燈。
STC8A8K64S4A12開發(fā)板上設(shè)計(jì)了4個(gè)LED指示燈,我們可以通過編程驅(qū)動(dòng)LED指示燈點(diǎn)亮、熄滅、閃爍,從而達(dá)到狀態(tài)指示的目的,LED指示燈驅(qū)動(dòng)電路如下圖所示。
圖1:LED指示燈驅(qū)動(dòng)電路
LED指示燈驅(qū)動(dòng)電路是一個(gè)很常見、簡單的電路,同時(shí)它也是一個(gè)典型的單元電路,對于初學(xué)者來說,類似常用的典型電路必須要掌握,不但要知其然、還要知其所以然。
接下來,我們來分析一下這個(gè)簡單的LED指示燈驅(qū)動(dòng)電路。
LED驅(qū)動(dòng)電路設(shè)計(jì)的時(shí)候,要考慮兩個(gè)方面:控制方式和限流電阻的選取。
2.控制方式
LED指示燈控制方式分為高電平有效和低電平有效兩種,高電平有效是單片機(jī)GPIO輸出高電平時(shí)點(diǎn)亮LED,低電平有效是單片機(jī)GPIO輸出低電平時(shí)點(diǎn)亮LED。
2.1.低電平有效的控制方式
LED控制-低電平有效原理
低電平有效控制方式中,當(dāng)單片機(jī)的GPIO輸出低電平(邏輯0)的時(shí)候,LED和電阻R上的壓降等于(VCC-VCCIO = 3.3V),這時(shí)候,因?yàn)榇嬖趬航?,同時(shí),這個(gè)電路是閉合回路,這就達(dá)到了電流產(chǎn)生的兩個(gè)要素,LED上會(huì)有電流流過,LED被點(diǎn)亮。
當(dāng)單片機(jī)的GPIO輸出高電平(邏輯1)的時(shí)候,LED和電阻R上的壓降等于(VCC-VCCIO = 0V),這時(shí)候,因?yàn)長ED上沒有壓降,當(dāng)然不會(huì)有電流流過,所以LED熄滅。
2.2.高電平有效的控制方式
圖3:LED控制-高電平有效原理
高電平有效控制方式中,由單片機(jī)的GPIO輸出電流驅(qū)動(dòng)LED,當(dāng)單片機(jī)的GPIO輸出高電平(邏輯1)的時(shí)候,LED上存在壓降,因?yàn)殡娐肥情]合回路,所以會(huì)有電流流過,這時(shí)LED被點(diǎn)亮,但要注意,單片機(jī)的GPIO要能提供足夠的輸出電流,否則,電流過小,會(huì)導(dǎo)致LED亮度很弱。
當(dāng)單片機(jī)的GPIO輸出低電平(邏輯0)的時(shí)候,LED和電阻R上的壓降等于0V,這時(shí)候,LED上沒有電流流過,LED熄滅。
2.3.選擇哪種方式來控制LED
絕大多數(shù)情況下,我們會(huì)選擇使用低電平有效的控制方式,如艾克姆科技STC8A8K64S4A12開發(fā)板中的LED指示燈就是低電平有效。這樣設(shè)計(jì)指示燈驅(qū)動(dòng)電路的好處是:
① 單片機(jī)GPIO口低電平時(shí)的灌入電流一般比高電平時(shí)的拉電流要大,能提供足夠的電流驅(qū)動(dòng)LED。
② 單片機(jī)上電或復(fù)位啟動(dòng)時(shí),GPIO口一般都是高阻輸入,用低電平有效的控制方式可以確保LED在上電或復(fù)位啟動(dòng)時(shí)處于熄滅狀態(tài)。
3.LED限流電阻的選取
3.1.限流電阻的計(jì)算
圖4:LED限流電阻計(jì)算
由上圖可以看出,LED限流電阻的計(jì)算公式如下:
其中,VCC=3.3V,VF是LED的正向壓降,LED的數(shù)據(jù)手冊都會(huì)給出正向電流為2mA時(shí)測試的VF的范圍,下圖是一款0805 LED的實(shí)物圖和參數(shù)。在參數(shù)表中可以看到正向電流為2mA時(shí)VF最小值是2.5V,典型值是2.7V,最大值是3.6V。
圖5:封裝0805的LED
圖6:0805 LED參數(shù)圖
計(jì)算時(shí)VF的值可以用典型值來進(jìn)行估算,對于電流,需要根據(jù)經(jīng)驗(yàn)值和對LED亮度的要求相結(jié)合來確定,一般經(jīng)驗(yàn)值是(1~5)mA,不過要注意,只要亮度符合自己的要求,電流低于1mA也沒有任何問題。
電流為1mA時(shí)限流電阻值計(jì)算如下:
3.2.限流電阻的選擇
根據(jù)上一節(jié)對限流電阻計(jì)算公式的描述及對選擇的封裝0805的指示燈參數(shù)的了解,計(jì)算出供電3.3V電流1mA時(shí)的限流電阻理論值是600Ω,供電5V電流1mA時(shí)的限流電阻理論值是2.3KΩ,為保證供電為3.3V時(shí)指示燈夠亮但同時(shí)5V供電指示燈又不宜過亮,選擇一個(gè)比較常見的阻值2K作為限流電阻。
還有一點(diǎn)需要強(qiáng)調(diào)的是,不同顏色的指示燈在即使同一亮度時(shí)所需的限流電阻不一定是相同的。這也是為什么有些產(chǎn)品的面板上有不同顏色的指示燈,各指示燈所使用的限流電阻不一樣的原因。
4.STC8A8K64S4A12系列單片機(jī)GPIO口
STC8A8K64S4A12系列單片機(jī)GPIO口數(shù)量取決于芯片引腳的個(gè)數(shù),芯片引腳個(gè)數(shù)和芯片封裝密切相關(guān)。正常情況下,GPIO口數(shù)量是所選擇單片機(jī)引腳個(gè)數(shù)減去5,因?yàn)閱纹瑱C(jī)需要2個(gè)引腳作為供電引腳(電源正VCC、電源負(fù)GND),ADC外設(shè)會(huì)占用3個(gè)引腳(電源正ADC_Avcc、電源負(fù)ADC_Agnd、參考電壓AVref)。
4.1.芯片封裝
封裝,Package,是把集成電路裝配為芯片最終產(chǎn)品的過程,簡單地說,就是把Foundry生產(chǎn)出來的集成電路裸片(Die)放在一塊起到承載作用的基板上,把管腳引出來,然后固定包裝成為一個(gè)整體。
STC8A8K64S4A12系列有多種封裝,廠家批量常見的芯片封裝是:LQFP44、LQFP48和LQFP64S。
4.2.GPIO口工作模式
STC8A8K64S4A12系列單片機(jī)所有GPIO口均有4種工作模式:準(zhǔn)雙向口/弱上拉(標(biāo)準(zhǔn)8051輸出口模式)、推挽輸出/強(qiáng)上拉、高阻輸入(電流既不能流入也不能流出)、開漏輸出。下面針對內(nèi)部結(jié)構(gòu)圖進(jìn)行分析。
■ 準(zhǔn)雙向口/弱上拉模式:
圖7:GPIO準(zhǔn)雙向口/弱上拉模式內(nèi)部框圖
1)準(zhǔn)雙向口(弱上拉) 輸出類型可用作輸出和輸入功能而不需要重新配置端口輸出狀態(tài)。這是因?yàn)闇?zhǔn)雙向口有3個(gè)上拉晶體管可適應(yīng)輸入輸出不同的需要。
2)手冊中有這樣一句話:準(zhǔn)雙向口(弱上拉)在讀外部狀態(tài)前,要先鎖存為‘1’,才可讀到外部正確的狀態(tài)。下圖分別就鎖存數(shù)據(jù)為‘1’和‘0’時(shí)進(jìn)行了分析。
圖8:GPIO準(zhǔn)雙向口/弱上拉模式內(nèi)部框圖分析
3)由上圖分析可知,準(zhǔn)雙向口(弱上拉)在讀外部狀態(tài)前,如果鎖存為‘0’,則GPIO引腳狀態(tài)被固定,無法讀到外部正確的狀態(tài)。
■ 推挽輸出/強(qiáng)上拉模式:
圖9:GPIO推挽輸出/強(qiáng)上拉模式內(nèi)部框圖
1)強(qiáng)推挽輸出配置的下拉結(jié)構(gòu)與開漏輸出以及準(zhǔn)雙向口的下拉結(jié)構(gòu)相同,但當(dāng)鎖存器為1時(shí)可提供持續(xù)的強(qiáng)上拉。所以,推挽輸出一般用于需要更大驅(qū)動(dòng)電流的情況。
2)在控制LED時(shí),如果采用的是高電平有效的控制方式,則控制LED的單片機(jī)GPIO口必須配置成推挽輸出/強(qiáng)上拉模式方可。
■ 高阻輸入模式:
圖10:GPIO高阻輸入模式內(nèi)部框圖
1)因帶有一個(gè)施密特觸發(fā)輸入以及一個(gè)干擾抑制電路,GPIO配置為高阻輸入時(shí),電流既不能流入也不能流出GPIO口。
2)在很多STC相關(guān)的文檔中有說的高阻態(tài)即是GPIO口被設(shè)置了高阻輸入模式。
■ 開漏輸出模式:
圖11:GPIO開漏輸出模式內(nèi)部框圖
1)開漏模式既可以讀外部狀態(tài)也可以對外輸出高電平或低電平。
2)如果要正確讀外部狀態(tài)或需要對外輸出高電平時(shí),需外加上拉電阻。
二、軟件編寫
1.GPIO寄存器匯集
STC8A8K64S4A12系列單片機(jī)提供了40個(gè)用于操作GPIO的寄存器,如下表所示:
表2:
2.寄存器解析
首先普及一個(gè)常用知識點(diǎn):為什么說STC8A8K64S4A12系列單片機(jī)是8位單片機(jī)呢?這個(gè)8位指的是什么?
一般來說某個(gè)單片機(jī)或微處理器是幾位,指的是“機(jī)器字長”。每個(gè)單片機(jī)或微處理器最基本的功能是算術(shù)邏輯運(yùn)算,而算術(shù)邏輯運(yùn)算的主要部件是“算術(shù)邏輯單元(ALU)”。機(jī)器字長即是指ALU的數(shù)據(jù)位寬,也就是指令能直接處理的二進(jìn)制位數(shù)。
通常單片機(jī)或微處理器的寄存器的位寬等于ALU的位寬,所以一般可通過識別單片機(jī)或微處理器寄存器的位寬來確定該單片機(jī)或微處理器是多少位的。我們所接觸的STC的單片機(jī),其寄存器都是8位的,所以STC的單片機(jī)都是8位的單片機(jī)。以后學(xué)習(xí)STM32F103系列的微處理器,其寄存器是32位的,所以會(huì)說STM32F103系列微處理器是32位的。
2.1.端口數(shù)據(jù)寄存器
下圖是對端口數(shù)據(jù)寄存器P0、P1、P2、P3、P4、P5、P6、P7的描述,端口數(shù)據(jù)寄存器各位代表對應(yīng)端口的IO口,比如,P7端口數(shù)據(jù)寄存器B0位代表P7.0口,B7位代表P7.7口。
圖12:端口數(shù)據(jù)寄存器
2.2.端口配置寄存器
端口配置寄存器PnM1和PnM0都是8位的寄存器,PnM1和PnM0寄存器必須組合使用才能正確地配置IO口工作模式。
STC8A8K64S4A12系列單片機(jī)所有GPIO口均有4種工作模式:準(zhǔn)雙向口/弱上拉(標(biāo)準(zhǔn)8051輸出口模式)、推挽輸出/強(qiáng)上拉、高阻輸入(電流既不能流入也不能流出)、開漏輸出。每個(gè)GPIO口工作模式由PnM1和PnM0寄存器中的相應(yīng)位控制。如下圖。
圖13:GPIO端口配置
3.GPIO驅(qū)動(dòng)LED實(shí)驗(yàn)(寄存器版本)
3.1.頭文件引用和路徑設(shè)置
■ 需要宏定義部分及引用的頭文件
因?yàn)樵凇癿ain.c”文件中使用了STC8的頭文件“STC8.H”,所以需要引用下面的頭文件。在頭文件“STC8.H”中需要確定主時(shí)鐘取值,所以宏定義主時(shí)鐘值。
1.#define uint16 unsigned int
2.#define uint8 unsigned char
在程序設(shè)計(jì)中會(huì)用到定義變量的類型,為了定義變量方便,將較為復(fù)雜的“unsigned int”和“unsigned char ”進(jìn)行了宏定義。
#define uint16 unsigned int
#define uint8 unsigned char
這樣,再定義變量時(shí)可直接使用“uint16”和“uint8”來取代“unsigned int”和“unsigned char ”即可。
■ 需要包含的頭文件路徑
本例需要包含的頭文件路徑如下表:
MDK中點(diǎn)擊魔術(shù)棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。
圖14:添加頭文件包含路徑
3.2.編寫代碼
首先介紹下毫秒級的延時(shí)函數(shù)。控制指示燈亮和滅需要中間有足夠的間隔時(shí)間,這個(gè)間隔一般通過延時(shí)函數(shù)實(shí)現(xiàn)。微秒級的延時(shí)時(shí)間很難控制,這和主頻大小及其精度有密切關(guān)系。但毫秒級的延時(shí)還是可以控制的,下面給出在11.0592MHZ下的毫秒延時(shí)函數(shù),僅供參考。
代碼清單:毫秒延時(shí)函數(shù)
1./**************************************
2.功能描述:延時(shí)函數(shù)
3.入口參數(shù):uint16 x ,該值為1時(shí),延時(shí)1ms
4.返回值:無
5.***************************************/
6.void delay_ms(uint16 x)
7.{
8. uint16 j,i;
9. for(j=0;j
在對端口數(shù)據(jù)寄存器介紹時(shí)我們簡單介紹過控制單片機(jī)GPIO的過程。需要再說明的地方是關(guān)于兩個(gè)關(guān)鍵字“sfr”和“sbit”。
sfr是Keil C51為能直接訪問51內(nèi)核單片機(jī)中的SFR而提供了一個(gè)關(guān)鍵詞,其用法是:
1)sfrt 變量名=地址值。
sbit是定義特殊功能寄存器的位變量。其用法有三種:
1)sbit 位變量名=地址值。
2)sbit 位變量名=SFR名稱^變量位地址值。
3)sbit 位變量名=SFR地址值^變量位地址值。
程序清單:頭文件“STC8.H”定義P0端口部分
1.sfr P7 = 0Xf8;
2.sbit P70 = P7^0;
3.sbit P71 = P7^1;
4.sbit P72 = P7^2;
5.sbit P73 = P7^3;
6.sbit P74 = P7^4;
7.sbit P75 = P7^5;
8.sbit P76 = P7^6;
9.sbit P77 = P7^7;
}
然后,在主函數(shù)中先對P7.2口進(jìn)行模式配置,針對P7.2口是被配置了準(zhǔn)雙向口,后主循環(huán)中將用戶指示燈D3點(diǎn)亮,延時(shí)200ms,再熄滅,再延時(shí)200ms的過程,這樣可觀察到指示燈D3不停閃爍的現(xiàn)象。
代碼清單:主函數(shù)
1.int main()
2.{
3. P7M1 &= 0xFB; P7M0 &= 0xFB; //設(shè)置P7.2為準(zhǔn)雙向口
4. // P7M1 &= 0xFB; P7M0 |= 0x04; //設(shè)置P7.2為推挽輸出
5. // P7M1 |= 0x04; P7M0 &= 0xFB; //設(shè)置P7.2為高阻輸入
6. // P7M1 |= 0x04; P7M0 |= 0x04; //設(shè)置P7.2為開漏輸出
7.
8. while(1)
9. {
10. P72=0; //控制P7.2端口輸出低電平,點(diǎn)亮用戶指示燈D3
11. delay_ms(200);
12. P72=1; //控制P7.2端口輸出高電平,熄滅用戶指示燈D3
13. delay_ms(200);
14. }
15.}
4.GPIO驅(qū)動(dòng)LED實(shí)驗(yàn)(庫函數(shù)版本)
4.1.工程需要用到的c文件
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
該GPIO.c是STC官方提供的有關(guān)GPIO配置的函數(shù)庫。
4.2.頭文件引用和路徑設(shè)置
■ 需要引用的頭文件
因?yàn)樵凇癿ain.c”文件中使用了GPIO相關(guān)的庫,所以需要引用下面的頭文件。
1.#include "GPIO.h"
■ 需要包含的頭文件路徑
本例需要包含的頭文件路徑如下表:
MDK中點(diǎn)擊魔術(shù)棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。
圖15:添加頭文件包含路徑
4.3.編寫代碼
首先在GPIO口初始化函數(shù)中調(diào)用庫函數(shù)GPIO_Inilize完成P7.2口的工作模式配置,即配置P7.2為準(zhǔn)雙向口。
代碼清單:GPIO口初始化函數(shù)
1./**************************************
2.功能描述:GPIO口初始化
3.入口參數(shù):無
4.返回值:無
5.***************************************/
6.void GPIO_config(void)
7.{
8. GPIO_InitTypeDef GPIO_InitStructure;
9.
10. //設(shè)置P7.2口工作模式
11. GPIO_InitStructure.Mode=GPIO_PullUp; //配置P7.2口為準(zhǔn)雙向口
12. //GPIO_InitStructure.Mode=GPIO_OUT_PP; //配置P7.2口為推挽輸出(強(qiáng)上拉)
13. //GPIO_InitStructure.GPIO_HighZ; //配置P7.2口為高阻輸入
14. //GPIO_InitStructure.Mode=GPIO_OUT_OD; //配置P7.2口為開漏輸出
15. GPIO_InitStructure.Pin=GPIO_Pin_2;
16. GPIO_Inilize(GPIO_P7,&GPIO_InitStructure);
17.
18.}
打開庫函數(shù)GPIO_Inilize后會(huì)發(fā)現(xiàn),配置P7.2口實(shí)際最終操作還是P0M0和P0M1寄存器。代碼如下。
程序清單:頭文件“GPIO.c”定義GPIO初始化庫函數(shù)
1.//========================================================================
2.// 函數(shù): uint8 GPIO_Inilize(uint8 GPIO, GPIO_InitTypeDef *GPIOx)
3.// 描述: 初始化IO口.
4.// 參數(shù): GPIOx: 結(jié)構(gòu)參數(shù),請參考gpio.h里的定義.
5.// 返回: 成功返回0, 空操作返回1,錯(cuò)誤返回2.
6.//========================================================================
7.uint8 GPIO_Inilize(uint8 GPIO, GPIO_InitTypeDef *GPIOx)
8.{
9. if(GPIO > GPIO_P7) return 1; //空操作
10. if(GPIOx->Mode > GPIO_OUT_PP) return 2; //錯(cuò)誤
11.
12. if(GPIO == GPIO_P0)
13. {
14. if(GPIOx->Mode == GPIO_PullUp) P0M1 &= ~GPIOx->Pin, P0M0 &= ~GPIOx->Pin; //上拉準(zhǔn)雙向口
15. if(GPIOx->Mode == GPIO_HighZ) P0M1 |= GPIOx->Pin, P0M0 &= ~GPIOx->Pin; //浮空輸入
16. if(GPIOx->Mode == GPIO_OUT_OD) P0M1 |= GPIOx->Pin, P0M0 |= GPIOx->Pin; //開漏輸出
17. if(GPIOx->Mode == GPIO_OUT_PP) P0M1 &= ~GPIOx->Pin, P0M0 |= GPIOx->Pin; //推挽輸出
18. }
19. if(GPIO == GPIO_P1)
20. {
21. if(GPIOx->Mode == GPIO_PullUp) P1M1 &= ~GPIOx->Pin, P1M0 &= ~GPIOx->Pin; //上拉準(zhǔn)雙向口
22. if(GPIOx->Mode == GPIO_HighZ) P1M1 |= GPIOx->Pin, P1M0 &= ~GPIOx->Pin; //浮空輸入
23. if(GPIOx->Mode == GPIO_OUT_OD) P1M1 |= GPIOx->Pin, P1M0 |= GPIOx->Pin; //開漏輸出
24. if(GPIOx->Mode == GPIO_OUT_PP) P1M1 &= ~GPIOx->Pin, P1M0 |= GPIOx->Pin; //推挽輸出
25. }
26. if(GPIO == GPIO_P2)
27. {
28. if(GPIOx->Mode == GPIO_PullUp) P2M1 &= ~GPIOx->Pin, P2M0 &= ~GPIOx->Pin; //上拉準(zhǔn)雙向口
29. if(GPIOx->Mode == GPIO_HighZ) P2M1 |= GPIOx->Pin, P2M0 &= ~GPIOx->Pin; //浮空輸入
30. if(GPIOx->Mode == GPIO_OUT_OD) P2M1 |= GPIOx->Pin, P2M0 |= GPIOx->Pin; //開漏輸出
31. if(GPIOx->Mode == GPIO_OUT_PP) P2M1 &= ~GPIOx->Pin, P2M0 |= GPIOx->Pin; //推挽輸出
32. }
33. if(GPIO == GPIO_P3)
34. {
35. if(GPIOx->Mode == GPIO_PullUp) P3M1 &= ~GPIOx->Pin, P3M0 &= ~GPIOx->Pin; //上拉準(zhǔn)雙向口
36. if(GPIOx->Mode == GPIO_HighZ) P3M1 |= GPIOx->Pin, P3M0 &= ~GPIOx->Pin; //浮空輸入
37. if(GPIOx->Mode == GPIO_OUT_OD) P3M1 |= GPIOx->Pin, P3M0 |= GPIOx->Pin; //開漏輸出
38. if(GPIOx->Mode == GPIO_OUT_PP) P3M1 &= ~GPIOx->Pin, P3M0 |= GPIOx->Pin; //推挽輸出
39. }
40. if(GPIO == GPIO_P4)
41. {
42. if(GPIOx->Mode == GPIO_PullUp) P4M1 &= ~GPIOx->Pin, P4M0 &= ~GPIOx->Pin; //上拉準(zhǔn)雙向口
43. if(GPIOx->Mode == GPIO_HighZ) P4M1 |= GPIOx->Pin, P4M0 &= ~GPIOx->Pin; //浮空輸入
44. if(GPIOx->Mode == GPIO_OUT_OD) P4M1 |= GPIOx->Pin, P4M0 |= GPIOx->Pin; //開漏輸出
45. if(GPIOx->Mode == GPIO_OUT_PP) P4M1 &= ~GPIOx->Pin, P4M0 |= GPIOx->Pin; //推挽輸出
46. }
47. if(GPIO == GPIO_P5)
48. {
49. if(GPIOx->Mode == GPIO_PullUp) P5M1 &= ~GPIOx->Pin, P5M0 &= ~GPIOx->Pin; //上拉準(zhǔn)雙向口
50. if(GPIOx->Mode == GPIO_HighZ) P5M1 |= GPIOx->Pin, P5M0 &= ~GPIOx->Pin; //浮空輸入
51. if(GPIOx->Mode == GPIO_OUT_OD) P5M1 |= GPIOx->Pin, P5M0 |= GPIOx->Pin; //開漏輸出
52. if(GPIOx->Mode == GPIO_OUT_PP) P5M1 &= ~GPIOx->Pin, P5M0 |= GPIOx->Pin; //推挽輸出
53. }
54. if(GPIO == GPIO_P6)
55. {
56. if(GPIOx->Mode == GPIO_PullUp) P6M1 &= ~GPIOx->Pin, P6M0 &= ~GPIOx->Pin; //上拉準(zhǔn)雙向口
57. if(GPIOx->Mode == GPIO_HighZ) P6M1 |= GPIOx->Pin, P6M0 &= ~GPIOx->Pin; //浮空輸入
58. if(GPIOx->Mode == GPIO_OUT_OD) P6M1 |= GPIOx->Pin, P6M0 |= GPIOx->Pin; //開漏輸出
59. if(GPIOx->Mode == GPIO_OUT_PP) P6M1 &= ~GPIOx->Pin, P6M0 |= GPIOx->Pin; //推挽輸出
60. }
61. if(GPIO == GPIO_P7)
62. {
63. if(GPIOx->Mode == GPIO_PullUp) P7M1 &= ~GPIOx->Pin, P7M0 &= ~GPIOx->Pin; //上拉準(zhǔn)雙向口
64. if(GPIOx->Mode == GPIO_HighZ) P7M1 |= GPIOx->Pin, P7M0 &= ~GPIOx->Pin; //浮空輸入
65. if(GPIOx->Mode == GPIO_OUT_OD) P7M1 |= GPIOx->Pin, P7M0 |= GPIOx->Pin; //開漏輸出
66. if(GPIOx->Mode == GPIO_OUT_PP) P7M1 &= ~GPIOx->Pin, P7M0 |= GPIOx->Pin; //推挽輸出
67. }
68. return 0; //成功
}
然后,在主函數(shù)中先調(diào)用GPIO口初始化函數(shù),后主循環(huán)中將用戶指示燈D3點(diǎn)亮,延時(shí)500ms,再熄滅,再延時(shí)500ms的過程,這樣可觀察到指示燈D3不停閃爍的現(xiàn)象。
代碼清單:主函數(shù)
1.int main()
2.{
3. GPIO_config(); //設(shè)置P7.2口為準(zhǔn)雙向口
4.
5. while(1)
6. {
7. P72=0; //控制P7.2端口輸出低電平,點(diǎn)亮用戶指示燈D3
8. delay_ms(500);
9. P72=1; //控制P7.2端口輸出高電平,熄滅用戶指示燈D3
10. delay_ms(500);
11. }
12.}
5.流水燈實(shí)驗(yàn)(單個(gè)c文件)
5.1.頭文件引用和路徑設(shè)置
本實(shí)驗(yàn)需要用到的頭文件以及添加頭文件包含路徑的方法請參考“實(shí)驗(yàn)2-1-1:GPIO驅(qū)動(dòng)LED(寄存器版本)”部分。
在程序設(shè)計(jì)中重新定義了P2寄存器的位變量P26和P27及P7寄存器的位變量P71和P72,這是為了控制GPIO口比較鮮明地知道其用途。
1./*********************************************
2.引腳別名定義
3.**********************************************/
4.sbit LED_D1=P2^6; //用戶指示燈D1用IO口P26
5.sbit LED_D2=P2^7; //用戶指示燈D2用IO口P27
6.sbit LED_D3=P7^2; //用戶指示燈D3用IO口P72
sbit LED_D4=P7^1; //用戶指示燈D4用IO口P71
須知,語句“LED_D1=0; ”和語句“P26=0;” 效果是完全一樣的;語句“LED_D1=1; ”和語句“P26=1;” 效果也是完全一樣的。
5.2.編寫代碼
首先編寫一個(gè)函數(shù),該函數(shù)會(huì)控制4個(gè)用戶LED分別依次點(diǎn)亮,代碼如下。
程序清單:流水燈點(diǎn)亮函數(shù)
1./*************************************************************************
2.功能描述:流水燈
3.入口參數(shù):無
4.返回值:無
5. ************************************************************************/
6.void LED_Blink(void)
7.{
8. LED_D1=0; //點(diǎn)亮用戶指示燈D1
9. LED_D2=1; //熄滅用戶指示燈D2
10. LED_D3=1; //熄滅用戶指示燈D3
11. LED_D4=1; //熄滅用戶指示燈D4
12. delay_ms(300);
13. LED_D1=1; //熄滅用戶指示燈D1
14. LED_D2=0; //點(diǎn)亮用戶指示燈D2
15. LED_D3=1; //熄滅用戶指示燈D3
16. LED_D4=1; //熄滅用戶指示燈D4
17. delay_ms(300);
18. LED_D1=1; //熄滅用戶指示燈D1
19. LED_D2=1; //熄滅用戶指示燈D2
20. LED_D3=0; //點(diǎn)亮用戶指示燈D3
21. LED_D4=1; //熄滅用戶指示燈D4
22. delay_ms(300);
23. LED_D1=1; //熄滅用戶指示燈D1
24. LED_D2=1; //熄滅用戶指示燈D2
25. LED_D3=1; //熄滅用戶指示燈D3
26. LED_D4=0; //點(diǎn)亮用戶指示燈D4
27. delay_ms(300);
28. LED_D1=1; //熄滅用戶指示燈D1
29. LED_D2=1; //熄滅用戶指示燈D2
30. LED_D3=1; //熄滅用戶指示燈D3
31. LED_D4=1; //熄滅用戶指示燈D4
32. delay_ms(300);
33.}
然后,在主函數(shù)中先對P2.6、P2.7、P7.1、P7.2口進(jìn)行模式配置,后主循環(huán)中調(diào)用流水燈函數(shù),這樣可觀察到指示燈D1、D2、D3、D4被流水點(diǎn)亮。
代碼清單:主函數(shù)
1.int main(void)
2.{
3. P2M1 &= 0x3F; P2M0 &= 0x3F; //設(shè)置P2.6~P2.7為準(zhǔn)雙向口
4. //P2M1 &= 0x3F; P2M0 |= 0xC0; //設(shè)置P2.6~P2.7為推挽輸出
5. //P2M1 |= 0xC0; P2M0 &= 0x3F; //設(shè)置P2.6~P2.7為高阻輸入
6. //P2M1 |= 0xC0; P2M0 |= 0xC0; //設(shè)置P2.6~P2.7為開漏輸出
7. P7M1 &= 0xF9; P7M0 &= 0xF9; //設(shè)置P7.1~P7.2為準(zhǔn)雙向口
8. //P7M1 &= 0xF9; P7M0 |= 0x06; //設(shè)置P7.1~P7.2為推挽輸出
9. //P7M1 |= 0x06; P7M0 &= 0xF9; //設(shè)置P7.1~P7.2為高阻輸入
10. //P7M1 |= 0x06; P7M0 |= 0x06; //設(shè)置P7.1~P7.2為開漏輸出
11.
12. while(1)
13. {
14. LED_Blink(); //指示燈流水點(diǎn)亮
15. }
16.}
6.流水燈實(shí)驗(yàn)(多個(gè)c文件)
6.1.工程需要用到的c文件
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
6.2.頭文件引用和路徑設(shè)置
■ 需要引用的頭文件
因?yàn)樵凇癿ain.c”文件中使用了控制led的函數(shù)和延時(shí)函數(shù)(延時(shí)函數(shù)沒有在main.c中定義),所以需要引用下面的頭文件。
1.#include "led.h"
2.#include "delay.h"
■ 需要包含的頭文件路徑
本例需要包含的頭文件路徑如下表:
MDK中點(diǎn)擊魔術(shù)棒,打開工程配置窗口,添加頭文件包含路徑。
6.3.編寫代碼
首先在delay.c文件中編寫兩個(gè)延時(shí)函數(shù)delay_ms和Delay10us,delay_ms函數(shù)是毫秒延時(shí),Delay10us函數(shù)是10微秒延時(shí),代碼如下。
程序清單:延時(shí)函數(shù)
1./**************************************
2.功能描述:延時(shí)函數(shù)
3.入口參數(shù):uint16 x ,該值為1時(shí),延時(shí)1ms
4.返回值:無
5.***************************************/
6.void delay_ms(uint16 x)
7.{
8. uint16 j,i;
9. for(j=0;j
程序清單:延時(shí)函數(shù)
1./*******************************************************************
2.功能描述:延時(shí)函數(shù),延時(shí)約10us,在11.0592MHZ下
3.入口參數(shù):無
4.返回值:無
5.********************************************************************/
6.void Delay10us(void)
7.{
8. uint8 i;
9. _nop_();
10. i = 33;
11. while (--i);
12.}
該delay_ms函數(shù)會(huì)在delay.h頭文件中被聲明,這樣可以被外部調(diào)用。如下。
1.extern void delay_ms(uint16 x);
extern void Delay10us(void);
然后在led.c文件中封裝和4個(gè)LED有關(guān)的所有基本操作函數(shù)。如下表所示的5個(gè)函數(shù)。
LED基本操作函數(shù)程序清單如下:
程序清單:點(diǎn)亮一個(gè)指定的LED
1. /**************************************************************************
2.功能描述:點(diǎn)亮一個(gè)指定的指示燈(D1、D2、D3、D4)
3.入口參數(shù):uint8 led_idx (可取值LED_1、LED_2、LED_3、LED_4)
4.返回值:無
5. *************************************************************************/
6.void led_on(uint8 led_idx)
7.{
8. switch(led_idx)
9. {
10. case LED_1:
11. LED_D1=0; //控制P2.6端口輸出低電平,點(diǎn)亮用戶指示燈D1
12. break;
13. case LED_2:
14. LED_D2=0; //控制P2.7端口輸出低電平,點(diǎn)亮用戶指示燈D2
15. break;
16. case LED_3:
17. LED_D3=0; //控制P7.2端口輸出低電平,點(diǎn)亮用戶指示燈D3
18. break;
19. case LED_4:
20. LED_D4=0; //控制P7.1端口輸出低電平,點(diǎn)亮用戶指示燈D4
21. break;
22. default:
23. break;
24. }
25.}
程序清單:熄滅一個(gè)指定的LED
1./**************************************************************************
2.功能描述:熄滅一個(gè)指定的指示燈(D1、D2、D3、D4)
3.入口參數(shù):uint8 led_idx (可取值LED_1、LED_2、LED_3、LED_4)
4.返回值:無
5. *************************************************************************/
6.void led_off(uint8 led_idx)
7.{
8. switch(led_idx)
9. {
10. case LED_1:
11. LED_D1=1; //控制P2.6端口輸出高電平,熄滅用戶指示燈D1
12. break;
13. case LED_2:
14. LED_D2=1; //控制P2.7端口輸出高電平,熄滅用戶指示燈D2
15. break;
16. case LED_3:
17. LED_D3=1; //控制P7.2端口輸出高電平,熄滅用戶指示燈D3
18. break;
19. case LED_4:
20. LED_D4=1; //控制P7.1端口輸出高電平,熄滅用戶指示燈D4
21. break;
22. default:
23. break;
24. }
25.}
程序清單:翻轉(zhuǎn)一個(gè)指定的LED的狀態(tài)
1./**************************************************************************
2.功能描述:翻轉(zhuǎn)一個(gè)指定的指示燈(D1、D2、D3、D4)
3.入口參數(shù):uint8 led_idx (可取值LED_1、LED_2、LED_3、LED_4)
4.返回值:無
5.*************************************************************************/
6.void led_toggle(uint8 led_idx)
7.{
8. switch(led_idx)
9. {
10. case LED_1:
11. LED_D1=~LED_D1; //控制P2.6端口輸出不同于上一次的電平,翻轉(zhuǎn)用戶指示燈D1
12. break;
13. case LED_2:
14. LED_D2=~LED_D2; //控制P2.7端口輸出不同于上一次的電平,翻轉(zhuǎn)用戶指示燈D2
15. break;
16. case LED_3:
17. LED_D3=~LED_D3; //控制P7.2端口輸出不同于上一次的電平,翻轉(zhuǎn)用戶指示燈D3
18. break;
19. case LED_4:
20. LED_D4=~LED_D4; //控制P7.1端口輸出不同于上一次的電平,翻轉(zhuǎn)用戶指示燈D4
21. break;
22. default:
23. break;
24. }
25.}
程序清單:同時(shí)點(diǎn)亮開發(fā)板上的4個(gè)指示燈
1./**************************************************************************
2.功能描述:點(diǎn)亮開發(fā)板上的4個(gè)指示燈(D1、D2、D3、D4)
3.入口參數(shù):無
4.返回值:無
5. *************************************************************************/
6.void leds_on(void)
7.{
8. LED_D1=0; //控制P2.6端口輸出低電平,點(diǎn)亮用戶指示燈D1
9. LED_D2=0; //控制P2.7端口輸出低電平,點(diǎn)亮用戶指示燈D2
10. LED_D3=0; //控制P7.2端口輸出低電平,點(diǎn)亮用戶指示燈D3
11. LED_D4=0; //控制P7.1端口輸出低電平,點(diǎn)亮用戶指示燈D4
12.}
程序清單:同時(shí)熄滅開發(fā)板上的4個(gè)LED
1./**************************************************************************
2.功能描述:熄滅開發(fā)板上的4個(gè)指示燈(D1、D2、D3、D4)
3.入口參數(shù):無
4.返回值:無
5. *************************************************************************/
6.void leds_off(void)
7.{
8. LED_D1=1; //控制P2.6端口輸出高電平,熄滅用戶指示燈D1
9. LED_D2=1; //控制P2.7端口輸出高電平,熄滅用戶指示燈D2
10. LED_D3=1; //控制P7.2端口輸出高電平,熄滅用戶指示燈D3
11. LED_D4=1; //控制P7.1端口輸出高電平,熄滅用戶指示燈D4
12.}
在led.c文件中還編寫了一個(gè)流水燈點(diǎn)亮的函數(shù)LED_Blink,該函數(shù)調(diào)用LED的基本函數(shù)實(shí)現(xiàn)流水點(diǎn)亮4個(gè)用戶指示燈的目的。代碼如下。
程序清單:流水燈點(diǎn)亮函數(shù)
1./**************************************************************************
2.功能描述:流水燈
3.入口參數(shù):無
4.返回值:無
5. *************************************************************************/
6.void LED_Blink(void)
7.{
8. leds_off(); //熄滅所有用戶指示燈
9. led_on(LED_1); //點(diǎn)亮用戶指示燈D1
10. delay_ms(300);
11. leds_off(); //熄滅所有用戶指示燈
12. led_on(LED_2); //點(diǎn)亮用戶指示燈D2
13. delay_ms(300);
14. leds_off(); //熄滅所有用戶指示燈
15. led_on(LED_3); //點(diǎn)亮用戶指示燈D3
16. delay_ms(300);
17. leds_off(); //熄滅所有用戶指示燈
18. led_on(LED_4); //點(diǎn)亮用戶指示燈D4
19. delay_ms(300);
20. leds_off(); //熄滅所有用戶指示燈
21. delay_ms(300);
}
在led.h頭文件中會(huì)聲明可供外部調(diào)用的函數(shù),LED_Blink函數(shù)便是其中之一。如下。
1.extern void led_on(uint8 led_idx);
2.extern void led_off(uint8 led_idx);
3.extern void led_toggle(uint8 led_idx);
4.extern void leds_on(void);
5.extern void leds_off(void);
6.extern void LED_Blink(void);
最后,在主函數(shù)中先對P2.6、P2.7、P7.1、P7.2口進(jìn)行模式配置,后主循環(huán)中調(diào)用流水燈函數(shù),這樣可觀察到指示燈D1、D2、D3、D4被流水點(diǎn)亮。
代碼清單:主函數(shù)
1.int main(void)
2.{
3. P2M1 &= 0x3F; P2M0 &= 0x3F; //設(shè)置P2.6~P2.7為準(zhǔn)雙向口
4. //P2M1 &= 0x3F; P2M0 |= 0xC0; //設(shè)置P2.6~P2.7為推挽輸出
5. //P2M1 |= 0xC0; P2M0 &= 0x3F; //設(shè)置P2.6~P2.7為高阻輸入
6. //P2M1 |= 0xC0; P2M0 |= 0xC0; //設(shè)置P2.6~P2.7為開漏輸出
7. P7M1 &= 0xF9; P7M0 &= 0xF9; //設(shè)置P7.1~P7.2為準(zhǔn)雙向口
8. //P7M1 &= 0xF9; P7M0 |= 0x06; //設(shè)置P7.1~P7.2為推挽輸出
9. //P7M1 |= 0x06; P7M0 &= 0xF9; //設(shè)置P7.1~P7.2為高阻輸入
10. //P7M1 |= 0x06; P7M0 |= 0x06; //設(shè)置P7.1~P7.2為開漏輸出
11.
12. while(1)
13. {
14. LED_Blink(); //指示燈流水點(diǎn)亮
15. }
16.}
好啦!以上就是今天要講的內(nèi)容,當(dāng)然期間也咨詢了艾克姆科技的技術(shù)人員幫忙搞定的,希望對你有所幫助!
-
led
+關(guān)注
關(guān)注
242文章
23277瀏覽量
660846 -
指示燈
+關(guān)注
關(guān)注
3文章
415瀏覽量
28284 -
開發(fā)板
+關(guān)注
關(guān)注
25文章
5050瀏覽量
97456 -
硬件電路
+關(guān)注
關(guān)注
39文章
243瀏覽量
29229 -
GPIO
+關(guān)注
關(guān)注
16文章
1204瀏覽量
52091
發(fā)布評論請先 登錄
相關(guān)推薦
評論