「ZigBee模块」基础实验(5)串口通讯

一、补充基础知识

  在CC2530 中,USART0 和USART1 是串行通信接口,它们能够分别运行于异步USART 模式或者同步SPI 模式。两个USART 的功能是一样的,并且各自有单独的IO 引脚。USART里面的A指的就是asynchronous(异步),S指的是synchronous(同步)。这里我们使用异步通信方式。

  UART模式特征:

  ·一次传8或9个比特的数据

  ·奇校验、偶校验或者无校验位

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

  ·配置LSB或者MSB首先传送

  ·独立收发中断

  ·独立收发DMA触发

  UART模式下可以进行全双工异步通信,UART发送的一个字节由一个起始位,8个数据位,第9个数据位或者奇偶校验位,一或二个结束位组成。


1


2


3


4


5


6


7


8


9


10


12


13


起始位


数据位


数据位或奇偶校验位


结束位

  UART的控制和状态寄存器:U0CSR、U1CSR

  UART的控制寄存器:U0UCR、U1UCR

  (0、1分别对应UART0、UART1)

  把UxCSR.MODE置1即选中UART模式

  UART0  P0_2——RX

      P0_3——TX

  UART1  P0_5——RX

       P0_4——TX

二、实验目的和步骤

1. 实验目的:实现串口发送、接收、控制LED

2. 实验步骤

 我把实验分成三个小实验,逐步实现

①实现串口发送数据

 ②实现串口发送和接收数据

③实现控制LED功能

三、USB转串口部分原理图

四、实验1——串口发送数据

1. 寄存器及波特率计算

  本次实验串口相关的寄存器和标志位有:U0CSR、U0GCR、U0BAUD、U0DBUF、UTX0IF、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:当来自CPOL的SCK反相之后又返回CPOL时,数据输出到MOSI;当来自CPOL的SCK返回CPOL反相时,输入数据采样到MISO


1:当来自CPOL的SCK返回CPOL反相时,数据输出到MISO;当来自CPOL的SCK反相之后又返回CPOL时,输入数据采样到MOSI


Bit5:ORDER


0:LSB先传送


1:MSB先传送


Bit[4-0]:

BAUD_E


波特率指数值 BAUD_E和BAUD_M一起决定了UART的波特率


U0BAUD

(UART0波特率控制寄存器)


Bit[7-0]:

BAUD_M


波特率尾数值 BAUD_E和BAUD_M一起决定了UART的波特率


U0DBUF(UART0收发数据缓冲区)


串口发送/接收数据缓冲区


UTX0IF


中断标志5

IRCON2的Bit1

(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. 再多学一个寄存器和标志位:IEN0、URX0IF

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


中断标志1

TCON的Bit3


0:USART0接受中断使能


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; //读取缓冲中的数据
}
时间: 2024-08-01 10:29:39

「ZigBee模块」基础实验(5)串口通讯的相关文章

「ZigBee模块」基础实验(3)外部中断

1.实现功能 使用中断方式实现: 按键KEY1按下LED1依次亮灭 按键KEY2按下LED2依次亮灭 2.元件连接方式 P1_0连接LED1 P1_1连接LED2 P0_0连接KEY1 P0_1连接KEY2 3.中断相关寄存器 PXIEN P0IEN P1IEN P2IEN 地址 0xAB 0x8D 0xAC PX[7:0] 各个控制口中断使能 (0:中断禁止 1:中断使能) PICTL: D0~D3设置各个端口的中断触发方式(0:上升沿触发 1:下降沿触发) D7控制I/O引脚在输出模式下的驱

「ZigBee模块」基础实验(1)点亮LED

1.IO配置 CC2530 的 IO 口配置需要三个寄存器:PXSEL.PXDIR.PXINP . IO口寄存器 P0 P1 P2 地址 0x80 0x90 0xA0 PXSEL P0SEL P1SEL P2SEL 地址 0xF3 0xF4 0xF5 PX[7:0]功能设置寄存器,默认普通IO口 (0:普通 IO 口 1:第二功能) PXDIR P0DIR P1DIR P2DIR 地址 0xFD 0xFE 0xFF PX[7:0] 输入输出设置寄存器 (0:输入 1:输出) PXINP P0IN

「ZigBee模块」基础实验(2)按键

1.实现功能 按键KEY1按下LED1依次亮灭 按键KEY2按下LED2依次亮灭 2.元件连接方式 P1_0连接LED1 P1_1连接LED2 P0_0连接KEY1 P0_1连接KEY2 3.部分代码分析 按键需要消抖(因为按键选择之后的代码较少,直接写这里面啦) void keyScan() { if(KEY1 == 0) { delayms(10); if(KEY1 == 0) { while(!KEY1); LED1 = !LED1; } } if(KEY2 == 0) { delayms

「ZigBee模块」组网实验-无线点灯

ZigBee入门小实验——无线点灯 写在前面:无线点灯实验不涉及协议栈,只是对Basic RF的应用,但是其中关于数据收发的思想和协议栈类似,可以借鉴.这个代码和实验过程都是参考某教程的,然后有加上自己的理解......欢迎纠错(*^__^*) 一.设备 两个ZigBee模块 一个方口USB线(这个只是供电用,要看自己模块用什么接口,不一定是方口的,用电池也行) 一个编译器 二.几个名词解释 CCM -Counter with CBC-MAC(mode of operation) 就知道和加密有

「ZigBee模块」组网实验-信号传输质量检测

信号传输质量检测 重点在代码分析部分...就是废话比较多... 一.实验平台 两个ZigBee模块 一个方口USB线 一个编译器 二.实验现象 两块ZigBee模块通信,一个模块作发射,另外一个模块作接收,接收模块通过串口在PC机上显示当前的误包率.RSSI值和接收到数据包的个数 三.准备工作 由于硬件平台不同,所以我们需要在per_test中加入串口发送函数 1. 打开工程—>application—>per_test.c 在per_test.c文件中添加串口发送函数 2. INCLUDES

「ZigBee模块」协议栈-Z-Stack协议栈基础和数据传输实验

花了好久写的...感觉还不错的呢...如果看,请细看...Mua~ Z-Stack协议栈基础和数据传输实验 一.实验目的 终端节点将数据无线发送到协调器,协调器通过串口将数据发送到PC端,并在屏幕上显示出来.串口优化把有线串口传输改为无线蓝牙传输. 二.实验平台 硬件:2个zigbee节点,1个编译器,1根方口转USB数据线,一个蓝牙模块 软件:实验基于SampleApp工程进行. 三.实验步骤 串口初始化代码 发送部分代码 接收部分代码 四.协议栈基础 做实验之前先了解一点关于协议栈的基础知识

「ZigBee模块」协议栈-串口透传,打造无线串口模块

前面写比较仔细,后面一个么因为和前面重复了,不多说了,还有个原因...我懒...O(∩_∩)O哈哈~ 串口透传,打造无线串口模块 一.实验目的 两台PC机各使用串口连接一个zigbee模块,连接正确后打开串口调试助手发送信息.利用zigbee将从串口接收到的数据无线传送给另一个zigbee模块,另一个zigbee模块通过串口将数据传给PC端并在屏幕上显示. 二.实验平台 硬件:两个zigbee模块,两台PC机(其实一台也许,连接不同串口即可),编译器,方口转USB数据线两根 软件:基于Z-sta

「ZigBee模块」网络通讯实验-点播、组播、广播

预告下,明天还有最后一个实验<zigbee协议栈管理>......太棒了~马上就如期完成任务啦!哈哈哈 点播.组播.广播 一.基础知识补充 Zigbee的通信方式主要有三种:点播.组播.广播. 点播就是点对点通信,也就是两个设备之间的通信,不允许第三个设备收到信息. 组播就是把网络中的节点分组,每一个组员发出的信息只有相同组号的组员才能收到. 广播,最广泛的就是1个设备上发出的信息所以设备都能接收到. 二.点播实验步骤 因为要将收到的数据通过串口显示在屏幕上,所以在程序开始之前先把串口初始化吧

「ZigBee模块」zigbee协议栈网络管理

Zigbee协议栈网络管理 一.补充基础知识 每个cc2530芯片出厂时候都有一个全球唯一的32位MAC地址,当设备连入网络的时候,每个设备都能获得由协调器分配的16位短地址,协调器默认地址0x0000,很多时候网络就是通过短地址进行管理. 二.实验现象 路由器.设备终端发送自己定义的设备号给协调器,协调器通过接收到的设备号判断设备类型,并且获取设备的短地址,通过串口打印出来. 三.实验步骤 串口初始化 图1 先在SampleApp.c添加串口通信的头文件.(如图1) #include “MT_