本學期學了物聯網技術與應用課程,有接觸到了ZigBee模塊,期末課設就是做一個簡單的ZigBee環境數據採集,通過串口傳輸到STM32,並用esp8266 WIFI模塊上傳至雲端。這裏記錄一下STM32F429與CC2530 ZigBee模塊通信的方法。
目錄
- ZigBee簡介
- 串口通信簡介
- 簡單的數據顯示
ZigBee簡介
ZigBee譯爲"紫蜂",它與藍牙相類似。是一種新興的短距離無線通信技術,用於傳感控制應用(Sensor and Control)。由IEEE 802.15工作組中提出,並由其TG4工作組制定規範。特點如下:
①低功耗。在低耗電待機模式下,2節5號乾電池可支持1個節點工作6~24個月,甚至更長。這是ZigBee的突出優勢。相比較,藍牙能工作數週、WiFi可工作數小時。
TI公司和德國的Micropelt公司共同推出新能源的ZigBee節點。該節點採用Micropelt公司的熱電發電機給TI公司的ZigBee提供電源。
②低成本。通過大幅簡化協議(不到藍牙的1/10),降低了對通信控制器的要求,按預測分析,以8051的8位微控制器測算,全功能的主節點需要32KB代碼,子功能節點少至4KB代碼,而且ZigBee免協議專利費。每塊芯片的價格大約爲2美元。
③低速率。ZigBee工作在20~250kbps的速率,分別提供250 kbps(2.4GHz)40kbps(915 MHz)和20kbps(868 MHz)的原始數據吞吐率,滿足低速率傳輸數據的應用需求。
④近距離。傳輸範圍一般介於10~100m之間,在增加發射功率後,可增加到1-3km。這指的是相鄰節點間的距離。如果通過路由和節點間通信的接力,傳輸距離將可以更遠。
⑤短時延。ZigBee的響應速度較快,一般從睡眠轉入工作狀態只需15ms,節點連接進入網絡只需30ms,進一步節省了電能。相比較,藍牙需要3~10s、WiFi 需要3 s。
⑥高容量。ZigBee可採用星狀、片狀和網狀網絡結構,由一個主節點管理若干子節點,最多一個主節點可管理254個子節點;同時主節點還可由上一層網絡節點管理,最多可組成65000 個節點的大網。
⑦高安全。ZigBee提供了三級安全模式,包括安全設定、使用訪問控制清單(Access Control List, ACL) 防止非法獲取數據以及採用高級加密標準(AES 128)的對稱密碼,以靈活確定其安全屬性。
⑧免執照頻段。使用工業科學醫療(ISM)頻段,915MHz(美國), 868MHz(歐洲), 2. 4GHz(全球) 。
串口通信簡介
串口通信是指外設和計算機間,通過數據信號線 、地線、控制線等,按位進行傳輸數據的一種通訊方式。這種通信方式使用的數據線少,在遠距離通信中可以節約通信成本,但其傳輸速度比並行傳輸低。
串口是計算機上一種非常通用的設備通信協議。大多數計算機(不包括筆記本電腦)包含兩個基於RS-232的串口。串口同時也是儀器儀表設備通用的通信協議;很多GPIB兼容的設備也帶有RS-232口。同時,串口通信協議也可以用於獲取遠程採集設備的數據。
RS-232(ANSI/EIA-232標準)是IBM-PC及其兼容機上的串行連接標準。可用於許多用途,比如連接鼠標、打印機或者Modem,同時也可以接工業儀器儀表。用於驅動和連線的改進,實際應用中RS-232的傳輸長度或者速度常常超過標準的值。RS-232只限於PC串口和設備間點對點的通信。RS-232串口通信最遠距離是50英尺。
簡單的數據顯示
簡單來說,就是把ZigBee的串口和STM32的串口連接起來,這裏STM32的串口選取串口2,波特率都設置爲115200 。
接線如下:
STM32-----ZigBee
VCC -----> VCC
GND -----> GND
TXD -----> RXD
RXD -----> TXD
程序部分,就是通過配置串口2實現數據的採集,這裏給出一個簡單的串口2配置函數,通過該函數的配置可以在串口1輸出在ZigBee傳輸過來的數據:
//初始化IO 串口1
//bound:波特率
void uart_init(u32 bound)
{
//UART 初始化設置
UART1_Handler.Instance=USART1; //USART1
UART1_Handler.Init.BaudRate=bound; //波特率
UART1_Handler.Init.WordLength=UART_WORDLENGTH_8B; //字長爲8位數據格式
UART1_Handler.Init.StopBits=UART_STOPBITS_1; //一個停止位
UART1_Handler.Init.Parity=UART_PARITY_NONE; //無奇偶校驗位
UART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; //無硬件流控
UART1_Handler.Init.Mode=UART_MODE_TX_RX; //收發模式
HAL_UART_Init(&UART1_Handler); //HAL_UART_Init()會使能UART1
//HAL_UART_Receive_IT(&UART1_Handler, (u8 *)aRxBuffer, RXBUFFERSIZE);//該函數會開啓接收中斷:標誌位UART_IT_RXNE,並且設置接收緩衝以及接收緩衝接收最大數據量
}
//串口2初始化
void uart2_init(u32 baund)
{
UART2_Handler.Instance=USART2; //USART2
UART2_Handler.Init.BaudRate=baund; //波特率
UART2_Handler.Init.WordLength=UART_WORDLENGTH_8B; //字長爲8位數據格式
UART2_Handler.Init.StopBits=UART_STOPBITS_1; //一個停止位
UART2_Handler.Init.Parity=UART_PARITY_NONE; //無奇偶校驗位
UART2_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE; //無硬件流控
UART2_Handler.Init.Mode=UART_MODE_TX_RX; //收發模式
HAL_UART_Init(&UART2_Handler);//HAL_UART_Init()會使能UART2
}
//UART底層初始化,時鐘使能,引腳配置,中斷配置
//此函數會被HAL_UART_Init()調用
//huart:串口句柄
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
//GPIO端口設置
GPIO_InitTypeDef GPIO_Initure;
if(huart->Instance==USART1)//如果是串口1,進行串口1 MSP初始化
{
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA時鐘
__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1時鐘
GPIO_Initure.Pin=GPIO_PIN_9; //PA9
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //複用推輓輸出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FAST; //高速
GPIO_Initure.Alternate=GPIO_AF7_USART1; //複用爲USART1
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA9
GPIO_Initure.Pin=GPIO_PIN_10; //PA10
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA10
#if EN_USART1_RX
HAL_NVIC_EnableIRQ(USART1_IRQn); //使能USART1中斷通道
HAL_NVIC_SetPriority(USART1_IRQn,3,3); //搶佔優先級3,子優先級3
#endif
}
if(huart->Instance==USART2)//如果是串口2,進行串口2 MSP初始化
{
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA時鐘
__HAL_RCC_USART2_CLK_ENABLE(); //使能USART3時鐘
GPIO_Initure.Pin=GPIO_PIN_2; //PA2
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //複用推輓輸出
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FAST; //高速
GPIO_Initure.Alternate=GPIO_AF7_USART2; //複用爲USART2
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PB10
GPIO_Initure.Pin=GPIO_PIN_3; //PA3
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化PA3
__HAL_UART_ENABLE_IT(huart,UART_IT_RXNE); //開啓接收中斷
HAL_NVIC_EnableIRQ(USART2_IRQn); //使能USART3中斷
HAL_NVIC_SetPriority(USART2_IRQn,2,3); //搶佔優先級2,子優先級3
}
}
//串口1中斷服務程序
void USART1_IRQHandler(void)
{
u8 Res;
#if SYSTEM_SUPPORT_OS //使用OS
OSIntEnter();
#endif
if((__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_RXNE)!=RESET)) //接收中斷(接收到的數據必須是0x0d 0x0a結尾)
{
HAL_UART_Receive(&UART1_Handler,&Res,1,1000);
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收錯誤,重新開始
else USART_RX_STA|=0x8000; //接收完成了
}
else //還沒收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數據錯誤,重新開始接收
}
}
}
}
HAL_UART_IRQHandler(&UART1_Handler);
#if SYSTEM_SUPPORT_OS //使用OS
OSIntExit();
#endif
}
void USART2_IRQHandler(void)
{
u8 Res;
if((__HAL_UART_GET_FLAG(&UART2_Handler,UART_FLAG_RXNE)!=RESET)) //接收中斷(接收到的數據必須是0x0d 0x0a結尾)
{
HAL_UART_Receive(&UART2_Handler,&Res,1,1000);
if((USART2_RX_STA&0x8000)==0)//接收未完成
{
if(USART2_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART2_RX_STA=0;//接收錯誤,重新開始
else USART2_RX_STA|=0x8000; //接收完成了
}
else //還沒收到0X0D
{
if(Res==0x0d)USART2_RX_STA|=0x4000;
else
{
USART2_RX_BUF[USART2_RX_STA&0X3FFF]=Res ;
USART2_RX_STA++;
if(USART2_RX_STA>(USART2_MAX_RECV_LEN-1))USART2_RX_STA=0;//接收數據錯誤,重新開始接收
}
}
}
}
HAL_UART_IRQHandler(&UART2_Handler);
}
main.c中的輸出如下:
int main(void)
{
u8 reclen=0;
HAL_Init(); //初始化HAL庫
Stm32_Clock_Init(360,25,2,8); //設置時鐘,180Mhz
delay_init(180);
uart_init(115200);
uart2_init(115200);
printf("Welcome to use!\r\n");
while(1)
{
reclen=USART2_RX_STA&0X7FFF; //得到數據長度
USART2_RX_BUF[reclen]=0; //加入結束符
printf("%s\r\n",USART2_RX_BUF);//USART2接ZigBeeTXD和RXD
USART2_RX_STA=0;
delay_ms(1000);
}
}
ZigBee部分的代碼是一個裸機代碼,隨便寫的:
/**************************************/
/* WeBee團隊 */
/* Zigbee學習例程 */
/*例程名稱:溫溼度傳感器DHT11 */
/*建立時間:2012/10/2 */
/*描述:將採集到的環境信息通過串口打印到
串口調試助手。
**************************************/
#include <ioCC2530.h>
#include <string.h>
#include "UART.H"
#include "DHT11.H"
#define AIR P2_0 //定義煙霧接口
#define HUO P1_1 //定義火焰接口
#define uint unsigned int
#define uchar unsigned char
void Yanwu_init();
void huoyan_init();
uchar AirScan();
uchar AirScan2();
void Delayms(uint);
void Delayms(uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=587;j>0;j--);
}
void Yanwu_init()
{
P2SEL &= ~0X01;
P2DIR &= ~0X01;
P2INP &= ~0x01;
}
void huoyan_init()
{
P1SEL &= ~0X01;
P1DIR &= ~0X01;
P1INP &= ~0x01;
}
uchar AirScan(void)
{
if(AIR==0)
{
Delayms(10);
if(AIR==0)
{
return 1;
}
}
return 0;
}
uchar AirScan2(void)
{
if(HUO==0)
{
Delayms(10);
if(HUO==0)
{
return 1; // ?T?ì?í
}
}
return 0; //óD?ì?í
}
/***************************
主函數
***************************/
void main(void)
{
Yanwu_init();
huoyan_init();
Delay_ms(1000);//讓設備穩定
InitUart(); //串口初始化
while(1)
{
DHT11(); //獲取溫溼度
P0DIR |= 0x40; //IO口需要重新配置
/******溫溼度的ASC碼轉換*******/
temp[0]=wendu_shi+0x30;
temp[1]=wendu_ge+0x30;
humidity[0]=shidu_shi+0x30;
humidity[1]=shidu_ge+0x30;
/*******信息通過串口打印********/
Uart_Send_String(biaoshifu,6);
Uart_Send_String(douhao,1);
Uart_Send_String(temp,2);
Uart_Send_String(douhao,1);
Uart_Send_String(temp1,1);
Uart_Send_String(douhao,1);
Uart_Send_String(humidity,2);
Uart_Send_String(douhao,1);
Uart_Send_String(humidity1,1);
Uart_Send_String(douhao,1);
if(AirScan())
{
Uart_Send_String(truenumber,1);
Uart_Send_String(douhao,1);
Uart_Send_String(youyanwu,1);
Uart_Send_String(douhao,1);
}
else
{
Uart_Send_String(falsenumber,1);
Uart_Send_String(douhao,1);
Uart_Send_String(youyanwu,1);
Uart_Send_String(douhao,1);
}
if(AirScan2())
{
Uart_Send_String(truenumber,1);
Uart_Send_String(douhao,1);
Uart_Send_String(youhuoyan,1);
Uart_Send_String(douhao,1);
}
else
{
Uart_Send_String(falsenumber,1);
Uart_Send_String(douhao,1);
Uart_Send_String(youhuoyan,1);
Uart_Send_String(douhao,1);
}
Uart_Send_String("\r\n",2);
Delay_ms(2000);
}
}
Uart_Send_String裏面的數組數據定義如下:
uchar biaoshifu[6]="$ZIGBE";
uchar temp[2]={0,0};
uchar temp1[1]="T";//temp
uchar humidity[2]={0,0};
uchar humidity1[1]="H";//humidity
uchar youyanwu[1]="W";//youyanwu
uchar meiyanwu[1]="U";//meiyanwu
uchar youhuoyan[1]="Y";//youhuoyan
uchar meihuoyan[1]="N";//meihuoyan
uchar douhao[1]=",";//douhao
uchar truenumber[1]="1";
uchar falsenumber[1]="0";
在電腦串口助手可以看到輸出從ZigBee獲取到的數據: