「ZigBee模塊」基礎實驗(5)串口通訊


一、補充基礎知識

  在CC2530 中,USART0 USART1 是串行通信接口,它們能夠分別運行於異步USART 模式或者同步SPI 模式。兩個USART 的功能是一樣的,並且各自有單獨的IO 引腳。USART里面的A指的就是asynchronous(異步),S指的是synchronous(同步)。這里我們使用異步通信方式。

  UART模式特征:

  ·一次傳89個比特的數據

  ·奇校驗、偶校驗或者無校驗位

  ·配置起始位和停止位點平

  ·配置LSB或者MSB首先傳送

  ·獨立收發中斷

  ·獨立收發DMA觸發

  UART模式下可以進行全雙工異步通信,UART發送的一個字節由一個起始位,8個數據位,第9個數據位或者奇偶校驗位,一或二個結束位組成。

1

2

3

4

5

6

7

8

9

10

12

13

起始位

數據位

數據位或奇偶校驗位

結束位

  UART的控制和狀態寄存器:U0CSRU1CSR

  UART的控制寄存器:U0UCRU1UCR

  (01分別對應UART0UART1

  把UxCSR.MODE1即選中UART模式

  UART0  P0_2——RX

          P0_3——TX

  UART1  P0_5——RX

          P0_4——TX

 

二、實驗目的和步驟

1. 實驗目的:實現串口發送、接收、控制LED

2. 實驗步驟

 我把實驗分成三個小實驗,逐步實現

   ①實現串口發送數據

 ②實現串口發送和接收數據

   ③實現控制LED功能

 

三、USB轉串口部分原理圖

 

 

四、實驗1——串口發送數據

1. 寄存器及波特率計算

  本次實驗串口相關的寄存器和標志位有:U0CSRU0GCRU0BAUDU0DBUFUTX0IF、PERCFG、P2DIR

  相關功能見下表

U0CSR

UART0控制和狀態寄存器)

Bit7:MODE

0:SPI模式

1:UART模式

Bit6:RE

0:接收器禁止

1:接收器使能

Bit5:SLAVE

0:SPI主模式

1:SPI從模式

Bit4:FE

0:沒有檢測出幀錯誤

1:收到字節停止位電平出錯

Bit3:ERR

0:沒有檢測出奇偶校驗出錯

1:收到字節奇偶校驗出錯

Bit2:RX_BYTE

0:沒有收到字節

1:收到字節就緒

Bit1:TX_BYTE

0:沒有發送字節

1:寫到數據緩沖區寄存器的最后字節已經發送

Bit0:ACTIVE

0:UART空閑

1:UART

U0GCR

UART0通用控制寄存器)

Bit7:CPOL

0:SPI負時鍾極性

1:SPI正時鍾極性

Bit6:CPHA

0:當來自CPOLSCK反相之后又返回CPOL時,數據輸出到MOSI;當來自CPOLSCK返回CPOL反相時,輸入數據采樣到MISO

1:當來自CPOLSCK返回CPOL反相時,數據輸出到MISO;當來自CPOLSCK反相之后又返回CPOL時,輸入數據采樣到MOSI

Bit5:ORDER

0:LSB先傳送

1:MSB先傳送

Bit[4-0]

BAUD_E

波特率指數值 BAUD_EBAUD_M一起決定了UART的波特率

U0BAUD

UART0波特率控制寄存器)

Bit[7-0]

BAUD_M

 

波特率尾數值 BAUD_EBAUD_M一起決定了UART的波特率

U0DBUFUART0收發數據緩沖區)

 

串口發送/接收數據緩沖區

UTX0IF

中斷標志

IRCON2Bit1

(UART0字節發送完成標志位)

0:中斷未掛起

未發送完

1:中斷掛起

發送完畢

 

串口波特率公式:

 

32Mhz系統時鍾的常用波特率設置

波特率(bps)

UxBaud.BAUD_M

UxGCR.BAUD_E

誤差(%)

2400

59

6

0.14

4800

59

7

0.14

9600

59

8

0.14

14400

216

8

0.03

19200

59

9

0.14

28800

216

9

0.03

38400

59

10

0.14

57600

216

10

0.03

76800

59

11

0.14

115200

216

11

0.03

230400

216

12

0.03

   端口

Bit位

名稱

初始化

讀/寫

描述

PERCFG

外設控制寄存器

7

---

0

R0

未使用

6

T1CFG

0

R/W

計時器1的I/O位置:

0:選擇到位置1(Alt.1)

1:選擇到位置2(Alt.2)

5

T3CFG

0

R/W

計時器3的I/O位置:

0:選擇到位置1(Alt.1)

1:選擇到位置2(Alt.2)

4

T4CFG

0

R/W

計時器4的I/O位置:

0:選擇到位置1(Alt.1)

1:選擇到位置2(Alt.2)

3:2

---

00

R/W

未使用

1

U1CFG

0

R/W

USART 1的I/O位置:

0:選擇到位置1(P0_4、P0_5)

1:選擇到位置2(P1_6、P1_7)

0

U0CFG

0

R/W

USART 0的I/O位置:

0:選擇到位置1(P0_2、P0_3)

1:選擇到位置2(P1_4、P1_5)

P2DIR

7:6

PRIP0[1:0]

00

R/W

端口0外設優先級控制,當PERCFG分配給一些外設相同引腳的時候,這些位將確定優先級。優先級從前到后如下:

00:USART 0,USART 1,Timer 1

01:USART 1,USART 0,Timer 1

10:Timer 1 channels 0-1,USART 1,USART 0,Timer 1 channels 2-3

11:Timer 1 channels 2-3,

USART 0,USART 1,Timer 1 channels 0-1

 

5

---

0

R0

未使用

 

4:0

DIRP2_[4:0]

00000

R/W

P2.4—P2.0的方向

(0:輸入 1:輸出)

 

2.串口初始化代碼

void uartInit()
{
  //先設置晶振
  CLKCONCMD &= ~0x40;           //設置系統時鍾源為32MHz晶振
  while(CLKCONSTA & 0x40);      //等待晶振穩定為32M
  CLKCONCMD &= ~0x47;           //設置系統主時鍾頻率為32MHz
  
  //先把串口通信相應引腳初始化下
  PERCFG &= ~0x01;              //位置1,即P0口
  P0SEL  |=  0x0c;              //P0_2、P0_3用作串口
  P2DIR  &= ~0xc0;              //P0優先作為UART0
  
  //再配置串口
  U0CSR  |= 0x80;               //設置為UART方式
  U0GCR  |= 11;                 //設置波特率115200
  U0BAUD |= 216;                //|
  UTX0IF  = 0;                  //UART0 TX中斷標志初始位
  
}

3. 串口發送代碼

void uartSend(char *Data, int len)
{
  int j;
  for(j=0; j<len; j++)         //發送設定長度個字節
  {
    U0DBUF = *Data++;          //當前字節放入緩存並指向下一個字節
    while(UTX0IF == 0);        //等待標志位置1,表示當前字節發送完了
    UTX0IF = 0;                //手動置0,准備發送下一個字節
  }
}

4. 完整代碼

#include <ioCC2530.h>
#include <string.h> 

#define uchar unsigned char
#define uint  unsigned int

//引腳定義
#define led1 P1_0

//函數聲明
void delayms(uint ms);              //延時函數
void ledInit();                     //led初始化
void uartInit();                    //串口初始化
void uartSend(char *Data, int len); //串口發送

//變量聲明
char Txdata[14];                  

/*************************************
延時函數
*************************************/
void delayms(uint ms)
{
  uint i, j;
  for(i=ms; i>0; i--)
    for(j=1774; j>0; j--);
}

/*************************************
led初始化
*************************************/
void ledInit()
{
  P1SEL &= ~0x01;
  P1DIR |= 0x01;
  P1INP &= ~0x01;
  
  led1 = 1;
}

/*************************************
串口初始化
*************************************/
void uartInit()
{
  //先設置晶振
  CLKCONCMD &= ~0x40;           //設置系統時鍾源為32MHz晶振
  while(CLKCONSTA & 0x40);      //等待晶振穩定為32M
  CLKCONCMD &= ~0x47;           //設置系統主時鍾頻率為32MHz
  
  //先把串口通信相應引腳初始化下
  PERCFG &= ~0x01;              //位置1,即P0口
  P0SEL  |=  0x0c;              //P0_2、P0_3用作串口
  P2DIR  &= ~0xc0;              //P0優先作為UART0
  
  //再配置串口
  U0CSR  |= 0x80;               //設置為UART方式
  U0GCR  |= 11;                 //設置波特率115200
  U0BAUD |= 216;                //|
  UTX0IF  = 0;                  //UART0 TX中斷標志初始位
  
}

/*************************************
串口發送
*************************************/
void uartSend(char *Data, int len)
{
  int j;
  for(j=0; j<len; j++)         //發送設定長度個字節
  {
    U0DBUF = *Data++;          //當前字節放入緩存並指向下一個字節
    while(UTX0IF == 0);        //等待標志位置1,表示當前字節發送完了
    UTX0IF = 0;                //手動置0,准備發送下一個字節
  }
}

/*************************************
主函數
*************************************/
void main()
{
  ledInit();
  uartInit();
  strcpy(Txdata, "I'm Donut!    ");             //將發送內容復制到Txdata
  while(1)
  {
    uartSend(Txdata, sizeof("I'm Donut!    ")); //串口發送數據
    delayms(1000);                              //延時
    led1 = ~led1;
  }
}

5. 實驗結果

 

注意波特率、數據位之類的不要設置錯!不然會出現亂碼!

五、實驗二——串口收發數據

1. 實驗目的

PC端通過串口發送數據給硬件端(數據長度不超過50,終止符為#),硬件端收到數據后發送回PC

 

2. 再多學一個寄存器和標志位IEN0URX0IF

IEN0(置1為中斷)

 

 位名

 復位值

 操作性

 功能描述

 7

 EA

 0

 /

 中斷總開關

 6

 

 0

 /

 未用

 5

 STIE

 0

 /

 睡眠定時器中斷使能

 4

 ENCIE

 0

 /

 AES/解密,完成中斷使能

 3

 URX1IE/I2SRXIE

 0

 /

 USART1/I^2S接受中斷

 2

 URX0IE

 0

 /

 USART0接受中斷

 1

 ADCIE

 0

 /

 A/D轉換完成中斷

 0

 RFTXRXIE

 0

 /

 RF收發完成中斷

 

URX0IF

中斷標志

TCONBit3

0USART0接受中斷使能

1:保留,但必須置1

這個URX0IF我的理解就是有數據傳送過來就自動置1,產生中斷,然后需要手動清0

 

3. 程序流程

①初始化(LED、串口)

②接收狀態(沒有收到數據則一直等待、收到數據放到指定數組里、數組放滿或收到終止符轉到發送狀態)

③發送狀態(關閉數據接收中斷、發送數據直至發完、打開中斷、轉到接收狀態)

④接收狀態里面的數據是怎么收到的?用串口中斷!接收到的數據會放到緩沖區,中斷程序的任務就是把緩沖區的數據讀出來!

 

4. 完整代碼

#include <ioCC2530.h>
#include <string.h>

#define uchar unsigned char
#define uint  unsigned int

//引腳定義
#define led1 P1_0
#define led2 P1_1

//函數聲明
void delayms(uint ms);               //延時函數
void ledInit();                      //led初始化
void uartInit();                     //串口初始化
void uartSend(char *Data, int len);  //串口發送函數

//變量聲明
uchar RXTXflag = 1;                  //選擇標志位,決定接收數據還是發送數據
char  temp;                          //存放接收到的數據 
uchar datanumber = 0;                //累計一次接收的數據個數
char  Rxdata[50];                    //一次最多接收50個字符

/***********************************
延時函數
***********************************/
void delayms(uint ms)
{
  int i, j;
  for(i=ms; i>0; i--)
    for(j=1156; j>0; j--);
}

/***********************************
led初始化
***********************************/
void ledInit()
{
  P1SEL &= ~0x03;
  P1DIR |= 0x03;
  P1INP &= ~0x03; 
  
  led1 = 0;
  led2 = 0;
}

/***********************************
串口初始化
***********************************/
void uartInit()
{
  //設置晶振
  CLKCONCMD &= ~0x40;           //設置系統時鍾源為32MHz晶振
  while(CLKCONSTA & 0x40);      //等待晶振穩定為32M
  CLKCONCMD &= ~0x47;           //設置系統主時鍾頻率為32MHz
  
  //串口引腳初始化
  PERCFG &= ~0x01;            //位置1,即P0口
  P0SEL  |=  0x0c;            //P0_2、P0_3用作串口
  P2DIR  &= ~0xc0;            //P0優先作為UART0
  
  //設置串口寄存器
  U0CSR  |= 0x80;              //設置為UART方式
  U0GCR  |= 11;                //設置波特率115200
  U0BAUD |= 216;               //|
  UTX0IF  = 0;                 //UART0 TX中斷標志初始位
  U0CSR  |= 0x40;              //設置UART0允許接收數據
  IEN0   |= 0x84;              //開總中斷、UART0接收中斷
  
}

/***********************************
串口發送函數
***********************************/
void uartSend(char *Data, int len)
{
  int j;
  for(j=0; j<len; j++)         //發送設定長度個字節
  {
    U0DBUF = *Data++;          //當前字節放入緩存並指向下一個字節
    while(UTX0IF == 0);        //等待標志位置1,表示當前字節發送完了
    UTX0IF = 0;                //手動置0,准備發送下一個字節
  }
}

/***********************************
主函數
***********************************/
void main()
{
  //初始化
  ledInit();
  uartInit();
  
  //循環
  while(1)
  {
    if(RXTXflag == 1)          //接收狀態
    {
      led1 = 1;
      if(temp != 0)
      {
        if((temp!='#')&&(datanumber<50)) //如果沒有收到終止符且字符數小於50
          Rxdata[datanumber++] = temp;   //把收到的字符存入數組
        else                             //否則進入發送狀態
        {
          RXTXflag = 3;
          led1 = 0;
        }
        temp = 0;
      } 
    }
    if(RXTXflag == 3)          //發送狀態
    {
      led2 = 1;
      U0CSR &= ~0x40;          //禁止接收
      uartSend(Rxdata, datanumber); //發送已記錄的字符串
      RXTXflag = 1;            //恢復到接收狀態
      datanumber = 0;          //長度重新置0
      led2 = 0;                
      U0CSR |= 0x40;           //允許接收
    }
  }
}

/***********************************
UART0接收中斷
***********************************/
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void)
{
  URX0IF = 0;    //清中斷標志
  temp = U0DBUF; //讀取緩沖中的數據
}

六、實驗三——串口控制LED

1. 實驗目的

發送“L1#”,燈L1改變狀態

發送“L2#”,燈L2改變狀態

 2. 實驗代碼

其實主要思想和實驗二是一樣的,只是對收到的數據進行處理的方式不同

實驗二是把數據發送出去,該實驗則是分析數據並作出響應

#include <ioCC2530.h>
#include <string.h>

#define uchar unsigned char
#define uint  unsigned int

//引腳定義
#define led1 P1_0
#define led2 P1_1

//函數聲明
void delayms(uint ms);               //延時函數
void ledInit();                      //led初始化
void uartInit();                     //串口初始化
void uartSend(char *Data, int len);  //串口發送函數

//變量聲明
uchar RXTXflag = 1;                  //選擇標志位,決定接收數據還是發送數據
char  temp;                          //存放接收到的數據 
uchar datanumber = 0;                //累計一次接收的數據個數
char  Rxdata[50];                    //一次最多接收50個字符

/***********************************
延時函數
***********************************/
void delayms(uint ms)
{
  int i, j;
  for(i=ms; i>0; i--)
    for(j=1156; j>0; j--);
}

/***********************************
led初始化
***********************************/
void ledInit()
{
  P1SEL &= ~0x03;
  P1DIR |= 0x03;
  P1INP &= ~0x03; 
  
  led1 = 1;
  led2 = 1;
}

/***********************************
串口初始化
***********************************/
void uartInit()
{
  //設置晶振
  CLKCONCMD &= ~0x40;           //設置系統時鍾源為32MHz晶振
  while(CLKCONSTA & 0x40);      //等待晶振穩定為32M
  CLKCONCMD &= ~0x47;           //設置系統主時鍾頻率為32MHz
  
  //串口引腳初始化
  PERCFG &= ~0x01;            //位置1,即P0口
  P0SEL  |=  0x0c;            //P0_2、P0_3用作串口
  P2DIR  &= ~0xc0;            //P0優先作為UART0
  
  //設置串口寄存器
  U0CSR  |= 0x80;              //設置為UART方式
  U0GCR  |= 11;                //設置波特率115200
  U0BAUD |= 216;               //|
  UTX0IF  = 0;                 //UART0 TX中斷標志初始位
  U0CSR  |= 0x40;              //設置UART0允許接收數據
  IEN0   |= 0x84;              //開總中斷、UART0接收中斷
  
}

/***********************************
串口發送函數
***********************************/
void uartSend(char *Data, int len)
{
  int j;
  for(j=0; j<len; j++)         //發送設定長度個字節
  {
    U0DBUF = *Data++;          //當前字節放入緩存並指向下一個字節
    while(UTX0IF == 0);        //等待標志位置1,表示當前字節發送完了
    UTX0IF = 0;                //手動置0,准備發送下一個字節
  }
}

/***********************************
主函數
***********************************/
void main()
{
  //初始化
  ledInit();
  uartInit();
  
  //循環
  while(1)
  {
    if(RXTXflag == 1)          //接收狀態
    {
      if(temp != 0)
      {
        if((temp!='#')&&(datanumber<50)) //如果沒有收到終止符且字符數小於50
          Rxdata[datanumber++] = temp;   //把收到的字符存入數組
        else                             //否則進入發送狀態
          RXTXflag = 3;
       
        temp = 0;
      } 
    }
    if(RXTXflag == 3)          //發送狀態
    {
      U0CSR &= ~0x40;          //禁止接收
      
      if(Rxdata[0] == 'L')
      {
        if(Rxdata[1] == '1')
          led1 = ~led1;
        else if(Rxdata[1] == '2')
          led2 = ~led2;
      }
      
      RXTXflag = 1;            //恢復到接收狀態
      datanumber = 0;          //長度重新置0
      U0CSR |= 0x40;           //允許接收
    }
  }
}

/***********************************
UART0接收中斷
***********************************/
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void)
{
  URX0IF = 0;    //清中斷標志
  temp = U0DBUF; //讀取緩沖中的數據
}

 


免責聲明!

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



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