⭐❤️zigbee无线通信模块的深入浅出❤️⭐
Posted 魔动山霸
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了⭐❤️zigbee无线通信模块的深入浅出❤️⭐相关的知识,希望对你有一定的参考价值。
zigbbe实验
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端
以上是关于⭐❤️zigbee无线通信模块的深入浅出❤️⭐的主要内容,如果未能解决你的问题,请参考以下文章
❤️一个聊天室案例带你了解Node.js+ws模块是如何实现websocket通信的
❤️C语言深入篇❤️(04)- 什么是集成开发环境(IDE)及工程/项目?