【CC2530入門教程-02】CC2530的通用I/O端口輸入和輸出控制


第2課  CC2530的通用I/O端口輸入和輸出控制

XMF393 / 廣東職業技術學院  歐浩源

【視頻教程】:將寄存器中某些為清0或置1

【視頻教程】:CC2530通用I/O及相關寄存器

【視頻教程】:LED燈閃爍實現的源碼分析

【視頻教程】:基於CC2530的跑馬燈實現

【視頻教程】:按鍵的工作原理與程序設計思路

【視頻教程】:按鍵控制LED燈開關

【視頻教程】:按鍵控制跑馬燈的運行與暫停

一、CC2530的引腳概述

        CC2530微控制器采用QFN40封裝,有40 個引腳。其中,有21個數字I/O端口,其中P0P18 位端口P2僅有5位可以使用。這21個端口均可以通過編程進行配置。實際上,在P2端口的5個引腳中,有2個需要用作仿真,有2個需要用作晶振,你在CC2530的開發中真正能夠使用的只有17個引腳

        在微控制器內部,有一些特殊功能的存儲單元,這些單元用來存放控制微控制器內部器件的命令、數據或運行過程中的一些狀態信息,這些寄存器統稱為“特殊功能寄存器(SFR)”。操作微控制器的本質,就是對這些特殊功能寄存器進行讀寫操作,並且某些特殊功能寄存器可以位尋址

        每一個特殊功能寄存器本質上就是一個內存單元,而標識每個內存單元的是內存地址,不容易記憶。為了便於使用,每個特殊功能寄存器都會起一個名字,在程序設計時,只要引入頭文件“ioCC2530.h”,就可以直接使用寄存器的名稱訪問內存地址了。

        CC2530的通用I/O端口相關的常用寄存器有下面4個:

        <1> PxSEL:端口功能選擇,設置端口是通用I/O還是外設功能

        <2> PxDIR:作為通用I/O時,用來設置數據的傳輸方向。

        <3> PxINP:作為通用輸入端口時,選擇輸入模式是上拉下拉還是三態

        <4> Px:數據端口,用來控制端口的輸出或獲取端口的輸入。

 

二、設置寄存器中某些位的方法

        <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的位,即1、3、5位將被清0,其余的位會保持原來的值不變。

        所以:P1TM的當前值為0x6c,即0110 1100,

        0110 1100 && 1101 0101 = 0100 0100,即1、3、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的位,即1、4、5位將被設置為1,其余的位會保持原來的值不變。

        所以:P1TM的當前值為0x6c,即0110 1100,

        0110 1100 || 0011 0010 = 0111 1110,即1、4、5位置1,其他位不變。

        同樣要注意:該方法只能操作多位同時置1,或者某一位置1的情況。

        對於寄存器的第n位的清0操作也可以寫成:寄存 |= (0x01<<(n));

 

三、實訓案例:按鍵輸入控制燈光輸出狀態

【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_2、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();
  }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM