基于ZigBee的无线温度监测与控制器设计
本文所设计的无线温度监测与控制器主要实现了对环境温度的实时监测和控制。该系统基于Zigbee的无线通信技术,主要分为三部分,分别是网络协调器、终端节点和上位机。终端节点上有温度监测模块和控制模块,用来获取数据和发送数据,协调器通过USB串口与PC连接,用来获取终端数据和上传数据至PC,同时可以下发数据至终端控制模块,上位机主要实现实时温度显示的功能。
通过实际测试,本文设计的无线温度监测与控制器能够实现温度的实时监测功能,同时当温度高于设定值时,能够自动开启风扇,从而达到控制终端节点所在位置的环境温度。
基于IAR的下位机软件设计
(1)网络初始化
在协议栈安装目录 \Projects \z—stack Samples下寻找命名为*.eww的工程文件。协议栈应用工程打开后如图1-1所示。在协议栈目录中分为三部分进行网络初始化,分别是确定网络协调器、进行信道扫描和配置网络参数如图1-2所示。
图1-1 IAR开发环境Z-Stack工程(https://img-blog.csdnimg.cn/20190424172619421.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzQ2MjQ1NQ==,size_16,color_FFFFFF,t_70)
图1-2 网络初始化框图(https://img-blog.csdnimg.cn/20190424172502944.PNG)
(2)节点加入网络
为了建立连接,FFD节点需要向协调器提出请求,协调器接收到节点的连接请求后根据情况决定是否允许其连接,然后对请求连接的节点做出响应,节点与协调器建立连接后,才能实现数据的收发如图1-3所示。
图1-3节点入网框图(https://img-blog.csdnimg.cn/20190424172737394.PNG)
(3)整个系统启动初始化的内容主要有初始化时钟和电压、初始化各硬件模块、初始化 FLASH存储、初始化非易失量(NV)、初始化MAC硬件地址、初始化操作系统、初始化堆栈、初始化各层协议等。
主代码如下
#ifndef NONWK
#include “AF.h”
#endif
#include “hal_adc.h”
#include “hal_flash.h”
#include “hal_lcd.h”
#include “hal_led.h”
#include “hal_drivers.h”
#include “OnBoard.h”
#include “OSAL.h”
#include “OSAL_Nv.h”
#include “ZComDef.h”
#include “ZMAC.h”
/*********************************************************************
- LOCAL FUNCTIONS
*/
static void zmain_ext_addr( void );
#if defined ZCL_KEY_ESTABLISH
static void zmain_cert_init( void );
#endif
static void zmain_dev_info( void );
static void zmain_vdd_check( void );
#ifdef LCD_SUPPORTED
static void zmain_lcd_init( void );
#endif
extern uint8 AppTitle[]; //应用程序名称
/*********************************************************************
- @fn main
- @brief First function called after startup.
- @return don’t care
*/
int main( void )
{
// Turn off interrupts
osal_int_disable( INTS_ALL );
// Initialization for board related stuff such as LEDs
HAL_BOARD_INIT();
// Make sure supply voltage is high enough to run
zmain_vdd_check();
// Initialize board I/O
InitBoard( OB_COLD );
// Initialze HAL drivers
HalDriverInit();
// Initialize NV System
osal_nv_init( NULL );
// Initialize the MAC
ZMacInit();
// Determine the extended address
zmain_ext_addr();
#if defined ZCL_KEY_ESTABLISH
// Initialize the Certicom certificate information.
zmain_cert_init();
#endif
// Initialize basic NV items
zgInit();
#ifndef NONWK
// Since the AF isn’t a task, call it’s initialization routine
afInit();
#endif
// Initialize the operating system
osal_init_system();
// Allow interrupts
osal_int_enable( INTS_ALL );
// Final board initialization
InitBoard( OB_READY );
// Display information about this device
zmain_dev_info();
/* Display the device info on the LCD */
#ifdef LCD_SUPPORTED
zmain_lcd_init();
#endif
#ifdef WDT_IN_PM1
/* If WDT is used, this is a good place to enable it. */
WatchDogEnable( WDTIMX );
#endif
osal_start_system(); // No Return from here
return 0; // Shouldn’t get here.
} // main()
/*********************************************************************
- @fn zmain_vdd_check
- @brief Check if the Vdd is OK to run the processor.
- @return Return if Vdd is ok; otherwise, flash LED, then reset
*********************************************************************/
static void zmain_vdd_check( void )
{
uint8 cnt = 16;
do {
while (!HalAdcCheckVdd(VDD_MIN_RUN));
} while (–cnt);
}
/**************************************************************************************************
- @fn zmain_ext_addr
- @brief Execute a prioritized search for a valid extended address and write the results
-
into the OSAL NV system for use by the system. Temporary address not saved to NV.
- input parameters
- None.
- output parameters
- None.
- @return None.
*/
static void zmain_ext_addr(void)
{
uint8 nullAddr[Z_EXTADDR_LEN] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8 writeNV = TRUE;
// First check whether a non-erased extended address exists in the OSAL NV.
if ((SUCCESS != osal_nv_item_init(ZCD_NV_EXTADDR, Z_EXTADDR_LEN, NULL)) ||
(SUCCESS != osal_nv_read(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, aExtendedAddress)) ||
(osal_memcmp(aExtendedAddress, nullAddr, Z_EXTADDR_LEN)))
{
// Attempt to read the extended address from the location on the lock bits page
// where the programming tools know to reserve it.
HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_IEEE_OSET, aExtendedAddress, Z_EXTADDR_LEN);
if (osal_memcmp(aExtendedAddress, nullAddr, Z_EXTADDR_LEN))
{
// Attempt to read the extended address from the designated location in the Info Page.
if (!osal_memcmp((uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), nullAddr, Z_EXTADDR_LEN))
{
osal_memcpy(aExtendedAddress, (uint8 *)(P_INFOPAGE+HAL_INFOP_IEEE_OSET), Z_EXTADDR_LEN);
}
else // No valid extended address was found.
{
uint8 idx;
#if !defined ( NV_RESTORE )
writeNV = FALSE; // Make this a temporary IEEE address
#endif
/* Attempt to create a sufficiently random extended address for expediency.
* Note: this is only valid/legal in a test environment and
* must never be used for a commercial product.
*/
for (idx = 0; idx < (Z_EXTADDR_LEN - 2);)
{
uint16 randy = osal_rand();
aExtendedAddress[idx++] = LO_UINT16(randy);
aExtendedAddress[idx++] = HI_UINT16(randy);
}
// Next-to-MSB identifies ZigBee devicetype.
#if ZG_BUILD_COORDINATOR_TYPE && !ZG_BUILD_JOINING_TYPE
aExtendedAddress[idx++] = 0x10;
#elif ZG_BUILD_RTRONLY_TYPE
aExtendedAddress[idx++] = 0x20;
#else
aExtendedAddress[idx++] = 0x30;
#endif
// MSB has historical signficance.
aExtendedAddress[idx] = 0xF8;
}
}
if (writeNV)
{
(void)osal_nv_write(ZCD_NV_EXTADDR, 0, Z_EXTADDR_LEN, aExtendedAddress);
}
}
// Set the MAC PIB extended address according to results from above.
(void)ZMacSetReq(MAC_EXTENDED_ADDRESS, aExtendedAddress);
}
#if defined ZCL_KEY_ESTABLISH
/**************************************************************************************************
- @fn zmain_cert_init
- @brief Initialize the Certicom certificate information.
- input parameters
- None.
- output parameters
- None.
- @return None.
*/
static void zmain_cert_init(void)
{
uint8 certData[ZCL_KE_IMPLICIT_CERTIFICATE_LEN];
uint8 nullData[ZCL_KE_IMPLICIT_CERTIFICATE_LEN] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
(void)osal_nv_item_init(ZCD_NV_IMPLICIT_CERTIFICATE, ZCL_KE_IMPLICIT_CERTIFICATE_LEN, NULL);
(void)osal_nv_item_init(ZCD_NV_DEVICE_PRIVATE_KEY, ZCL_KE_DEVICE_PRIVATE_KEY_LEN, NULL);
// First check whether non-null certificate data exists in the OSAL NV. To save on code space,
// just use the ZCD_NV_CA_PUBLIC_KEY as the bellwether for all three.
if ((SUCCESS != osal_nv_item_init(ZCD_NV_CA_PUBLIC_KEY, ZCL_KE_CA_PUBLIC_KEY_LEN, NULL)) ||
(SUCCESS != osal_nv_read(ZCD_NV_CA_PUBLIC_KEY, 0, ZCL_KE_CA_PUBLIC_KEY_LEN, certData)) ||
(osal_memcmp(certData, nullData, ZCL_KE_CA_PUBLIC_KEY_LEN)))
{
// Attempt to read the certificate data from its corresponding location on the lock bits page.
HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_CA_PUBLIC_KEY_OSET, certData,
ZCL_KE_CA_PUBLIC_KEY_LEN);
// If the certificate data is not NULL, use it to update the corresponding NV items.
if (!osal_memcmp(certData, nullData, ZCL_KE_CA_PUBLIC_KEY_LEN))
{
(void)osal_nv_write(ZCD_NV_CA_PUBLIC_KEY, 0, ZCL_KE_CA_PUBLIC_KEY_LEN, certData);
HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_IMPLICIT_CERT_OSET, certData,
ZCL_KE_IMPLICIT_CERTIFICATE_LEN);
(void)osal_nv_write(ZCD_NV_IMPLICIT_CERTIFICATE, 0,
ZCL_KE_IMPLICIT_CERTIFICATE_LEN, certData);
HalFlashRead(HAL_FLASH_IEEE_PAGE, HAL_FLASH_DEV_PRIVATE_KEY_OSET, certData,
ZCL_KE_DEVICE_PRIVATE_KEY_LEN);
(void)osal_nv_write(ZCD_NV_DEVICE_PRIVATE_KEY, 0, ZCL_KE_DEVICE_PRIVATE_KEY_LEN, certData);
}
}
}
#endif
/**************************************************************************************************
- @fn zmain_dev_info
- @brief This displays the IEEE (MSB to LSB) on the LCD.
- input parameters
- None.
- output parameters
- None.
- @return None.
*/
static void zmain_dev_info(void)
{
#ifdef LCD_SUPPORTED
uint8 i;
uint8 xad;
uint8 lcd_buf[Z_EXTADDR_LEN2+1];
// Display the extended address.
xad = aExtendedAddress + Z_EXTADDR_LEN - 1;
for (i = 0; i < Z_EXTADDR_LEN*2; xad–)
{
uint8 ch;
ch = (*xad >> 4) & 0x0F;
lcd_buf[i++] = ch + (( ch < 10 ) ? ‘0’ : ‘7’);
ch = xad & 0x0F;
lcd_buf[i++] = ch + (( ch < 10 ) ? ‘0’ : ‘7’);
}
lcd_buf[Z_EXTADDR_LEN2] = ‘\0’;
//DrawRectFill(0 ,0 ,128,128,GREEN);//背景色
DrawRectFill(3 ,20 ,122,106,WHITE); //显示窗口
Color = BLACK; //前景色
Color_BK = GREEN; //背景色
LCD_write_EN_string(64-7*osal_strlen((char *)AppTitle)/2,3,AppTitle); //显示标题
Color = BLACK; //前景色
Color_BK = WHITE; //背景色
HalLcdWriteString( "IEEE: ", HAL_LCD_LINE_3 );
Color = BLUE;
HalLcdWriteString( (char*)lcd_buf, HAL_LCD_LINE_4 );
Color = RED;
LCD_write_CN_string(9, 95, “西安工程大学”);
Color = BLACK;
LCD_write_CN_string(9, 110, “厚德弘毅”);
Color = MAGENTA;
LCD_write_CN_string(63,110, “博学笃行”);
#endif