CC2530學習路線-基礎實驗-GPIO 按鍵控制LED燈亮滅(2)




1.前期預備知識


1.1 新大陸Zigbee模塊按鍵電路圖

image_1bq9qhq7u5b6g1od316api579.png-35.8kB

由上圖可知,Zigbee模塊的SW1按鈕連接在P1.2端口上,當SW1導通,P1.2電平從3.3V被拉低接地。所以P1.2輸入模式為下拉輸入.

1.2 CC2530相關寄存器


寄存器名稱 寄存器作用 寄存器描述
P1 (0x90) *控制端口1的高低電平 端口1.通用I/O。可以通過SFR位尋址
P1SEL (0xF4) 端口1 8個子端口的功能選擇 P1SEL的8個bit分別代表 => P1.7~P1.0的功能選擇.
值為 0:代表通用I/0(GPIO)功能.
值為 1 : 代表外設功能
P1DIR (0xFE) 端口1 輸入輸出選擇 P1DIR的bit定義同P1SEL;
值為 0:代表從外部輸入信號至CC2530;
值為 1:代表從CC2530輸出信號至外部
P1INP (0xF6) 端口1 輸入模式選擇 P1INP定義為P1.7~P1.2的I/O輸入模式。其中P1.0和P1.1是沒有上拉/下拉功能
值為 0:上拉/下拉。
值為 1:三態(高電平、低電平、高阻態)
P2INP (0xINP) 端口2 輸入模式及其它端口選擇 P2INP比較特殊,因為P2端口引出的引腳只有3個,所以P2INP還有其它功能。
bit 0 ~ 4 : P2.4~P2.0的輸入模式。 0 : 上拉/下拉; 1:三態
bit 5 : 設置端口0上拉/下拉選擇。對端口P0上面的所有引腳設置為上拉/下拉輸入 0 : 上拉; 1 : 下拉
bit 6 : 同bit 5功能,但是是設置端口1上所有引腳
bit 7 : 同bit5功能,但是是設置端口2上的所有引腳
P1IEN (0x8D) 端口1 中斷屏蔽 端口P1.7~P1.0的中斷使能(也就是說中斷是否Enable*(打開))
0 : 中斷禁用
1 : 中斷使能
PICTL (0x8C) 端口中斷控制 P0ICON(bit0) 端口0、1、2輸入模式下的中斷配置。
0 : 輸入的上升沿引起中斷
1 : 輸入的下降沿引起中斷
P1IFG (0x8A) 端口0 中斷狀態標志 端口0,bit7 ~ 0輸入中斷狀態標志。當輸入端口中斷請求后,其相應的標志位將會被置為1.
IEN2 (0x9A) 中斷使能1 P0IE(bit5) 端口1中斷使能
0 : 中斷禁止
1 : 中斷使能
EA 中斷的總開關 只有打開該開關,中斷才能傳入51芯片
0 : 中斷禁止
1 : 中斷使能

1.3 CC2530中斷走向圖

image_1bq9vkesqg0q1av8nqi14477hq9.png-423.6kB
如上圖所示,如果P1端口發生中斷,需要傳入51內核中,流程如下圖所示.

7

所以,我們對中斷進行初始化的一個流程也和上圖一樣,一層一層的將中斷使能開關打開。

1.4 使用C語言為51單片機編寫中斷程序

使用C語言為51單片機編寫中斷程序,有一個特殊的函數聲明形式。如以下代碼所示:

#pragma vector = 中斷向量地址
__interrupt void P01_ISR(void)
{
    /*Do something*/
}

其中中斷向量地址,可以在ioCC2530.h頭文件中找到,可以直接使用宏定義字符替換。

/* --------------------------------------------------------------------------
 *                          Interrupt Vectors
 * --------------------------------------------------------------------------
 */
#define  RFERR_VECTOR   VECT(  0, 0x03 )   /*  RF TX FIFO下溢和RX FIFO溢出*/
#define  ADC_VECTOR     VECT(  1, 0x0B )   /*  ADC轉換結束*/
#define  URX0_VECTOR    VECT(  2, 0x13 )   /*  USART0 RX完成*/
#define  URX1_VECTOR    VECT(  3, 0x1B )   /*  USART1 RX完成*/
#define  ENC_VECTOR     VECT(  4, 0x23 )   /*  AES加密/解密完成*/
#define  ST_VECTOR      VECT(  5, 0x2B )   /*  睡眠定時器比較*/
#define  P2INT_VECTOR   VECT(  6, 0x33 )   /*  端口2輸入*/
#define  UTX0_VECTOR    VECT(  7, 0x3B )   /*  USART0 TX完成*/
#define  DMA_VECTOR     VECT(  8, 0x43 )   /*  DMA傳輸完成*/
#define  T1_VECTOR      VECT(  9, 0x4B )   /*  定時器1(16位)捕捉/比較/溢出 */
#define  T2_VECTOR      VECT( 10, 0x53 )   /*  定時器2(MAC定時器)*/
#define  T3_VECTOR      VECT( 11, 0x5B )   /*  定時器3(8位)捕捉/比較/溢出*/
#define  T4_VECTOR      VECT( 12, 0x63 )   /*  定時器4(8位)捕捉/比較/溢出*/
#define  P0INT_VECTOR   VECT( 13, 0x6B )   /*  端口0輸入*/
#define  UTX1_VECTOR    VECT( 14, 0x73 )   /*  USART1 TX完成*/
#define  P1INT_VECTOR   VECT( 15, 0x7B )   /*  端口1輸入*/
#define  RF_VECTOR      VECT( 16, 0x83 )   /*  射頻通用中斷*/
#define  WDT_VECTOR     VECT( 17, 0x8B )   /*  定時器模式下看門狗溢出*/

1.5 *函數指針

本節為選擇學習內容,是筆者在學習按鍵中斷時,思考的一個問題。想實現高級語言中事件機制,在高級語言中事件主要是靠方法指針和觀察者設計模式一並完成。方法指針就是一個指向方法的指針。而C語言中的指針一樣可以指向一個函數。如:

例1,簡單的事件實現,函數指針。
#include <ioCC2530.h>
typedef unsigned int uint;
/************************/
void (*timer_ow)(); // 定義一個返回值為void參數為空的函數指針
int (*timer_ow1)(); // 定義一個返回值為int參數為void的函數指針
int (*timer_ow2)(int); // 定義一個返回值為int參數為int的函數指針
/************************/
void timer_Overflow(void)
{
    /*Do something*/
}
int timer_Overflow1(void)
{
    /*Do something*/
}
int timer_Overflow2(int z)
{
    /*Do something*/
}
void main(void)
{
    // 將函數timer_Overflow賦值給函數指針timer_ow
    timer_ow = timer_Overflow;
    // 調用函數指針
    (*timer_ow)();
    
    timer_ow1 = timer_Overflow1;
    int result = (*timer_ow1)();
    
    timer_ow2 = timer_Overflow2;
    result = (*timer_ow2)(result);
}

2. 程序代碼

#include <ioCC2530.h>

// 初始化通用端口
void init_gpio(void)
{
  // 將p1_0,1,2設置成GPIO
  P1SEL &=~ 0x07;
  // 將p1_0,1設置成輸出
  P1DIR |= 0x03;
  // 將p1_2設置成輸入
  P1DIR &=~ 0x04;
  // 下拉P1全部端口,使LED全滅
  P1 = 0x00;
  // 設置端口1為上下拉功能
  P1INP &=~ 0x04;
  // 設置端口1輸入模式為上拉
  P2INP &=~ 0x40;
}

// 初始化通用端口中斷
void init_gpio_interrupt(void)
{
  // 將P1設置為輸入下降沿引起中斷
  PICTL |= 0x02;
  // 設置P1引腳2為中斷使能
  P1IEN |= 0x04;
  // 設置端口P1為中斷使能
  IEN2 |= 0x10;
  // 打開中斷總開關
  EA = 1;
  
  //清空中斷標志
  P1IFG = 0;
  P1IF = 0;
}

#pragma vector = P1INT_VECTOR
__interrupt void P1_ISR(void)
{
  // 判斷中斷信號是否從P1.2 SW1引腳發生
  if(P1IFG == 0x04)
  {
      // 讓LED翻轉
      P1_0 = ~P1_0;
      P1_1 = ~P1_1;
  }
  // 清空中斷標志
  P1IFG = 0;
  P1IF = 0;
}

void main()
{
  init_gpio();
  init_gpio_interrupt();
  while(1){;}
}

代碼並沒有特別困難的地方,根據前面的預備知識和流程圖基本可以看得懂。

THE END


免責聲明!

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



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