感知层编程实验三
南昌航空大学实验报告
二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 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律