zoukankan      html  css  js  c++  java
  • 「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; //读取缓冲中的数据
    }
  • 相关阅读:
    USB2.0协议学习笔记---USB工作过程(类的方法)
    USB2.0协议学习笔记---USB数据包结构
    (转)css选择器及其优先级
    通用后台管理系统UI模板-AdminLTE简介及构造动态菜单栏
    css定位研究
    css浮动知识点(转)
    深入理解cookie和session
    js中json知识点
    js中的循环
    jquey中json字符串与json的转换(转)
  • 原文地址:https://www.cnblogs.com/Donut/p/4134085.html
Copyright © 2011-2022 走看看