第2課 CC2530的通用I/O端口輸入和輸出控制html
XMF393 / 廣東職業技術學院 歐浩源編程
【通用I/O端口視頻教程:https://v.qq.com/x/page/x0793aol7us.html】函數
1、CC2530的引腳概述spa
CC2530微控制器採用QFN40封裝,有40 個引腳。其中,有21個數字I/O端口,其中P0和P1是8 位端口,P2僅有5位可使用。這21個端口都可以經過編程進行配置。實際上,在P2端口的5個引腳中,有2個須要用做仿真,有2個須要用做晶振,你在CC2530的開發中真正可以使用的只有17個引腳。設計
在微控制器內部,有一些特殊功能的存儲單元,這些單元用來存放控制微控制器內部器件的命令、數據或運行過程當中的一些狀態信息,這些寄存器統稱爲「特殊功能寄存器(SFR)」。操做微控制器的本質,就是對這些特殊功能寄存器進行讀寫操做,而且某些特殊功能寄存器能夠位尋址。3d
每個特殊功能寄存器本質上就是一個內存單元,而標識每一個內存單元的是內存地址,不容易記憶。爲了便於使用,每一個特殊功能寄存器都會起一個名字,在程序設計時,只要引入頭文件「ioCC2530.h」,就能夠直接使用寄存器的名稱訪問內存地址了。調試
CC2530的通用I/O端口相關的經常使用寄存器有下面4個:code
<1> PxSEL:端口功能選擇,設置端口是通用I/O仍是外設功能。視頻
<2> PxDIR:做爲通用I/O時,用來設置數據的傳輸方向。htm
<3> PxINP:做爲通用輸入端口時,選擇輸入模式是上拉、下拉仍是三態。
<4> Px:數據端口,用來控制端口的輸出或獲取端口的輸入。
2、設置寄存器中某些位的方法
<1> 對寄存器的某些位清0而不影響其餘位。
例如:寄存器P1TM的當前值是0x6c,現須要將該寄存器的第1位、第3 位和第5位設置爲0,同時不能影響該寄存器其餘位的值,那麼,在C語言中應該怎麼編寫代碼呢?
使用「&=」將寄存器指定位清0,同時不影響其餘位的值。
正確寫法:P1TM &= ~0x2A;
由於:邏輯「與」操做的特色是,該位有0結果就爲0,若爲1則保存原來值不變。
首先將字節 0000 0000 中要操做的位設置爲1,即0010 1010,在將該數值取反,即1101 0101,也就是~0x2A。再將該值與寄存器P1TM「相與」,那麼有0的位,即一、三、5位將被清0,其他的位會保持原來的值不變。
因此:P1TM的當前值爲0x6c,即0110 1100,
0110 1100 && 1101 0101 = 0100 0100,即一、三、5位清0,其餘位不變。
<注意>:該方法只能操做多位同時清0,或者某一位清0的狀況,若是要將寄存器的位既要清0又要置1,則不能採用這種寫法。(其中緣由本身思考一下)
在很多嵌入式應用的源碼程序中,對於寄存器的第n位的清0操做也能夠寫成:寄存器 &= ~(0x01<<(n));其道理是同樣的。
<2> 對寄存器的某些位置1而不影響其餘位。
例如:寄存器P1TM的當前值是0x6c,現須要將該寄存器的第1位、第4位和第5位設置爲1,同時不能影響該寄存器其餘位的值,那麼,在C語言中應該怎麼編寫代碼呢?
使用「|=」將寄存器指定位置1,同時不影響其餘位的值。
正確寫法:P1TM |= 0x32;
由於:邏輯「或」操做的特色是,該位有1結果就爲1,若爲0則保存原來值不變。
首先將字節 0000 0000 中要操做的位設置爲1,即0011 0010,也就是0x32。 再將該值與寄存器P1TM「相或」,那個有1的位,即一、四、5位將被設置爲1,其他的位會保持原來的值不變。
因此:P1TM的當前值爲0x6c,即0110 1100,
0110 1100 || 0011 0010 = 0111 1110,即一、四、5位置1,其餘位不變。
一樣要注意:該方法只能操做多位同時置1,或者某一位置1的狀況。
對於寄存器的第n位的清0操做也能夠寫成:寄存器 |= (0x01<<(n));
3、本身設計的Zigbee實訓硬件平臺(歡迎選購哦)
【1】綜合加強版功能概述
【2】引腳分配與結構框圖
3、實訓案例:按鍵輸入控制燈光輸出狀態
【1】準備工做。
引入CC2530必要的頭文件「ioCC2530.h」,定義相關變量等。
【2】端口功能選擇。
微控制器的大部分I/O端口都是功能複用的,在使用的時候須要經過功能選擇寄存器來配置端口的功能。
【3】端口傳輸方向設置。
【4】對於輸入的端口要設置其輸入方式。
輸入方式用來從外界器件獲取輸入的電信號,當CC2530的引腳爲輸入端口時,該端口可以提供「上拉」、「下拉」和「三態」三種輸入模式,能夠經過編程進行設置。在本次實訓中,實際上不須要對P0_1和P1_2引腳進行輸入方式的設置,由於CC2530復位後,各個I/O端口默認使用的就是上拉模式。
【5】通用I/O端口寄存器配置的基本思路。
【6】設計端口初始化函數InitPort()。
<1>設置P1SEL寄存器,將P1_二、P1_3和P1_4設置爲通用I/O端口。
<2>設置P1DIR寄存器,將P1_3和P1_4設置爲輸出,將P1_2設置爲輸入。
<3>設置P0SEL寄存器,將P0_1設置爲通用I/O端口。
<4>設置P0DIR寄存器,將P0_1設置爲輸入。
<5>設置PxINP寄存器,將P0_1和P1_2設置爲上拉模式,也能夠不設置。
【7】設計鍵盤掃描函數ScanKeys()。
<1>沒有按鍵下時,端口的輸入爲高電平,當發現該端口有低電平產生時,則有可能會是按鍵按下,須要通過去抖動處理,若是該端口仍是低電平,則確認爲按鍵按下。
<2>在進行按鍵處理時,先等待按鍵鬆開,而後再將相關的LED進行開關狀態的取反控制。
【8】主函數的實現。
至此,大功搞成,鏈接仿真器,進行編譯調試。
【附件】:本實訓源代碼。
#include "ioCC2530.h" #define LED5 P1_3 #define LED6 P1_4 #define SW1 P1_2 #define SW2 P0_1 /*===================延時函數=========================*/ void Delay(unsigned int t) { while(t--); } /*================端口初始化函數======================*/ void InitPort() { P1SEL &= ~0x18; //將P1_3和P1_4設置爲通用I/O端口功能 P1DIR |= 0x18; //將P1_3和P1_4的端口傳輸方式設置爲輸出 P1SEL &= ~0x04; //將P1_2設置爲通用I/O端口功能 P1DIR &= ~0x04; //將P1_2的端口傳輸方式設置爲輸入 P0SEL &= ~0x02; //將P0_1設置爲通用I/O端口功能 P0DIR &= ~0x02; //將P0_1的端口傳輸方式設置爲輸入 P0INP &= ~0x02; //將P0_1的端口輸入方式設置爲:上拉/下拉 P1INP &= ~0x04; //將P1_2的端口輸入方式設置爲:上拉/下拉 P2INP &= ~0x60; //將P0端口和P1端口引腳設置爲:上拉 LED5 = 0; //上電的時候,LED5不亮 LED6 = 0; //上電的時候,LED6不亮 } /*=================按鍵掃描函數=======================*/ void ScanKeys() { if(SW1 == 0) { //發現SW1有低電平信號 Delay(100); //按鍵去抖動 if(SW1 == 0) { //確實是有按鍵動做 while(SW1 == 0); //等待按鍵1鬆開 //將LED5的燈光開關狀態取反 LED5 = ~LED5; } if(SW2 == 0) { //發現SW2有低電平信號 Delay(100); //按鍵去抖動 if(SW2 == 0) { //確實是有按鍵動做 while(SW2 == 0); //等待按鍵2鬆開 LED6 = ~LED6; } } } /*=====================主函數=========================*/ void main() { InitPort(); while(1) { ScanKeys(); } }