⭐❤️zigbee无线通信模块的深入浅出❤️⭐

zigbee是什么

类似于蓝牙或者lora等等,属于物联网终端得一种无线通信技术。
蓝牙:距离较短,功耗低,组网数量不错,数据传输不大。
WiFi:数据量比较大,功耗比较大,比较耗电,无线局域网得数量不大。
zigbee:功耗低,休眠几个ua,也可以进行组网,单网络组网数目比较大。

这三种无线模块的载波都是2.4G频率,穿透能力较差

zigbee模块的选择

一般来说,TI公司和silicon公司的zigbee模块做得比较好

TI:
芯片特点是比较便宜,但是组网没有slilicon稳定,一般学习都使用TI公司生产的
TI方案 zigbee协议栈(ZSTACK)

silicon公司模块:
特点 组网目前来说是最稳定的,但是比较贵

我们通常使用zigbee是用TI公司生产的CC253X系列的模块,我们可以把它当成一个普通的单片机来进行学习,对后面的协议栈分析打下铺垫。
CC2530F256 CPU:8051 RAM:8K Byte Flash: 256K Byte, 工作频率无线通信32M,数据通信量是非常少
250K bps(bit 每秒)芯片的供电电压通常是3.3V

1.实验一:点灯

CC2530 的I/O 控制口一共有21 个,分成3 组,分别是P0、P1 和P2;由图可知,P1_0 与P1_1 分别控制LED1和LED2
在这里插入图片描述
相关寄存器
P1DIR(P1 方向寄存器,P0DIR 同理)

在这里插入图片描述

P1SEL(P1 功能选择寄存器,P0SEL 同理)
在这里插入图片描述

我们只需要配置该引脚的输出方向和功能即可

代码演示

#define LED0 P1_0
#define LED1 P1_1
void GPIO_init()
{
  P1SEL = P1SEL & ~0x03;
  P1DIR = P1DIR |  0x03;  
  LED0 = 0;
  LED1 = 0;
}
void DelayMs(unsigned int msec)//大约1ms延时
{
  for(unsigned int x = msec;x > 0;x --)
  {
    for(unsigned int y = 620;y > 0;y --)
    {
      asm("NOP");
    }    
  }
}
void main(void)
{
  GPIO_init(); 
  while(1)
   {
     DelayMs(500);
     LED0 = 1;
     DelayMs(500);
     LED0 = 0;
     DelayMs(500);
     LED1 = 1;
     DelayMs(500);
     LED1 = 0;      
   }
}

实验现象

两个灯交互闪烁

2.实验二:按键控制灯

从原理图可知,按键没有按下时是高电平,按下之后是低电平,因为接地了。我们需要对P00和P01引脚进行操作
在这里插入图片描述

代码演示

#include <iocc2530.h>
#define LED0 P1_0
#define LED1 P1_1
#define K1   P0_0
#define K2   P0_1
void GPIO_init()
{
  P1SEL = P1SEL & ~0x03;//设置P1_0,P1_1为普通IO口
  P1DIR = P1DIR |  0x03;//设置P1_0,P1_1为输出模式
  P0SEL = P0SEL & ~0x03;//设置P1_0,P1_1为普通IO口
  P0DIR = P0DIR & ~0x03;//设置P1_0,P1_1为输入模式
    
  LED0 = 0;
  LED1 = 0;
}
void DelayMs(unsigned int msec)//大约1ms延时
{
  for(unsigned int x = msec;x > 0;x --)
  {
    for(unsigned int y = 620;y > 0;y --)
    {
      asm("NOP");
    }    
  }
}
void main(void)
{
  GPIO_init(); 
  while(1)
  {
    if(K1 == 0)
     LED0 = 1;
    else
     LED0 = 0;
       
    if(K2 == 0)
    {
      DelayMs(100);//延时消斗
      if(K2 == 0)
      {
        LED1 = ~LED1;
      }
      while(K2 == 0);
    }   
  }
}

实验现象

K1按键控制led0的亮灭,k2按键控制led1的亮灭

3.实验三:外部中断

相关寄存器
P0IEN:各个控制口的中断使能,0 为中断禁止,1 为中断使能。
在这里插入图片描述
P0INP:设置各个I/O 口的输入模式,0 为上拉/下拉,1 为三态模式。
在这里插入图片描述
PICTL:D0~D3 设置各个端口的中断触发方式,0 为上升沿触发,1 为下降沿x发。
在这里插入图片描述
IEN1:中断使能1,0 为中断禁止,1 为中断使能。
在这里插入图片描述
P0IFG:中断状态标志寄存器,当输入端口有中断请求时,相应的标志位将置1。
在这里插入图片描述

代码演示

#include "exit.h"
#include "exit.h"
#define LED0 P1_0
#define LED1 P1_1
#define KEY0 P0_0
#define KEY1 P0_1
void DelayMs(unsigned int msec)//大约1ms延时
{
  for(unsigned int x = msec;x > 0;x --)
  {
    for(unsigned int y = 620;y > 0;y --)
    {
      asm("NOP");
    }    
  }
}
void led_init(void)
{
  P1SEL &= ~0x03 ; //清0第一次 第一为0,代表工作在普通模式
  P1DIR |= 0x03; //第一位为1,输出,否则输入
  P1_0= 0;                //关LED
  P1_1= 0;
}
//外部中断
void exit_init(void)
{
  //按键寄存器的操作,设置为普通模式和输入模式
    P0SEL &= ~0x03;
    P0DIR &= ~0x03;
   //P0IEN:各个控制口的中断使能,0 为中断禁止,1 为中断使能。
    P0IEN |= 0x03;
  //P0INP:设置各个I/O 口的输入模式,0 为上拉/下拉,1 为三态模式
    P0INP &= ~0x03;
  //PICTL:D0~D3 设置各个端口的中断触发方式,0 为上升沿触发,1 为下降沿触发
    PICTL |= 0x01;//下降沿触发
     
  //IEN1:中断使能1,0 为中断禁止,1 为中断使能。
  
  //P0IFG:中断状态标志寄存器,当输入端口有中断请求时,相应的标志位将置1。 
    P0IFG &= ~0x03;        //P0.0中断标志清0    
    P0IE = 1;              //P0中断使能    
    EA = 1;                //总中断使能  
}

#pragma vector = P0INT_VECTOR
__interrupt void P0_ISR(void)
{
  EA=0;
  if((P0IFG & 0x02 ) >0 )         //按键中断 ,p0_1
  {
        P0IFG &= ~0x02;               //P0.1中断标志清0
    LED1 = !LED1;
  }
  P0IF = 0;                       //P0中断标志清0
  EA = 1;                         //开中断
  
  if((P0IFG & 0x01 ) >0 )         //按键中断 ,p0_0
  {
        P0IFG &= ~0x01;               //P0.0中断标志清0
    LED1 = !LED1;
  }
  P0IF = 0;                       //P0中断标志清0
  EA = 1;                         //开中断
  void main(void)
{
  led_init();
  ext_init();
  while(1);//通过while循环等待中断,
}
}

实验现象

主要用到了中断,该中断可以需要配置多个寄存器,假设配置p01,需要开启总中断,然后是设置p0的中断位,后面通过读取P0IFG 这个寄存器的值来判断是否产生了中断

连续按下CC2530主板上K1按键,会发现当按键被按下时,LED的亮灭状态会发生改变。

4.实验四:定时器中断

定时器1 是一个16 位定时器,具有定时器/计数器/脉宽调制功能。它有3 个单独可编程 输入捕获/输出比较 信道,每一个信道都可以用来当做PWM 输出或用来捕获输入信号的边沿时间。
定时器有一个很重要的概念:操作模式。
操作模式包含:自由运行模式(free-running)、 模模式(modulo)和 正计数/倒计数模式(up-down)。本次实验学习到的新寄存器:

T1CTL:定时器1 的控制,D1D0 控制运行模式,D3D2 设置分频划分值。
在这里插入图片描述

T1STAT:定时器1 的状态寄存器,D4~D0 为通道4~通道0 的中断标志,D5 为溢出标志位,当计数到最终技术值是自动置1。在这里插入图片描述

T1CCTL0:D1D0 为捕捉模式选择:00 为不捕捉,01 为上升沿捕获,10 为下降沿捕获,11 为上升或下降沿都捕获。在这里插入图片描述

IRCON:中断标志4,;0 为无中断请求。1 为有中断请求。
在这里插入图片描述

在配置寄存器之前还需要配置时钟频率相关的寄存器

CLKCONCMD:时钟频率控制寄存器。在这里插入图片描述D7 位为32KHZ 时间振荡器选择,0 为32KRC 震荡,1 为32K 晶振。
D6 位为系统时钟选择。0 为32M 晶振,1 为16M RC 震荡。当D7 位为0 时D6 必须为1。
D5~D3 为定时器输出标记。000 为32MHZ,001 为16MHZ,010 为8MHZ,011 为4MHZ,100 为2MHZ,101 为 1MHZ,110 为500KHZ,111 为250KHZ。默认为001。需要注意的是:当D6 为1 时,定时器频率最高可采用频率为16MHZ。
D2~D0:系统主时钟选择:000 为32MHZ,001 为16MHZ,010 为8MHZ,011 为4MHZ,100 为2MHZ,101 为1MHZ,110 为500KHZ,111 为250KHZ。当D6 为1 时,系统主时钟最高可采用频率为16MHZ。

CLKCONSTA:时间频率状态寄存器。
在这里插入图片描述
D7 位为当前32KHZ 时间振荡器频率。0 为32KRC 震荡,1 为32K 晶振。
D6 位为当前系统时钟选择。0 为32M 晶振,1 为16M RC 震荡。
D5~D3 为当前定时器输出标记。000 为32MHZ,001 为16MHZ,010 为8MHZ,011 为4MHZ,100 为2MHZ,101 为 1MHZ,110 为500KHZ,111 为250KHZ。
D2~D0 为当前系统主时钟。000 为32MHZ,001 为16MHZ,010 为8MHZ,011 为4MHZ,100 为2MHZ,101 为1MHZ,110 为500KHZ,111 为250KHZ。

代码演示

#include "time.h"
#include <iocc2530.h>
#define  LED0   P1_0
#define  LED1   P1_1
#define  K1     P0_0

unsigned char counter;
void SysClockInit(void)
{
 unsigned int i;
  SLEEPCMD &= ~0x04;              //都上电
  while(!(CLKCONSTA & 0x40));     //晶体振荡器开启且稳定
  for (i=0; i<504; i++) asm("NOP");//适当延时
  CLKCONCMD &= ~0x47;             //选择32MHz晶体振荡器
  SLEEPCMD |= 0x04; 
}

//IRCON:中断标志4,;0 为无中断请求。1 为有中断请求。

void time1_init(void)
{
  //T1CTL:定时器1 的控制,D1D0 控制运行模式,D3D2 设置分频划分值。
T1CTL = 0x05 ;//自由运行和8分频

//T1STAT:定时器1 的状态寄存器,D4~D0 为通道4~通道0 的中断标志,D5 为溢出标志位,当计数到最终技术值是自动置1。
T1STAT =0x21; //
//T1CCTL0:D1D0 为捕捉模式选择:00 为不捕捉,01 为上升沿捕获,10 为下降沿捕获,11 为上升或下降沿都捕获。
T1CCTL0 |=0x01; //上升沿捕捉

IEN1 |=0X02;
EA = 1;//开启中断
}

#pragma vector = T1_VECTOR      
 __interrupt void T1_ISR(void)
 {
     EA = 0;
   
     if(counter>30)
   {
     counter=0;  
     LED0 = !LED0;
     LED1 = !LED1;
   }
   counter++;
   T1IF = 0;//清除中断位
   EA = 1;//开启中断
 }
void main(void)
{
  SysClockInit();
  led_init();
  time1_init();
  while(1);  
} 

实验现象

在这里插入图片描述
当某个中断发送后会进入这个向量中断表执行相对应的函数

精确控制LED 灯的闪烁间隔为2s,即:亮1s → 暗1s → 亮1s→ 暗1s(即从暗转亮的时刻间隔为1s)。

5.实验五:串口通信

相关寄存器

U0CSR:USART0 控制与状态。在这里插入图片描述
D7 为工作模式选择,0 为SPI 模式,1 为USART 模式。
D6 为UART 接收器使能,0 为禁用接收器,1 为接收器使能。
D5 为SPI 主/从模式选择,0 为SPI 主模式,1 为SPI 从模式。
D4 为帧错误检测状态,0 为无错误,1 为出现出错。
D3 为奇偶错误检测,0 为无错误出现,1 为出现奇偶校验错误。
D2 为字节接收状态,0 为没有收到字节,1 为准备好接收字节。
D1 为字节传送状态,0 为字节没有被传送,1 为写到数据缓冲区的字节已经被发送。
D0 为USART 接收/传送主动状态,0 为USART 空闲,1 为USART 忙碌。

U0GCR:USART0 通用控制寄存器。在这里插入图片描述
D7 为SPI 时钟极性:0 为负时钟极性,1 为正时钟极性;
D6 为SPI 时钟相位:
D5 为传送为顺序:0 为最低有效位先传送,1 为最高有效位先传送。
D4~D0 为波特率设置
在这里插入图片描述

代码演示

对串口进行配置的时候先要配置好系统的时钟,然后设置相应串口的配置,如波特率 校验位等等,最后在开启相关串口的中断,通过U0DBUF这个寄存器来接受和发送数据,当这个串口收到数据时,会产生接收中断,并接收一个字符

#include <iocc2530.h>
#define  LED0   P1_0
#define  LED1   P1_1
unsigned char Flag_RX,temp;
void led_init(void)
{
  P1SEL &= ~0x03;          //P1.0 P1.1为普通 I/O 口
  P1DIR |= 0x03;           //输出 
  LED0 = 0;                  //关LED
  LED1 = 0;
}
void SysClock_Init(void)
{
  SLEEPCMD &= ~0x04;              //都上电
  while(!(CLKCONSTA & 0x40));     //晶体振荡器开启且稳定
  CLKCONCMD &= ~0x47;             //选择32MHz晶体振荡器
  SLEEPCMD |= 0x04;
}
//接着初始化串口,代码为:
void uart0_init(void)
{
  PERCFG = 0x00;        //位置1 P0口 
  P0SEL = 0x3c;        //P0_2,P0_3,P0_4,P0_5用作串口,第二功能 
  P2DIR &= ~0XC0;      //P0 优先作为UART0 ,优先级

  U0CSR |= 0x80;       //UART 方式 
  U0GCR |= 11;         //U0GCR与U0BAUD配合     
  U0BAUD |= 216;       // 波特率设为115200 
  UTX0IF = 0;          //UART0 TX 中断标志初始置位1  (收发时候)
  U0CSR |= 0X40;       //允许接收 
  IEN0 |= 0x84;        // 开总中断,接收中断    

}
//串口发送字节函数
void Uart_Send_char(char ch)
{
  U0DBUF = ch;
  while(UTX0IF == 0);
  UTX0IF = 0;
}
//串口接收一个字符: 一旦有数据从串口传至CC2530, 则进入中断,将接收到的数据赋值给变量temp. 
#pragma vector = URX0_VECTOR 
__interrupt void UART0_ISR(void) 
{ 
  LED0 = 1;
  URX0IF = 0;    // 清中断标志 
  temp = U0DBUF; 
  Flag_RX = 1;
}

void main(void)
{
  SysClock_Init();
  led_init();
  uart0_init();
  while(1)
  {
    LED0 = 0;
    if(Flag_RX)
    {
      LED1 = 1;
      Flag_RX = 0;
      Uart_Send_char(temp);
      LED1 = 0;
    }   
  }
}

实验现象

发送什么数据给单片机单片机将会返回给相应的数据给pc端
在这里插入图片描述

  • 2
    点赞
  • 13
    收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:我行我“速” 设计师:Amelia_0503 返回首页
评论 9

打赏作者

魔动山霸

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值