- 通信模式
- CPU与外设之间的通信模式;
- 并行通信:一次传输多个比特;
- 串行通信:是将传输数据的每个字符一位接一位(例如先低位、后高位)地传送;
- 图1 通信模式
-
RS232 |
Recommended Standard |
UART |
Universal Asynchronous Receiver/Transmitter |
JTAG |
Joint Test Action Group |
Morse Code |
莫尔斯电码
|
SPI |
Serial Peripheral Interface |
MIDI |
Musical Instrument Digital Interface |
USB |
Universal Serial Bus |
- 表1 常见串口通信协议
- UART
- 通用异步收发器,是一种通用的串行 [1]、异步[2]通信总线;
- 实现全双工[3]的发送和接收;
- 广泛应用于嵌入式系统中主机和外设之间的通信;
- [1]串行通信
- 信号线少:分时使用同一传输通道,最少用一对线即可[收发];全双工通信;
- 实现较容易:允许双方使用各自的时钟信号,且时钟频率可以有一定误差;
- 效率较低:每个字符都要独立确定起始位和结束位;
- 起始位为低电平;结束位为高电平;数据线空闲时默认是高电平;
- [2]异步通信
-
同步:所有设备使用同一个时钟信号;以数据块为单位传送数据,包括同步字符、数据块和校验字符。同步字符位于数据块的开头,用于确认数据字符的开始;接收时,接收设备连续不断地对传输线采样,并把接收到的字符与双方约定的同步字符进行比较,只有比较成功后才会把后面接收到的字符加以存储;同步通信的优点是数据传输速率高,缺点是要求发送时钟和接收时钟保持严格同步。对硬件结构要求较高;
- 异步:每个设备使用自己的时钟信号;以字符为单位进行数据传送,每一个字符均按照固定的格式传送,又被称为帧,即异步串行通信一次传送一个帧;
- [3]全双工通信
-
单工通信 |
半双工通信 |
全双工通信 |
单向通信 |
双向通信,但是不能同时通信 |
双向同时通信 |
一根线 |
二根线 |
二根线 |
- 表2 通信方式
- 图2 通信方式
- 图3 全双工通信过程
- 要求
- 接收方对于同一根线上一连串的数字信号,首先要分割成位,再按位组成字符;
- 为了恢复发送的信息,双方必须协调工作[使用时钟];
- 逐位发送,消除累计误差;
- 帧格式 Frame
- 起始位 start bit
- 数据位 data bit:可以是5bit、6bit、7bit、8bit
- 可选的奇偶校验位 optional parity bit
- 终止位 stop bit
- 波特率 Baud
- 串口通信的速率,单位是每秒传输符号的个数;
- 用来正确区分/截断字符;
- 双方提前约定;不能随便指定,而应从规定的数字当中选择-programmable baud rates;
- 常用波特率:1200、2400、4800、9600、19200、38400、57600、115200;
- 由专门的寄存器通过设置不同的分频实现波特率的选择;
- 图4 帧格式和比特率
- 奇偶校验 parity check
- 通过增加冗余位使得代码中1的个数恒为奇数或偶数的编码方法,以确定代码传输的正确性,是一种检错码,不能纠错;现在网络环境比较好,一般不需要校验;
- 若1的个数是奇数,称为奇校验odd parity ;反之,称为偶校验even parity 需专门设置一个奇偶校验位;采用何种校验应事先约定好;
- 图5 奇偶检验
- RS-232C串行接口
- 美国电子工业协会EIA制定,全称是:数据终端设备( DTE)和数据通信设备(DCE)之间串行二进制数据交换接口技术标准;提供全双工通信;速率20Kbps;通信线长度15m;标准EIA电平,
PC使用的是TTL电平:需电平转换;
- 图6 电平转换
- RS-232C接口物理实现:早期使用DB25针连接;现在都是DB9针连接;实际只用了其中的GEN、TX、RX共3根线,其它为流控AFC–Auto Flow Control;
早期用来通信,现在多为调试使用,所以会禁掉流控;
- 图7 DB9接口和串口配置
-
Pin |
Name |
Desc |
1 |
CD-Carrier Detect |
载波检出,用以确认是否收到 Modem 的载波 |
2 |
RXD-Received Data |
数据输入线 |
3 |
TXD-Transmitted Data |
数据输出线 |
4 |
DTR-Data Terminal Ready |
告知数据终端处于待命状态 |
5 |
SG/GND-Signal Ground |
信号线的接地线(严格的说是信号线的零标准线) |
6 |
DSR-Data Set Ready |
告知本机在待命状态 |
7 |
RTS-Request to Send |
要求发送数据 |
8 |
CTS-Clear to Send |
回应对方发送的 RTS 的发送许可,告诉对方可以发送 |
9 |
RI-Ring Indicator |
响铃指示 |
- 表3 DB9各接口定义
- 几点考虑
- 根据通信速率确定采用的接口标准,如通信距离、通信速率;
- 确定通信的波特率:通信双方一定要一致;
- 确定通信协议:是否需要校验;
- 寄存器
- CC2530的USART串口通信,涉及到的寄存器有:
- UxCSR:USARTx控制和状态寄存器
- UxUCR:USARTx UART控制寄存器
- UxGCR:USARTx 通用控制寄存器
- UxBAUD:USARTx 波特率控制寄存器
- UxBUF:USARTx 接收/发送数据缓冲寄存器
- [1]UxCSR 控制状态寄存器
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
7 |
MODE |
0 |
R |
串口模式选择:0 SPI;1 UART |
6 |
RE |
0 |
R/W |
接收使能:0 关闭;1 允许接收 |
5 |
SLAVE |
0 |
R/W |
SPI主从选择:0 SPI主;1 SPI从 |
4 |
FE |
0 |
R/W |
串口帧错误状态:0 没有错误;1 出现错误 |
3 |
ERR |
0 |
R/W |
串口校验结果:0 没有校验错误;1 字节校验出错 |
2 |
RX_BYTE |
0 |
R/W |
接收状态:0 没有收到数据;1 收到1字节数据 |
1 |
TX_BYTE |
0 |
R/W |
发送状态:0 没有发送;1 最后一次写入U0BUF的数据已经发 |
0 |
ACTIVE |
0 |
R/W |
串口忙标记:0 闲;1 忙 |
- 接收数据时,U0CSR |= 0X40,允许接收;
- 发送数据时,U0CSR &= 0X40,禁止接收;
- [配置示例]使用串口0并准备接收
- 方法1
- U0CSR |= 0x80;//1000 0000;打开串口
- U0CSR |= 0x40;//0000 0100;接收
- 方法2
- U0CSR |= (1<<7);
- U0CSR |= (1<<6);
- 方法3
- U0CSR |= (0x80 | 0x40);
- 方法4
- U0CSR |= (0x3<<6);
- 方法5
- U0CSR |= 0xC0;
- [2]UxUCR UART控制寄存器
- 通常无需设置该寄存器,采用默认值即可;
- U0UCR |= 0x80;//1000 0000;无流控、8位数据位;清空缓冲区
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
7 |
FLUSH |
0 |
R/W |
冲刷单位。当设置将停止当前操作,返回空闲状态 |
6 |
FLOW |
0 |
R/W |
流控制使能。硬件通过RTS和CTS控制流; 0:禁止; 1:使能 |
5 |
D9 |
0 |
R/W |
奇偶位;0: 奇校验;1: 偶校验 |
4 |
BIT9 |
0 |
R/W |
9-bit使能;0:8位传输;1:9位传输 |
3 |
PARITY |
0 |
R/W |
奇偶使能;0:禁止; 1:允许 |
2 |
SPB |
0 |
R/W |
停止位数; 0: 1位停止位; 1: 2位停止位 |
1 |
STOP |
0 |
R/W |
停止位等级必须不同起始位等级; 0: 低停止位; 1: 高停止位 |
0 |
START |
0 |
R |
USART起始位等级; 0: 低起始位; 1: 高起始位 |
- [3]UxGCR 通用控制寄存器
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
7 |
CPOL |
0 |
R/W |
SPI 时钟极性:0:低电平空闲;1:高电平空闲 |
6 |
CPHA |
0 |
R/W |
SPI 时钟相位
0:由 CPOL 跳向非 CPOL 时采样,由非 CPOL跳向 CPOL 时输出
1:由非 CPOL 跳向 CPOL 时采样,由 CPOL跳向非 CPOL 时输出
|
5 |
ORDER |
0 |
R/W |
传输位序:0:低位在先;1: 高位在先 |
4-0 |
BAUD_E[4:0] |
0x00 |
R/W |
波特率指数值,BAUD_M 决定波特率 |
- [4]UxBAUD 波特率控制寄存器
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
7-0 |
BAUD_M[7:0] |
0x00 |
R/W |
波特率尾数,与 BAUD_E 决定波特率 |
- 注意:设置波特率,需要同时操作UxGCR和UxBAUD;
- [配置示例]波特率设为57600
- U0GCR |= 10
- U0BAUD |= 216
- [配置示例]波特率设为115200
- U0GCR |= 11
- U0BAUD |= 216
- [5]UxDBUF 收发缓冲寄存器
- 通过UxDBUF来发送和接收数据
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
7-0 |
DATA[7:0] |
0x00 |
R/W |
UARTx收发缓存寄存器 |
- PERCFG 外设配置寄存器
- 两个USART接口具有相同的功能,通过PERCFG寄存器可以设置两个USART接口对应外部I/O引脚的映射关系;0为默认位置1,1为默认位置2;
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
1 |
U1CFG |
0 |
R/W |
UART1的映射位置:0->alt 1;1->alt 2 |
0 |
U0CFG |
0 |
R/W |
UART0的映射位置:0->alt 1;1->alt 2 |
- 位置映射
-
UART0 |
UART1 |
alt 1 |
TX:P0_3 RX:P0_2 |
alt 1 |
TX:P0_5 RX:P0_4 |
alt 2 |
TX:P1_5 RX:P1_4 |
alt 2 |
TX:P1_6 RX:P1_7 |
- [配置实例]PERCFG = 0x00;//使用UART0的备用位置1(即P0_2,P0_3)
- [配置实例]PERCFG |= 1;//使用UART0的备用位置2(即P1_4,P1_5)
- CLKCONCMD 时钟控制命令寄存器
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
7 |
OSC32K |
1 |
R/W |
32Khz时钟源选择:
0 32Khz的晶体振荡器;
1 32Khz的RC振荡器 |
6 |
OSC |
1 |
R/W |
系统主时钟源选择:
0 32Mhz的晶体振荡器;
1 16Mhz的RC振荡器 |
5-3 |
TICKSPD[2:0]
|
001 |
R/W |
计数时钟:不能超过系统时钟
000 32Mhz; 100 2Mhz
001 16Mhz; 101 1Mhz
010 8Mhz; 110 500Khz
011 4Mhz; 111 250Khz |
2-0 |
CLKSPD |
001 |
R/W |
时钟速度:不能超过系统时钟;取值同TICKSPD |
- SLEEPSTA 睡眠模式控制状态寄存器
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
7 |
OSC32K_CALDIS |
0 |
R |
32Khz RC振荡器校准状态 |
6:5 |
- |
00 |
R |
保留 |
4-3 |
RST[1:0] |
XX |
R |
状态位,表示上一次复位的原因;只保留最新的复位事件
00 上电复位和掉电探测;01 外部复位
10 看门狗定时器复位;11 时钟丢失复位 |
2-1 |
- |
00 |
R |
保留 |
0 |
CLK32K |
0 |
R |
32Khz时钟信号(与系统时钟同步) |
- 注意:时钟切换必须等待稳定;
- [配置示例]选择32Mhz
- CLKCONCMD &= ~0x40; //或CLKCONCMD &= ~(1<<6)
- while(!(SLEEPSTA & 0x40)); //等待 XSOC稳定
- CLKCONCMD = 0xb8; //1 0 111 000;TICHSPD[128分频],CLKSPD[不分频]
- IENx 中断使能寄存器
-
位号 |
位名 |
复位值 |
操作性 |
说明 |
7 |
EA |
0 |
R |
中断系统使能控制,即:总中断;0 禁止所有中断;1 允许所有中断 |
6 |
- |
0 |
R |
保留 |
5 |
STIE |
0 |
R/W |
睡眠定时器中断使能:0 中断禁止;1 中断使能 |
4 |
ENCIE |
0 |
R/W |
AES加密/解密中断使能:0 中断禁止;1 中断使能 |
3 |
URX1IE |
0 |
R/W |
USART1接收中断使能:0 中断禁止;1 中断使能 |
2 |
URX0IE |
0 |
R/W |
USART0接收中断使能:0 中断禁止;1 中断使能 |
1 |
ADCIE |
0 |
R/W |
ADC中断使能:0 中断禁止;1 中断使能 |
0 |
RFERRIE |
0 |
R/W |
RF收发中断使能:0 中断禁止;1 中断使能 |
- 中断寄存器
- UTX0IF来判断是否发送完成 ,为1则发送成功;
- URX0IF来判断是否接受完成,为1则接收成功;
- 更多中断请点击访问 Interrupt
- 实操1
- 发送字符串
-
#include "ioCC2530.h"
#include "string.h"
#include "../lib/delay.h"
typedef unsigned char uchar;
typedef unsigned int uint;
#define TX_SIZE 20
#define TX_STRING "Hello Zigbee... "
void Init32M( void )
{
CLKCONCMD &= ~0x40; //设置系统时钟源为32MHZ晶振
while( CLKCONSTA & 0x40 ); //等待晶振稳定为32M
CLKCONCMD &= ~0x47; //设置系统主时钟频率为32MHZ
SLEEPCMD |= 0x04; //关闭不用的RC振荡器
}
void InitUart( void )
{
PERCFG = 0x00; //外设控制寄存器 USART 0的IO位置:0为P0口位置1
P0SEL = 0x0c; //P0_2,P0_3用作串口(外设功能)
P2DIR &= ~0XC0; //P0优先作为UART0
U0CSR |= 0x80; //设置为UART方式
U0GCR |= 11;
U0BAUD |= 216; //波特率设为115200
UTX0IF = 0; //UART0 TX中断标志初始置位0
}
void UartSendString( char *Data, int len )
{
uint i;
for( i = 0; i < len; i++ )
{
U0DBUF = *Data++;
while( UTX0IF == 0 );
UTX0IF = 0;
}
}
void main( void )
{
char TxData[TX_SIZE];
Init32M();
InitUart(); //调置串口相关寄存器
memset( TxData, 0, TX_SIZE ); //数据清0
memcpy( TxData, TX_STRING, sizeof( TX_STRING ) ); //复制发送字符串到TxData
while( 1 )
{
UartSendString( TxData, sizeof( TX_STRING ) ); //串口发送数据
delay( 1000 );
}
}
- 实操2
- 利用IO发送字符串
-
#include "ioCC2530.h"
#include "../lib/delay.h"
char uart_buffer;
void InitIO( void );
void InitUART( void );
void Init32M( void );
void UartTX_Send_String( unsigned char *Data, int len );
void UartTX_Send_Data( unsigned char Data, int len );
#pragma vector=URX0_VECTOR
__interrupt void uart0( void )
{
URX0IF = 0;//清中断标志
P0_0 = ~P0_0;
uart_buffer = U0DBUF;
//UartTX_Send_String("welcome",10);
UartTX_Send_Data( uart_buffer, 1 );
}
void main( void )
{
unsigned char buf[4];
//InitIO();[NOT MUST]
Init32M();
InitUART();
buf[0] = '\t';
while( 1 )
{
P2_0 = ~P2_0;
delay( 1000 );
if( uart_buffer == 0x01 ) //按照16进制输入[cnplaman]
{
UartTX_Send_String( "welcome", 7 ); //串口接收要发送的数据
UartTX_Send_String( &buf[0], 1 ); //串口发送接收的数据
}
}
}
void InitIO( void )
{
P0DIR |= 0x01; //设置P0.0为输出方式[P0.4和P0.5为输入方式???]
P2DIR |= 0x01; //设置P2.0为输出方式
P0_0 = 1; //高电平截至
P2_0 = 1; //高电平截至
}
void InitUART( void )
{
PERCFG = 0x00; //外设控制寄存器UART0:P0口位置1:RX0 - P0_2;TX0 - P0_3
P0SEL = 0x0C; //0011 1100:P0_2,P0_3 用作串口(外设功能);[0x3c]
P2DIR &= ~0xC0; //设置P0口优先为UART0,即串口0优先级最高;其次是串口1,再是计时器1;P2DIR[7-6]PRIP0:00
U0CSR |= 0x80; //1000 0000;UART方式
U0GCR |= 10; //baud_e = 10;
U0BAUD |= 216; //波特率设为57600
UTX0IF = 0; //清除UART0 TX中断标志:置0
U0CSR |= 0x40; //允许接收
IEN0 |= 0x84; //1000 0100开总中断,允许接收中断
}
void Init32M( void )
{
CLKCONCMD &= ~0x40; //选择32M晶振
while( !( SLEEPSTA & 0x40 ) ); //等待XSOC稳定
CLKCONCMD = 0xb8; //TICHSPD 128分频,CLKSPD 不分频
SLEEPCMD |= 0x04; //关闭不用的RC 振荡器[cnplaman:not MUST]}
}
void UartTX_Send_String( unsigned char *Data, int len )
{
for( int j = 0; j < len; j++ )
{
U0DBUF = *Data++;
while( UTX0IF == 0 );
UTX0IF = 0;
}
}
void UartTX_Send_Data( unsigned char Data, int len )
{
for( int j = 0; j < len; j++ )
{
U0DBUF = Data;
while( UTX0IF == 0 );
UTX0IF = 0;
}
}
- 实操3
- 利用IO控制LED
-
#include “ioCC2530.h”
#define uint unsigned int
#define uchar unsigned char
#define LED1 P0_0 //定义P0_0为LED1的控制引脚
#define LED2 P2_0 //定义P2_0为LED2的控制引脚
void InitIO(); //声明LED初始化函数
void InitUART(); //声明串口0初始化函数
void Init32M(); //声明初始化32M时钟初始化函数
void UR0SendByte( unsigned char Byte ); //声明发送一个字节初始化函数
void UR0SendString( unsigned char *str ); //声明发送字符串初始化函数
void Execute_CMD(); //声明执行上位机命令初始化函数
char RxBuf; //定义接收缓冲区
char Rx_flag; //定义串口接收标志位
#pragma vector = URX0_VECTOR
__interrupt void URX0_ISR()
{
URX0IF = 0; //清中断标志位
RxBuf = U0DBUF; //将缓冲寄存器的数据给读出来
Rx_flag = 1; //接收标志位置1
}
void main()
{
InitIO(); //初始化LED端口
InitUART(); //初始化串口0
Init32M(); //初始化32M晶振
UR0SendString( "Hello ZigBee!\r\n" );
while( 1 )
{
if( Rx_flag == 1 ) //是否接收到上位机指令
{
Execute_CMD(); //判断并执行上位机指令
}
}
}
/*===================LED初始化函数==================*/
void InitIO()
{
P0SEL &= ~0x01; //将P1_0和P1_1设置为通用I/O端口功能
P0DIR |= 0x01; //将P1_0和P1_1的端口设置为输出
P2SEL &= ~0x01;
P2DIR |= 0x01;
LED1 = 1; //关闭LED1灯
LED2 = 1; //关闭LED2灯
}
void Init32M()
{
CLKCONCMD &= ~0x40; //系统时钟源选择:外部32MHz 。
while( !( SLEEPSTA & 0x40 ) ); //等待晶振稳定
CLKCONCMD &= ~0x47; //128分频 CLKSPD不发分频
SLEEPCMD |= 0x04; //关闭不用的RC振荡器
}
void InitUART()
{
PERCFG = 0x00; //外设控制寄存器USART 0 的IO位置:
P0SEL = 0x0C; //设置P0_2,P_3为外设功能
P2DIR &= ~0xC0; //设置P0口优先为UART0,即串口0优先级最高
U0CSR |= 0xC0; //设置为UART模式
U0GCR |= 10; //查表
U0BAUD |= 216; //设置波特率为57600
U0UCR |= 0x80; //无流控,8位数据位,清空缓冲区
UTX0IF = 0; //串口0TX发送中断标志位清0:清除中断标记
URX0IF = 0; //串口0RX接收中断标志位清0:清除中断标记
URX0IE = 1; //开串口0接收中断:使能串口0中断
EA = 1; //开中断总开关
}
/*================串口0发送一个字节函数==============*/
void UR0SendByte( unsigned char Byte )
{
U0DBUF = Byte; //将要发送的一个字节数据写入U0DBUF
while( !UTX0IF ); //等待TX中断标志,即数据发送完成
UTX0IF = 0; //清除TX中断标志,准备下一次发送
}
/*================串口0发送字符串函数================*/
void UR0SendString( unsigned char *str )
{
while( *str != '\0' )
{
UR0SendByte( *str++ ); //逐个发送字符串中的字节
}
}
/*================执行上位机指令函数=================*/
void Execute_CMD()
{
Rx_flag = 0; //清0接收标志位
switch( RxBuf ) //通过上位机发送的命令,判断并执行
{
case 0xF1: //如果PC发送00xF1 则点亮LED1 并串口发送字符串
LED1 = 0;
UR0SendString( "The LED1 is Open!\r\n" );
break;
case 0xF2: //如果PC发送0xF2 则熄灭LED1 并串口发送字符串
LED1 = 1;
UR0SendString( "The LED1 is Closed!\r\n" );
break;
case 0xF3: //如果PC发送0xF3 则点亮LED2 并串口发送字符串
LED2 = 0;
UR0SendString( "The LED2 is Open!\r\n" );
break;
case 0xF4: //如果PC发送0xF4 则熄灭LED2 并串口发送字符串
LED2 = 1;
UR0SendString( "The LED2 is Closed!\r\n" );
break;
default:
UR0SendString( "F1 F2 F3 F4!\r\n" );
break;
}
}
- 实验目的
- 1. 掌握CC 2530 UART串口寄存器设置;
- 2. 掌握UART串口中断函数程序的编程方法;
- 实验内容
- 在IAR集成开发环境中编写定时器中断程序;通过按键以串行方式发送指定数据;即:上位机PC通过串口助手向CC2530发送一个数据命令;
CC2530先接收,然后判断并执行相应的命令;
- 预备知识
- 1. 串口通信;
- 2. 了解C语言的基本知识;
- 3. 了解IAR中编写和调试程序的方法;
- 实验需求
- 安装IAR和相关驱动的个人PC1台
- 迷你USB线mini USB1根
- 仿真器CC Debugger1根
- 串并转换线USB to UART1根
- ZigBee通用节点板1块
- 实验步骤
- 1.创建IAR工作空间;
- 2.创建基于C的IAR工程;
- 3.编辑代码并调试;可参考提供的源码,调试应无差错、无告警;
- 4.试验箱上电;使用mini USB分别连接CC Debugger和PC;并将仿真器CC Debugger的另外一端和ZigBee通用节点板上的JTAG插座相连;
- 5.按下仿真器CC Debugger的复位按钮RESET,绿灯常亮表示模块连接成功,可以往芯片中烧写程序;每次烧写程序都需要复位,确保仿真器是绿灯状态;
- 6.在IAR中点击下载并调试按钮download and debug(CTRL+D)烧写程序;
- 7.在IAR的调试窗口中,点击[全速]运行;
- 8.用串并转换线USB to UART线连接节点板串口和PC机某USB接口,在PC设备管理器中确认串口端口;
- 9.打开PC机上的串口调试助手,选择对应的串口、波特率及8位数据、1位停止、无校验、无流控;
- 10.利用串口调试助手操作串口发送数据;
- 开发过程中,请注意CTRL+S保存项目!
- 项目提升
- 1.修改波特率
- 2.修改控制字符
- 3.修改发送内容
- 4.修改时钟
- 5.按键发送消息
- 6.控制LED灯
- 7.完善项目
- 实验报告
- 1. 根据实操部分的内容,完成项目[三选一];
- 2. 以纸质的形式提交实验报告;
- 3. 论文格式请参照范文[点击下载]。