前言
最近空閑時間比較多,準備說說STC8A8K64S4A12開發板。 實驗做起來——先從GPIO點燈開始。
一、硬件電路原理
1.開發板指示燈硬件電路
LED(Light Emitting Diode)是發光二極管的簡稱,在很多設備上常用它來做為一種簡單的人機接口,如網卡、路由器等通過LED向用戶指示設備的不同工作狀態。所以,我們習慣把這種用于指示狀態的LED稱為LED指示燈。
STC8A8K64S4A12開發板上設計了4個LED指示燈,我們可以通過編程驅動LED指示燈點亮、熄滅、閃爍,從而達到狀態指示的目的,LED指示燈驅動電路如下圖所示。
圖1:LED指示燈驅動電路
LED指示燈驅動電路是一個很常見、簡單的電路,同時它也是一個典型的單元電路,對于初學者來說,類似常用的典型電路必須要掌握,不但要知其然、還要知其所以然。
接下來,我們來分析一下這個簡單的LED指示燈驅動電路。
LED驅動電路設計的時候,要考慮兩個方面:控制方式和限流電阻的選取。
2.控制方式
LED指示燈控制方式分為高電平有效和低電平有效兩種,高電平有效是單片機GPIO輸出高電平時點亮LED,低電平有效是單片機GPIO輸出低電平時點亮LED。
2.1.低電平有效的控制方式
LED控制-低電平有效原理
低電平有效控制方式中,當單片機的GPIO輸出低電平(邏輯0)的時候,LED和電阻R上的壓降等于(VCC-VCCIO = 3.3V),這時候,因為存在壓降,同時,這個電路是閉合回路,這就達到了電流產生的兩個要素,LED上會有電流流過,LED被點亮。
當單片機的GPIO輸出高電平(邏輯1)的時候,LED和電阻R上的壓降等于(VCC-VCCIO = 0V),這時候,因為LED上沒有壓降,當然不會有電流流過,所以LED熄滅。
2.2.高電平有效的控制方式
圖3:LED控制-高電平有效原理
高電平有效控制方式中,由單片機的GPIO輸出電流驅動LED,當單片機的GPIO輸出高電平(邏輯1)的時候,LED上存在壓降,因為電路是閉合回路,所以會有電流流過,這時LED被點亮,但要注意,單片機的GPIO要能提供足夠的輸出電流,否則,電流過小,會導致LED亮度很弱。
當單片機的GPIO輸出低電平(邏輯0)的時候,LED和電阻R上的壓降等于0V,這時候,LED上沒有電流流過,LED熄滅。
2.3.選擇哪種方式來控制LED
絕大多數情況下,我們會選擇使用低電平有效的控制方式,如艾克姆科技STC8A8K64S4A12開發板中的LED指示燈就是低電平有效。這樣設計指示燈驅動電路的好處是:
① 單片機GPIO口低電平時的灌入電流一般比高電平時的拉電流要大,能提供足夠的電流驅動LED。
② 單片機上電或復位啟動時,GPIO口一般都是高阻輸入,用低電平有效的控制方式可以確保LED在上電或復位啟動時處于熄滅狀態。
3.LED限流電阻的選取
3.1.限流電阻的計算
圖4:LED限流電阻計算
由上圖可以看出,LED限流電阻的計算公式如下:
其中,VCC=3.3V,VF是LED的正向壓降,LED的數據手冊都會給出正向電流為2mA時測試的VF的范圍,下圖是一款0805 LED的實物圖和參數。在參數表中可以看到正向電流為2mA時VF最小值是2.5V,典型值是2.7V,最大值是3.6V。
圖5:封裝0805的LED
圖6:0805 LED參數圖
計算時VF的值可以用典型值來進行估算,對于電流,需要根據經驗值和對LED亮度的要求相結合來確定,一般經驗值是(1~5)mA,不過要注意,只要亮度符合自己的要求,電流低于1mA也沒有任何問題。
電流為1mA時限流電阻值計算如下:
3.2.限流電阻的選擇
根據上一節對限流電阻計算公式的描述及對選擇的封裝0805的指示燈參數的了解,計算出供電3.3V電流1mA時的限流電阻理論值是600Ω,供電5V電流1mA時的限流電阻理論值是2.3KΩ,為保證供電為3.3V時指示燈夠亮但同時5V供電指示燈又不宜過亮,選擇一個比較常見的阻值2K作為限流電阻。
還有一點需要強調的是,不同顏色的指示燈在即使同一亮度時所需的限流電阻不一定是相同的。這也是為什么有些產品的面板上有不同顏色的指示燈,各指示燈所使用的限流電阻不一樣的原因。
4.STC8A8K64S4A12系列單片機GPIO口
STC8A8K64S4A12系列單片機GPIO口數量取決于芯片引腳的個數,芯片引腳個數和芯片封裝密切相關。正常情況下,GPIO口數量是所選擇單片機引腳個數減去5,因為單片機需要2個引腳作為供電引腳(電源正VCC、電源負GND),ADC外設會占用3個引腳(電源正ADC_Avcc、電源負ADC_Agnd、參考電壓AVref)。
4.1.芯片封裝
封裝,Package,是把集成電路裝配為芯片最終產品的過程,簡單地說,就是把Foundry生產出來的集成電路裸片(Die)放在一塊起到承載作用的基板上,把管腳引出來,然后固定包裝成為一個整體。
STC8A8K64S4A12系列有多種封裝,廠家批量常見的芯片封裝是:LQFP44、LQFP48和LQFP64S。
4.2.GPIO口工作模式
STC8A8K64S4A12系列單片機所有GPIO口均有4種工作模式:準雙向口/弱上拉(標準8051輸出口模式)、推挽輸出/強上拉、高阻輸入(電流既不能流入也不能流出)、開漏輸出。下面針對內部結構圖進行分析。
■ 準雙向口/弱上拉模式:
圖7:GPIO準雙向口/弱上拉模式內部框圖
1)準雙向口(弱上拉) 輸出類型可用作輸出和輸入功能而不需要重新配置端口輸出狀態。這是因為準雙向口有3個上拉晶體管可適應輸入輸出不同的需要。
2)手冊中有這樣一句話:準雙向口(弱上拉)在讀外部狀態前,要先鎖存為‘1’,才可讀到外部正確的狀態。下圖分別就鎖存數據為‘1’和‘0’時進行了分析。
圖8:GPIO準雙向口/弱上拉模式內部框圖分析
3)由上圖分析可知,準雙向口(弱上拉)在讀外部狀態前,如果鎖存為‘0’,則GPIO引腳狀態被固定,無法讀到外部正確的狀態。
■ 推挽輸出/強上拉模式:
圖9:GPIO推挽輸出/強上拉模式內部框圖
1)強推挽輸出配置的下拉結構與開漏輸出以及準雙向口的下拉結構相同,但當鎖存器為1時可提供持續的強上拉。所以,推挽輸出一般用于需要更大驅動電流的情況。
2)在控制LED時,如果采用的是高電平有效的控制方式,則控制LED的單片機GPIO口必須配置成推挽輸出/強上拉模式方可。
■ 高阻輸入模式:
圖10:GPIO高阻輸入模式內部框圖
1)因帶有一個施密特觸發輸入以及一個干擾抑制電路,GPIO配置為高阻輸入時,電流既不能流入也不能流出GPIO口。
2)在很多STC相關的文檔中有說的高阻態即是GPIO口被設置了高阻輸入模式。
■ 開漏輸出模式:
圖11:GPIO開漏輸出模式內部框圖
1)開漏模式既可以讀外部狀態也可以對外輸出高電平或低電平。
2)如果要正確讀外部狀態或需要對外輸出高電平時,需外加上拉電阻。
二、軟件編寫
1.GPIO寄存器匯集
STC8A8K64S4A12系列單片機提供了40個用于操作GPIO的寄存器,如下表所示:
表2:
2.寄存器解析
首先普及一個常用知識點:為什么說STC8A8K64S4A12系列單片機是8位單片機呢?這個8位指的是什么?
一般來說某個單片機或微處理器是幾位,指的是“機器字長”。每個單片機或微處理器最基本的功能是算術邏輯運算,而算術邏輯運算的主要部件是“算術邏輯單元(ALU)”。機器字長即是指ALU的數據位寬,也就是指令能直接處理的二進制位數。
通常單片機或微處理器的寄存器的位寬等于ALU的位寬,所以一般可通過識別單片機或微處理器寄存器的位寬來確定該單片機或微處理器是多少位的。我們所接觸的STC的單片機,其寄存器都是8位的,所以STC的單片機都是8位的單片機。以后學習STM32F103系列的微處理器,其寄存器是32位的,所以會說STM32F103系列微處理器是32位的。
2.1.端口數據寄存器
下圖是對端口數據寄存器P0、P1、P2、P3、P4、P5、P6、P7的描述,端口數據寄存器各位代表對應端口的IO口,比如,P7端口數據寄存器B0位代表P7.0口,B7位代表P7.7口。
圖12:端口數據寄存器
2.2.端口配置寄存器
端口配置寄存器PnM1和PnM0都是8位的寄存器,PnM1和PnM0寄存器必須組合使用才能正確地配置IO口工作模式。
STC8A8K64S4A12系列單片機所有GPIO口均有4種工作模式:準雙向口/弱上拉(標準8051輸出口模式)、推挽輸出/強上拉、高阻輸入(電流既不能流入也不能流出)、開漏輸出。每個GPIO口工作模式由PnM1和PnM0寄存器中的相應位控制。如下圖。
圖13:GPIO端口配置
3.GPIO驅動LED實驗(寄存器版本)
3.1.頭文件引用和路徑設置
■ 需要宏定義部分及引用的頭文件
因為在“main.c”文件中使用了STC8的頭文件“STC8.H”,所以需要引用下面的頭文件。在頭文件“STC8.H”中需要確定主時鐘取值,所以宏定義主時鐘值。
1.#define uint16 unsigned int
2.#define uint8 unsigned char
在程序設計中會用到定義變量的類型,為了定義變量方便,將較為復雜的“unsigned int”和“unsigned char ”進行了宏定義。
#define uint16 unsigned int
#define uint8 unsigned char
這樣,再定義變量時可直接使用“uint16”和“uint8”來取代“unsigned int”和“unsigned char ”即可。
■ 需要包含的頭文件路徑
本例需要包含的頭文件路徑如下表:
MDK中點擊魔術棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。
圖14:添加頭文件包含路徑
3.2.編寫代碼
首先介紹下毫秒級的延時函數??刂浦甘緹袅梁蜏缧枰虚g有足夠的間隔時間,這個間隔一般通過延時函數實現。微秒級的延時時間很難控制,這和主頻大小及其精度有密切關系。但毫秒級的延時還是可以控制的,下面給出在11.0592MHZ下的毫秒延時函數,僅供參考。
代碼清單:毫秒延時函數
1./**************************************
2.功能描述:延時函數
3.入口參數:uint16 x ,該值為1時,延時1ms
4.返回值:無
5.***************************************/
6.void delay_ms(uint16 x)
7.{
8. uint16 j,i;
9. for(j=0;j
在對端口數據寄存器介紹時我們簡單介紹過控制單片機GPIO的過程。需要再說明的地方是關于兩個關鍵字“sfr”和“sbit”。
sfr是Keil C51為能直接訪問51內核單片機中的SFR而提供了一個關鍵詞,其用法是:
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;
}
然后,在主函數中先對P7.2口進行模式配置,針對P7.2口是被配置了準雙向口,后主循環中將用戶指示燈D3點亮,延時200ms,再熄滅,再延時200ms的過程,這樣可觀察到指示燈D3不停閃爍的現象。
代碼清單:主函數
1.int main()
2.{
3. P7M1 &= 0xFB; P7M0 &= 0xFB; //設置P7.2為準雙向口
4. // P7M1 &= 0xFB; P7M0 |= 0x04; //設置P7.2為推挽輸出
5. // P7M1 |= 0x04; P7M0 &= 0xFB; //設置P7.2為高阻輸入
6. // P7M1 |= 0x04; P7M0 |= 0x04; //設置P7.2為開漏輸出
7.
8. while(1)
9. {
10. P72=0; //控制P7.2端口輸出低電平,點亮用戶指示燈D3
11. delay_ms(200);
12. P72=1; //控制P7.2端口輸出高電平,熄滅用戶指示燈D3
13. delay_ms(200);
14. }
15.}
4.GPIO驅動LED實驗(庫函數版本)
4.1.工程需要用到的c文件
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
該GPIO.c是STC官方提供的有關GPIO配置的函數庫。
4.2.頭文件引用和路徑設置
■ 需要引用的頭文件
因為在“main.c”文件中使用了GPIO相關的庫,所以需要引用下面的頭文件。
1.#include "GPIO.h"
■ 需要包含的頭文件路徑
本例需要包含的頭文件路徑如下表:
MDK中點擊魔術棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。
圖15:添加頭文件包含路徑
4.3.編寫代碼
首先在GPIO口初始化函數中調用庫函數GPIO_Inilize完成P7.2口的工作模式配置,即配置P7.2為準雙向口。
代碼清單:GPIO口初始化函數
1./**************************************
2.功能描述:GPIO口初始化
3.入口參數:無
4.返回值:無
5.***************************************/
6.void GPIO_config(void)
7.{
8. GPIO_InitTypeDef GPIO_InitStructure;
9.
10. //設置P7.2口工作模式
11. GPIO_InitStructure.Mode=GPIO_PullUp; //配置P7.2口為準雙向口
12. //GPIO_InitStructure.Mode=GPIO_OUT_PP; //配置P7.2口為推挽輸出(強上拉)
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.}
打開庫函數GPIO_Inilize后會發現,配置P7.2口實際最終操作還是P0M0和P0M1寄存器。代碼如下。
程序清單:頭文件“GPIO.c”定義GPIO初始化庫函數
1.//========================================================================
2.// 函數: uint8 GPIO_Inilize(uint8 GPIO, GPIO_InitTypeDef *GPIOx)
3.// 描述: 初始化IO口.
4.// 參數: GPIOx: 結構參數,請參考gpio.h里的定義.
5.// 返回: 成功返回0, 空操作返回1,錯誤返回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; //錯誤
11.
12. if(GPIO == GPIO_P0)
13. {
14. if(GPIOx->Mode == GPIO_PullUp) P0M1 &= ~GPIOx->Pin, P0M0 &= ~GPIOx->Pin; //上拉準雙向口
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; //上拉準雙向口
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; //上拉準雙向口
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; //上拉準雙向口
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; //上拉準雙向口
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; //上拉準雙向口
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; //上拉準雙向口
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; //上拉準雙向口
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; //成功
}
然后,在主函數中先調用GPIO口初始化函數,后主循環中將用戶指示燈D3點亮,延時500ms,再熄滅,再延時500ms的過程,這樣可觀察到指示燈D3不停閃爍的現象。
代碼清單:主函數
1.int main()
2.{
3. GPIO_config(); //設置P7.2口為準雙向口
4.
5. while(1)
6. {
7. P72=0; //控制P7.2端口輸出低電平,點亮用戶指示燈D3
8. delay_ms(500);
9. P72=1; //控制P7.2端口輸出高電平,熄滅用戶指示燈D3
10. delay_ms(500);
11. }
12.}
5.流水燈實驗(單個c文件)
5.1.頭文件引用和路徑設置
本實驗需要用到的頭文件以及添加頭文件包含路徑的方法請參考“實驗2-1-1:GPIO驅動LED(寄存器版本)”部分。
在程序設計中重新定義了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.編寫代碼
首先編寫一個函數,該函數會控制4個用戶LED分別依次點亮,代碼如下。
程序清單:流水燈點亮函數
1./*************************************************************************
2.功能描述:流水燈
3.入口參數:無
4.返回值:無
5. ************************************************************************/
6.void LED_Blink(void)
7.{
8. LED_D1=0; //點亮用戶指示燈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; //點亮用戶指示燈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; //點亮用戶指示燈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; //點亮用戶指示燈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.}
然后,在主函數中先對P2.6、P2.7、P7.1、P7.2口進行模式配置,后主循環中調用流水燈函數,這樣可觀察到指示燈D1、D2、D3、D4被流水點亮。
代碼清單:主函數
1.int main(void)
2.{
3. P2M1 &= 0x3F; P2M0 &= 0x3F; //設置P2.6~P2.7為準雙向口
4. //P2M1 &= 0x3F; P2M0 |= 0xC0; //設置P2.6~P2.7為推挽輸出
5. //P2M1 |= 0xC0; P2M0 &= 0x3F; //設置P2.6~P2.7為高阻輸入
6. //P2M1 |= 0xC0; P2M0 |= 0xC0; //設置P2.6~P2.7為開漏輸出
7. P7M1 &= 0xF9; P7M0 &= 0xF9; //設置P7.1~P7.2為準雙向口
8. //P7M1 &= 0xF9; P7M0 |= 0x06; //設置P7.1~P7.2為推挽輸出
9. //P7M1 |= 0x06; P7M0 &= 0xF9; //設置P7.1~P7.2為高阻輸入
10. //P7M1 |= 0x06; P7M0 |= 0x06; //設置P7.1~P7.2為開漏輸出
11.
12. while(1)
13. {
14. LED_Blink(); //指示燈流水點亮
15. }
16.}
6.流水燈實驗(多個c文件)
6.1.工程需要用到的c文件
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
6.2.頭文件引用和路徑設置
■ 需要引用的頭文件
因為在“main.c”文件中使用了控制led的函數和延時函數(延時函數沒有在main.c中定義),所以需要引用下面的頭文件。
1.#include "led.h"
2.#include "delay.h"
■ 需要包含的頭文件路徑
本例需要包含的頭文件路徑如下表:
MDK中點擊魔術棒,打開工程配置窗口,添加頭文件包含路徑。
6.3.編寫代碼
首先在delay.c文件中編寫兩個延時函數delay_ms和Delay10us,delay_ms函數是毫秒延時,Delay10us函數是10微秒延時,代碼如下。
程序清單:延時函數
1./**************************************
2.功能描述:延時函數
3.入口參數:uint16 x ,該值為1時,延時1ms
4.返回值:無
5.***************************************/
6.void delay_ms(uint16 x)
7.{
8. uint16 j,i;
9. for(j=0;j
程序清單:延時函數
1./*******************************************************************
2.功能描述:延時函數,延時約10us,在11.0592MHZ下
3.入口參數:無
4.返回值:無
5.********************************************************************/
6.void Delay10us(void)
7.{
8. uint8 i;
9. _nop_();
10. i = 33;
11. while (--i);
12.}
該delay_ms函數會在delay.h頭文件中被聲明,這樣可以被外部調用。如下。
1.extern void delay_ms(uint16 x);
extern void Delay10us(void);
然后在led.c文件中封裝和4個LED有關的所有基本操作函數。如下表所示的5個函數。
LED基本操作函數程序清單如下:
程序清單:點亮一個指定的LED
1. /**************************************************************************
2.功能描述:點亮一個指定的指示燈(D1、D2、D3、D4)
3.入口參數: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端口輸出低電平,點亮用戶指示燈D1
12. break;
13. case LED_2:
14. LED_D2=0; //控制P2.7端口輸出低電平,點亮用戶指示燈D2
15. break;
16. case LED_3:
17. LED_D3=0; //控制P7.2端口輸出低電平,點亮用戶指示燈D3
18. break;
19. case LED_4:
20. LED_D4=0; //控制P7.1端口輸出低電平,點亮用戶指示燈D4
21. break;
22. default:
23. break;
24. }
25.}
程序清單:熄滅一個指定的LED
1./**************************************************************************
2.功能描述:熄滅一個指定的指示燈(D1、D2、D3、D4)
3.入口參數: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.}
程序清單:翻轉一個指定的LED的狀態
1./**************************************************************************
2.功能描述:翻轉一個指定的指示燈(D1、D2、D3、D4)
3.入口參數: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端口輸出不同于上一次的電平,翻轉用戶指示燈D1
12. break;
13. case LED_2:
14. LED_D2=~LED_D2; //控制P2.7端口輸出不同于上一次的電平,翻轉用戶指示燈D2
15. break;
16. case LED_3:
17. LED_D3=~LED_D3; //控制P7.2端口輸出不同于上一次的電平,翻轉用戶指示燈D3
18. break;
19. case LED_4:
20. LED_D4=~LED_D4; //控制P7.1端口輸出不同于上一次的電平,翻轉用戶指示燈D4
21. break;
22. default:
23. break;
24. }
25.}
程序清單:同時點亮開發板上的4個指示燈
1./**************************************************************************
2.功能描述:點亮開發板上的4個指示燈(D1、D2、D3、D4)
3.入口參數:無
4.返回值:無
5. *************************************************************************/
6.void leds_on(void)
7.{
8. LED_D1=0; //控制P2.6端口輸出低電平,點亮用戶指示燈D1
9. LED_D2=0; //控制P2.7端口輸出低電平,點亮用戶指示燈D2
10. LED_D3=0; //控制P7.2端口輸出低電平,點亮用戶指示燈D3
11. LED_D4=0; //控制P7.1端口輸出低電平,點亮用戶指示燈D4
12.}
程序清單:同時熄滅開發板上的4個LED
1./**************************************************************************
2.功能描述:熄滅開發板上的4個指示燈(D1、D2、D3、D4)
3.入口參數:無
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文件中還編寫了一個流水燈點亮的函數LED_Blink,該函數調用LED的基本函數實現流水點亮4個用戶指示燈的目的。代碼如下。
程序清單:流水燈點亮函數
1./**************************************************************************
2.功能描述:流水燈
3.入口參數:無
4.返回值:無
5. *************************************************************************/
6.void LED_Blink(void)
7.{
8. leds_off(); //熄滅所有用戶指示燈
9. led_on(LED_1); //點亮用戶指示燈D1
10. delay_ms(300);
11. leds_off(); //熄滅所有用戶指示燈
12. led_on(LED_2); //點亮用戶指示燈D2
13. delay_ms(300);
14. leds_off(); //熄滅所有用戶指示燈
15. led_on(LED_3); //點亮用戶指示燈D3
16. delay_ms(300);
17. leds_off(); //熄滅所有用戶指示燈
18. led_on(LED_4); //點亮用戶指示燈D4
19. delay_ms(300);
20. leds_off(); //熄滅所有用戶指示燈
21. delay_ms(300);
}
在led.h頭文件中會聲明可供外部調用的函數,LED_Blink函數便是其中之一。如下。
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);
最后,在主函數中先對P2.6、P2.7、P7.1、P7.2口進行模式配置,后主循環中調用流水燈函數,這樣可觀察到指示燈D1、D2、D3、D4被流水點亮。
代碼清單:主函數
1.int main(void)
2.{
3. P2M1 &= 0x3F; P2M0 &= 0x3F; //設置P2.6~P2.7為準雙向口
4. //P2M1 &= 0x3F; P2M0 |= 0xC0; //設置P2.6~P2.7為推挽輸出
5. //P2M1 |= 0xC0; P2M0 &= 0x3F; //設置P2.6~P2.7為高阻輸入
6. //P2M1 |= 0xC0; P2M0 |= 0xC0; //設置P2.6~P2.7為開漏輸出
7. P7M1 &= 0xF9; P7M0 &= 0xF9; //設置P7.1~P7.2為準雙向口
8. //P7M1 &= 0xF9; P7M0 |= 0x06; //設置P7.1~P7.2為推挽輸出
9. //P7M1 |= 0x06; P7M0 &= 0xF9; //設置P7.1~P7.2為高阻輸入
10. //P7M1 |= 0x06; P7M0 |= 0x06; //設置P7.1~P7.2為開漏輸出
11.
12. while(1)
13. {
14. LED_Blink(); //指示燈流水點亮
15. }
16.}
好啦!以上就是今天要講的內容,當然期間也咨詢了艾克姆科技的技術人員幫忙搞定的,希望對你有所幫助!
-
led
+關注
關注
242文章
23355瀏覽量
663167 -
指示燈
+關注
關注
3文章
416瀏覽量
28382 -
開發板
+關注
關注
25文章
5121瀏覽量
98189 -
硬件電路
+關注
關注
39文章
244瀏覽量
29316 -
GPIO
+關注
關注
16文章
1216瀏覽量
52377
發布評論請先 登錄
相關推薦
STC8A8K64S4A12系列單片機DAC數模轉換器講解
![<b class='flag-5'>STC8A8K64S4A12</b>系列單片機DAC數模轉換器講解](https://file1.elecfans.com/web2/M00/B0/30/wKgZomVUi1GAFTdHAACCXfeqRic52.jpeg)
請問哪位朋友有火龍電子FD51D_8(STC8A8K64S4A12開發板)的資料呢?
STC8A8K64S4A12開發板學習資料
淺析STC8A8K64S4A12開發板
如何去實現一種基于STC8A8K64S4A12開發板的GPIO按鍵設計
基于STC8A8K64S4A12智能車設計資料分享
使用STC8A8K64S4A12單片機掉電喚醒定時器應用的實例
![使用<b class='flag-5'>STC8A8K64S4A12</b>單片機掉電喚醒定時器應用的實例](https://file.elecfans.com/web1/M00/DD/5B/pIYBAGASFvWAf5_3AAVUZrA2lMc917.png)
【STC8A8K64S4A12開發板】—聊聊單片機中斷原理
![【<b class='flag-5'>STC8A8K64S4A12</b><b class='flag-5'>開發板</b>】—聊聊單片機中斷原理](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論