1. 程式人生 > 其它 >ZigBee學習筆記(基礎篇)

ZigBee學習筆記(基礎篇)

技術標籤:zigbeezigbee

前言

搬運個人部落格內容,還有幾天就到期了,這是年初寫的。而且那時候由於一起疫情無法返校,沒有實驗器材,在學習過程沒有實踐,所以對於具體使用還十分生疏,也沒有做相關專案。對於逐漸忘記的zigbee,我想在這裡記錄下,以便後續學習的需要。


基本概念

ZigBee,也稱紫蜂,是一種低速短距離傳輸的無線網上協議,底層是採用IEEE 802.15.4標準規範的媒體訪問層與物理層。主要特色有低速、低耗電、低成本、支援大量網上節點、支援多種網上拓撲、低複雜度、快速、可靠、安全。

Zigbee模組主要基於TI CC2530晶片實現,其中有5根與下載有關,構成下載電路。工作電壓為2~3.6V(最好用3.3V)。關於IO口,一共有21個通用IO口,又分為三組P0(8個引腳)、P1(8)、P2(5)。

圖1

關於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;
}

時鐘

基本概念:

  1. CC2530在正常執行的時候需要一個高頻時鐘訊號和一個低頻的時鐘訊號
    高頻時鐘訊號,主要供給CPU,保證程式的執行。
    低頻時鐘訊號,主要供給看門狗、睡眠定時器等偏上外設。
  2. 時鐘訊號的來源;
    高頻訊號有2個,晶片內部的16M RC電路;外接的32M石英晶振
    低頻訊號也有2個來源,晶片內部的32K RC電路,外接的32.768K石英晶振。
  3. CC2530晶片預設上電的時候,是內部的2個RC電路作為高頻和低頻的時鐘來源。
  4. 如果我們在用串列埠,特別是無線通訊的時候,必須要用32M的石英晶振作為高頻時鐘來源。
  5. 高頻時鐘源特點: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();
}
}
}

串列埠時鐘

具體步驟:

  1. 指定串列埠的IO位置
  2. 相應IO配置成片上外設功能
  3. 8個數據位、一個停止位、無流控、無校驗確立
  4. 波特率
  5. 開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;
}