前言
搬运个人博客内容,还有几天就到期了,这是年初写的。而且那时候由于一起疫情无法返校,没有实验器材,在学习过程没有实践,所以对于具体使用还十分生疏,也没有做相关项目。对于逐渐忘记的zigbee,我想在这里记录下,以便后续学习的需要。
基本概念
ZigBee,也称紫蜂,是一种低速短距离传输的无线网上协议,底层是采用IEEE 802.15.4标准规范的媒体访问层与物理层。主要特色有低速、低耗电、低成本、支持大量网上节点、支持多种网上拓扑、低复杂度、快速、可靠、安全。
Zigbee模块主要基于TI CC2530芯片实现,其中有5根与下载有关,构成下载电路。工作电压为2~3.6V(最好用3.3V)。关于IO口,一共有21个通用IO口,又分为三组P0(8个引脚)、P1(8)、P2(5)。
关于IO设置
相关寄存器:PxSEL、PxDIR、PxINP。 Px(x分别对应0、1、2,用来控制对应的IO口组)3种寄存器。
PxSEL寄存器
PxSEL寄存器(x=0、1)相应的一个IO口,决定它是普通IO口还是片上外设,0表示普通IO口,1表示片上外设。(普通IO口与片上外设的区别:普通IO口又叫GPIO,可以任意设置这个IO口的高低状态;而片上外设不能被任意控制,必须要通过控制器去控制)
P2SEL寄存器
同样也是0表示普通IO、1表示片上外设 注意:其中P2组只有5个IO口,但是P2_1 P2_2是用于下载程序用的,所以,这两个IO不需要配置,因此P2SEL的低3位分别对应P2_0 P2_3 、P2_4。
PxDIR寄存器
共8位,每一位对应具体的IO组中的相应的一个IO,决定它是输入还是输出,0表示输入,1表示输出。(P2只有五位,低五位照常,高五位不管)(图片参考图2、图3)
PxINP寄存器
在输入的模式时,8位,每一位对应具体的IO组中的相应的一个IO,决定它是上下拉模式还是三态,0表示上下拉模式,1表示三态。(在上下拉模式的时候,需要P2INP后面的3位决定,0表示上拉,1表示下拉)
以下为练习代码
#include<iocc2530.h>
void main()
{
/* P1SEL &=0xFE;// 1111 1110 让P1_0处于普通IO,非偏上外设模式
P1DIR |=0x01;//0000 0001 让P1_0处于输出状态非输入状态
P1_0=1;*/
P0SEL &=0xEF;// 1110 1111
P0DIR |=0x10;//0001 0000
P0SEL &=0xBF;// 1011 1111
P0DIR &=0xBF;
P0INP &=0xBF;//让P0_6处于上下拉模式;
P2INP &=0xDF;//1101 1111 让P0组处于上拉模式
while(1)
{
if(1==P0_6)
{//检测到的是高电平
P0_4=0;
}
else
{//检测到的P0_6外部是低电平
P0_4=1;
}
}
中断
外部中断配置
初始化IO口工作在普通IO上拉输入状态
打开IO口组中断
打开组内对应的具体某IO口中断
上升沿还是下降沿触发
开总中断EA=1
步骤2、3参考下图
步骤4涉及寄存器PICTL,0代表上升沿,1代表下降沿。
中断函数
参考代码如下:
#pragma vector = PxINT_VECTOR //PxIFG 和 PxIF清零
_unterrupt void anyname()
{
PxIFG=0;
PxIF=0;
}
练习代码如下:
#include<iocc2530.h>
#define uchar unsigned char
void delay(uchar u)
{
while(u--);
}
void main()
{
P0SEL &= 0xDF ;//1101 1111 P0_5
P0DIR &= 0xDF ;//1101 1111 P0_5
P0INP &= 0xDF ;//1101 1111 P0_5
P2INP &= 0xDF ;//1101 1111 P0_5
EA = 1;
P0IE = 1;// P1IE如果要设置为1,不能直接用PIE=1,IEN2 |= 0x10 ;// 0001 0000
// IEN |=0x01 ;
P0IEN |= 0x20 ;//0010 0000 设置三个试能标志位,让相应的中断合上
PICTL |= 0x01;//下降沿触发
P1DIR |= 0x01;
while(1);
}
#pragma vector= P0INT_VECTOR
__interrupt void timeduan ()
{
if(P0IFG &= 0x20)//P0组的5发生外部中断
{
delay(1000);
if(0 == P0_5)
{
P1_0 ^=1 ;
}
}
P0IFG = 0;
P0IF = 0;
}
时钟
基本概念:
- CC2530在正常运行的时候需要一个高频时钟信号和一个低频的时钟信号
高频时钟信号,主要供给CPU,保证程序的运行。
低频时钟信号,主要供给看门狗、睡眠定时器等偏上外设。 - 时钟信号的来源;
高频信号有2个,芯片内部的16M RC电路;外接的32M石英晶振
低频信号也有2个来源,芯片内部的32K RC电路,外接的32.768K石英晶振。 - CC2530芯片默认上电的时候,是内部的2个RC电路作为高频和低频的时钟来源。
- 如果我们在用串口,特别是无线通信的时候,必须要用32M的石英晶振作为高频时钟来源。
- 高频时钟源特点:2高频时钟源可以同时起振产生高频时钟信号;而2个低频时钟源,某一时刻只能有1个起振,并且起振的这个时钟源供给CC2530.
系统高频时钟源切换步骤:
让2个高频时钟源起振;//让SLEEPCMD的第2位为0;
等待目标时钟源振荡稳定;// SLEEPSTA寄存器的第6位为1表示32M 时钟源稳定
延时一小段时间63us;// 超过63微秒延时
不分频输出;//把寄存器CLKCONCMD的低3位 设置为000,表示不分频输出
选中目标高频时钟源作为系统主时钟;//把寄存器CLKCONCMD的第6位 清0,设置32M作为系统主时钟
确认一下当前工作的系统时钟是不是所选的高频时钟;//如果读CLKCONSTA这个寄存器的第6位为0,表示32M的时钟源已经作为了当前的系统主时钟,程序可以往下运行了。
练习代码3如下:
#include<iocc2530.h>
#include"74LS164_8LED.h"
void delayus()
{
char k=63;
while(k--);
}
void delay()
{
int i,j;
for(i=0;i<1000;i++)
for(j=0;j<800;j++);
}
void Init32M()
{
SLEEPCMD &=0xFB;//1111 1011 开启2个高频时钟源
while(0==(SLEEPSTA & 0x40));// 0100 0000 等待32M稳定
delayus();
CLKCONCMD &=0xF8;//1111 1000 不分频输出
CLKCONCMD &=0XBF;//1011 1111 设置32M作为系统主时钟
while(CLKCONSTA & 0x40); //0100 0000 等待32M成功成为当前系统主时钟
}
void main()
{
char i;
LS164_Cfg();
Init32M();
while(1)
{
for(i=0;i<10;i++)
{
LS164_BYTE(i);
delay();
}
}
}
串口时钟
具体步骤:
- 指定串口的IO位置
- 相应IO配置成片上外设功能
- 8个数据位、一个停止位、无流控、无校验确立
- 波特率
- 开CPU中断,对应串口接收中断
串口中断函数
样例:
#pragma vector=URX0_VECTOR
__interrupt void anyname(void)
{
URX0IF=0;
ch=U0DBUF;
U0DBUF=ch;
while(UTX0IF==0);
UTX0IF=0;
}
波特率设置函数
//波特率设置参考上表
void Uart0Cfg()
{
PERCFG &=~0x01;
P0SEL |=0x0C;
U0CSR |=0Xc0;
U0GCR =8;
U0BAUD=59;
URX0IE=1;
EA=1;
}
练习代码如下:
#include<ioCC2530.h>
char ch;
void Cfg32M()
{
SLEEPCMD &=0xFB; //fB 0 00 让2个时钟源都起振
while(0==(SLEEPSTA & 0x40)); // 0100 0000 如果32M 晶振供电且稳定了,那么程序往下运行
CLKCONCMD &=0xF8; //1111 1000 不分频输出
CLKCONCMD &=0xBF;//1011 1111 让32M作为系统主时钟供给CPU
while(1==(CLKCONSTA & 0x40));//如果32M确实供给CPU在工作,那么程序往下执行
SLEEPCMD |=0x40;// 0000 0100
}
void UartCfg()
{//串口0的备用位置1配置成波特率9600
PERCFG &=0xFE;//1111 1110 选中串口0的的备用位置1
P0SEL |=0x0C; //0000 1100 P0_2 p0_3为偏上外设功能
U0CSR |=0Xc0;
U0GCR =8;
U0BAUD=59;
EA=1;
URX0IE=1;
}
void main()
{
Cfg32M();
UartCfg();
while(1);
}
#pragma vector=URX0_VECTOR
__interrupt void sdfs(void)
{
URX0IF=0;//串口0来数据的标志位,硬件会置1,我们软件要清0
ch=U0DBUF;//从接受寄存器里取字节存入变量ch
U0DBUF=ch;//把变量ch里的值赋给串口0发送数据寄存器
while(0==UTX0IF);
UTX0IF=0;
}