南昌航空大學實驗報告
二0二1年10月18日
課程名稱: 感知層編程實驗 實驗名稱:UART編程
班級學號: 姓名: 同組人: 無
指導教師評定: 簽名:
實驗三 UART編程
實驗目的:
- 加深和鞏固學生對於CC2530串口的理解和掌握
- 讓學生初步掌握CC2530串口編程方法
- 提高學生的上機和編程過程中處理具體問題的能力
實驗要求:
- 實驗要求自己獨立的完成;
- 編寫和調試過程中出現的問題要做好記錄,並事后總結到報告中
- 實驗程序調試完成后, 用給定的平台進行測試,由老師檢查測試結果,並給予相應的成績
- 實驗完成后,要上交實驗報告。
實驗內容:
- 首先完成教材上的串口實驗
- 開發一個新的應用,能夠利用串口消息控制LED燈的亮滅。
- 設計串口通信消息包格式,包含起始字段(2個字節,內容自定)、包長度(1個字節,不CRC字節)、命令碼(1個字節)、CRC字段(1個字節,除CRC之外所有字節的異或和);有上位機到CC2530的命令包,CC2530到上位機的狀態包。
- 命令包括:on/off/toggle,on命令開燈、off關燈、toggle切換燈狀態。
- 采用FSM(有限狀態機)處理命令包。
- 在實驗報告中分別給出源碼。
實驗環境:
集成開發環境為IAR
實驗過程:
首先根據要求設計串口通信包,根據起始字段,包長度,命令碼計算CRC,設計起始位為BF AA,包長為30,命令碼分別為30、31、32,則可以算出CRC分別為13、12、11。在把main函數中代碼里的大串if判斷語句改寫為FSM包判斷在IAR上寫好代碼,debug調試好,再接上cc2530板子燒入,再借助串口調試助手,調好波特率,選擇hex文件,在輸入指令觀察板子亮燈情況以及顯示窗口情況。
實驗代碼:
#include <iocc2530.h>
#include <string.h>
#define uint unsigned int
#define uchar unsigned char
//定義控制燈的端口
#define LED1 P1_0
#define LED2 P1_1
#define LED3 P1_4
void initUART0(void);
void Init_LED_IO(void);
void LED_Services(uchar code);
void sendmsg(char *data);
uint xor(uchar *data);
uint FSM(uchar *buff);
uchar Recdata[6];
uint datanumber = 0;
uint stringlen;
#define STATE1 'a'
#define STATE2 'b'
#define STATE3 'c'
#define STATE4 'd'
#define STATE5 'e'
void initUART0(void)
{
CLKCONCMD &= ~0x40; //設置系統時鍾源為32MHZ晶振
while(CLKCONSTA & 0x40); //等待晶振穩定
CLKCONCMD &= ~0x47; //設置系統主時鍾頻率為32MHZ
PERCFG = 0x00; //位置1 P0口
P0SEL = 0x3c; //P0用作串口
P2DIR &= ~0XC0; //P0優先作為UART0
U0CSR |= 0x80; //串口設置為UART方式
U0GCR |= 11;
U0BAUD |= 216; //波特率設為115200
UTX0IF = 1; //UART0 TX中斷標志初始置位1
U0CSR |= 0X40; //允許接收
IEN0 |= 0x84; //開總中斷,接收中斷
}
void Init_LED_IO(void)
{
P1DIR = 0x13; //P10 P11 P14為輸出
LED1 = 1;
LED3 = 1;
LED2 = 1; //滅LED
}
void main(void)
{
Init_LED_IO();
initUART0();
while(1)
{
if(datanumber==5)
{
if(xor(Recdata) == 1 )
{
sendmsg("Accept Sucess!\r\n");
if(FSM(Recdata) == 1)
{
sendmsg("Data Valid!\r\n");
LED_Services(Recdata[3]);
memset(Recdata,0,6);
datanumber = 0; //指針歸0
}
else
{
sendmsg("Data Invalid!\r\n");
}
}
else
{
sendmsg("Accept False!\r\n");
}
}
}//while
}
void sendmsg(char *data)
{
while(1)
{
if(*data=='\0')
break;
U0DBUF = *data++;
while(UTX0IF == 0);
UTX0IF = 0;
}
}
uint xor(uchar *data)
{
uchar temp = 0;
for(int i=0;i<4;i++)
temp ^= *data++;
if(temp == *data)
return 1;
else
return 0;
}
uint FSM(uchar *buff)
{
uchar state = STATE1;
uchar data;
uint flag = 0;
while(1)
{
data = *buff++;
switch(state)
{
case STATE1:
if(data == 0xBF)
{
state = STATE2;
}
else
flag = 1;
break;
case STATE2:
if(data == 0xAA)
{
state = STATE3;
}
else
flag = 1;
break;
case STATE3:
if(data == 0x36)
{
state = STATE4;
}
else
flag = 1;
break;
case STATE4:
state = STATE5;
break;
default:
break;
}
if(state == STATE5)
{
return 1;
}
if(flag == 1)
{
break;
}
}
return 0;
}
#define on '0'
#define off '1'
#define toggle '2'
void LED_Services(uchar code)
{
switch(code)
{
case on:
LED1 = 0;
LED2 = 0;
break;
case off:
LED1 = 1;
LED2 = 1;
break;
case toggle:
LED1 = !LED1;
LED2 = !LED2;
break;
default:
sendmsg("NO Command Code!");
break;
}
}
#pragma vector = URX0_VECTOR
__interrupt void UART0_ISR(void)
{
URX0IF = 0; //清中斷標志
Recdata[datanumber++] = U0DBUF;
}
實驗結果:
分別輸入BF AA 36 30 13 00,BF AA 36 31 12 00,BF AA 36 32 11 00,三個指令,顯示端口顯示Accept Sucess!和 Data Invalid,led燈情況依次為發亮,熄滅,發亮,若指令出錯,則led燈無現象,顯示端口顯示Accept False!
實驗總結:
這次實驗碰到的主要問題是包的設計以及CRC碼的計算,通過查詢可以了解到循環冗余校驗同其他差錯檢測方式一樣,通過在要傳輸的k比特數據D后添加(n-k)比特冗余位F形成n比特的傳輸幀T,再將其發送出去,可以通過模二運算求得。還有一個便是FSM處理命令包的問題,經過查詢發現它的定義有點難以理解,我理解的就是將根據條件來判斷執行的命令的狀態整合到一個包中。
通過本次實驗加深我們對於CC2530串口的理解和掌握,也讓我們初步掌握CC2530串口編程方法,但通過這次實驗收獲最大的還是通過自學來處理面對的問題的能力,比如FSM包,CRC碼這些最開始老師沒提到,通過自己查找學習來完成實驗,也鍛煉了我們獨立思考,自我學習的能力。
附錄:
UxCSR
| 位 |
名稱 |
復位 |
R/W |
描述 |
| 7 |
MODE |
0 |
R/W |
USART模式選擇 0:SPI模式 1:UART模式 |
| 6 |
RE |
0 |
R/W |
啟動UART接收器。注意UART完全配置之前不能接收。 0:禁止接收器 1:使能接收器 |
| 5 |
SLAVE |
0 |
R/W |
SPI主或者從模式選擇 0:SPI主模式 1:SPI從模式 |
| 4 |
FE |
0 |
R/W0 |
UART幀錯誤狀態 0:無幀錯誤檢測 1:字節收到不正確停止位級別 |
| 3 |
FRR |
0 |
R/W0 |
UART奇偶校驗錯誤狀態 0:無奇偶校驗檢測 1:字節收到奇偶錯誤 |
| 2 |
RX_BYTE |
0 |
R/W0 |
接收字節狀態,UART模式和SPI從模式。當讀U0DBUF該位自動清零,通過寫0清除它,這樣有效丟棄U0BUF中的數據 0:沒有收到字節 1:接收字節就緒 |
| 1 |
TX_BYTE |
0 |
R/W0 |
傳送字節狀態,UART和SPI主模式 0:字節沒有傳送 1:寫到數據緩存寄存器的最后字節已經傳送 |
| 0 |
ACTIVE |
0 |
R |
USART傳送/接收主動狀態 0:USART空閑 1:USART在傳送或者接收模式忙碌 |
UxUCR
| 位 |
名稱 |
復位 |
R/W |
描述 |
| 7 |
FLUSH |
0 |
R/W1 |
清除單元。當設置時,該事件將會立即停止當前操作並返回單元的空閑狀態 |
| 6 |
FLOW |
0 |
R/W |
UART硬件流使能。用RTS和CTS引腳選擇硬件流控制的使用 0:流控制禁止 1:流控制使能 |
| 5 |
D9 |
0 |
R/W |
UART奇偶校驗位。當使能奇偶校驗,寫入D9的值決定發送的第9位的值。如果收到的第9位不匹配收到的字節的奇偶校驗,接收報告ERR。 0:奇校驗 1:偶校驗 |
| 4 |
BIT9 |
0 |
R/W |
UART9位數據使能。當該位是1時,使能奇偶校驗位傳輸即第9位。如果通過PARITY使能奇偶校驗,第9位的內容是通過D9給出的。 0:8位傳輸 1:9位傳輸 |
| 3 |
PARITY |
0 |
R/W |
UART奇偶校驗使能。除了為奇偶校驗設置該位用於計算,必須使能9位模式 0:禁用奇偶校驗 1:使能奇偶校驗 |
| 2 |
SPB |
0 |
R/W |
UART停止位數。選擇要傳送的停止位的位數 0:1位停止位 1:2位停止位 |
| 1 |
STOP |
0 |
R/W |
UART停止位的電平必須不同於開始位的電平 0:停止位低電平 1:停止位高電平 |
| 0 |
START |
0 |
R/W |
UART起始位電平,閑置線的極性采用選擇的起始位級別的電平的相反的電平 0:起始位低電平 1:起始位高電平 |
UxDBUF
| 位 |
名稱 |
復位 |
R/W |
描述 |
| 7:0 |
DATA[7:0] |
0x00 |
R/W |
USART接收和傳送數據。當寫這個寄存器的時候數據被寫到內部的傳送數據寄存器,當讀取該寄存器的時候,數據來自內部讀取的數據寄存器 |
各波特率下寄存器值 :
| 波特率(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 |
