基于zigbee变电站入侵监测系统设计
作者:互联网
本系统实现了Zigbee组网监测,应用于变电站使用,多节点监测,上位机软件实时显示状态,同时检测到有人入侵就会报警。上位机将数据实时存到mysql数据库中。便于后续管理查询。Zigbee协调器连接上位机,Zigbee终端连接传感器。主控芯片采用CC2530
上位机采用VS2019进行编程开发,Zigbee代码采用IAR开发,硬件电路图采用AD17设计
实物图如下
展示视频链接:
https://www.bilibili.com/video/BV1wY4y1t7fJ?spm_id_from=333.999.0.0
上位机界面端设计
上位机界面效果截图如下:
硬件电路图如下:
IAR开发界面
上位机源代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using MySql.Data.MySqlClient;//添加对MySql.Data.MySqlClient的引用。
namespace Test
{
public partial class Form1 : Form
{
MySqlConnection conn;//定义数据库连接
MySqlCommand cmd = new MySqlCommand();//定义数据库执行操作类
MySqlDataAdapter adapter;
DateTime dtStart;//用于在批量添加测试时,记录添加数据库记录的开始时间
DateTime dtEnd;//用于在批量添加测试时,记录添加数据库记录的结束时间
private int sum = 0;//用于在批量添加测试时,记录要添加数据库记录的总数
string user_data_tebles_ck =
"cktables";
string user_data_tebles_ck2 =
"cktables2";
string user_data_tebles_log = "log";
string server_ip = "127.0.0.1";
string server_port = "3306";
string mysql_user = "root";
string mysql_pass = "1520747634@qq.com";
string mysql_dataname = "info";
// CREATE Database `spdata` DEFAULT CHARACTER SET utf8;
// CREATE Database `test` DEFAULT CHARACTER SET
utf8;
//CREATE TABLE `user` (
// `id` int (11) NOT NULL AUTO_INCREMENT,
// `序列号` varchar(45) DEFAULT NULL,
// `商品名称` varchar(45)
DEFAULT NULL,
// `商品价格` varchar(45)
DEFAULT NULL,
// PRIMARY KEY(`id`)
//) ENGINE=InnoDB DEFAULT CHARSET=utf8;
//CREATE TABLE `log` (
// `id` int (11) NOT NULL AUTO_INCREMENT,
// `time` varchar(45) DEFAULT NULL,
// `states` varchar(45) DEFAULT NULL,
// PRIMARY KEY(`id`)
//) ENGINE=InnoDB DEFAULT CHARSET=utf8;
public Form1()
{
InitializeComponent();
}
private bool OpenConnection()
{
try
{
String connetStr =
"server='" + server_ip + "';port='" + server_port +
"';user='" + mysql_user + "';password='" + mysql_pass +
"'; database='" + mysql_dataname + "';" +
"charset=utf8"; ;
//
server=127.0.0.1/localhost 代表本机,端口号port默认是3306可以不写
conn = new
MySqlConnection(connetStr);
conn.Open();//打开通道,建立连接,可能出现异常,使用try catch语句
Console.WriteLine("连接正常!");
return true;
}
catch (MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("不能连接服务器!");
break;
case
1045:
MessageBox.Show("账号密码错误!");
break;
case
1046:
MessageBox.Show("数据库未选择");
break;
default:
MessageBox.Show("未知错误!",
ex.Number.ToString() + ex);
break;
}
return false;
}
}
void ShowMsg(string str)
{
Console.Write(str +
"\r\n");
Write_SaveTxtFile(str +
"\r\n");
// txtMsg.Items.Add(str +
"\r\n");
}
public void Write_SaveTxtFile(string txtStr) //保存文本文件 到软件运行目录下
{
string str =
System.Windows.Forms.Application.StartupPath;//获取软件的运行目录
File.AppendAllText(@str +
"\\" + "config.txt", txtStr); //在软件运行目录下保存log信息
}
void create_tables()
{
//CREATE TABLE `log` (
// `id` int (11) NOT NULL
AUTO_INCREMENT,
// `time` varchar(45) DEFAULT
NULL,
// `states` varchar(45) DEFAULT
NULL,
// PRIMARY KEY(`id`)
//int primary key
auto_increment,value 自动递增
string createStatement = "CREATE
TABLE "+ user_data_tebles_ck+ "(id int primary key
auto_increment,value VarChar(50),time VarChar(50) )";
string createStatement2 =
"CREATE TABLE " + user_data_tebles_ck2 + "(id int primary key
auto_increment,value VarChar(50),time VarChar(50) )";
String sqlConn = "server='"
+ server_ip + "';port='" + server_port + "';user='" +
mysql_user +
"';password='" + mysql_pass + "'; database='" +
mysql_dataname + "';" + "Charset=utf8;";
conn = new
MySqlConnection(sqlConn);//
conn.Open();
try
{
// 建表
using (MySqlCommand cmd
= new MySqlCommand(createStatement, conn))
{
cmd.ExecuteNonQuery();
}
using (MySqlCommand cmd
= new MySqlCommand(createStatement2, conn))
{
cmd.ExecuteNonQuery();
}
// 改表或者增加行
//using (MySqlCommand
cmd = new MySqlCommand(alterStatement, conn))
//{
//
cmd.ExecuteNonQuery();
//}
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
Application.Exit();//直接推出
}
}
void init_mysql()
{
//
//mysql_dataname =
"liuhao11";
String sqlConn = "server="+
server_ip+"; port="+ server_port+"; user="+
mysql_user+"; password=" + mysql_pass + ";";
MySqlConnection conn = new
MySqlConnection(sqlConn);//
string sqlDB = "SELECT * FROM information_schema.SCHEMATA
where SCHEMA_NAME='"+ mysql_dataname+"';";
MySqlDataAdapter adp = new
MySqlDataAdapter(sqlDB, conn);
DataSet ds = new DataSet();
adp.Fill(ds);
if (ds.Tables[0].Rows.Count > 0)
{
MessageBox.Show("数据库初始化成功!");
}
else
{
conn.Open();
// MySqlCommand cmd =
new MySqlCommand(string.Format("CREATE DATABASE IF NOT EXISTS '"+
mysql_dataname+"';"));
MySqlCommand cmd = new
MySqlCommand("CREATE DATABASE "+ mysql_dataname+";", conn);
if
(cmd.ExecuteNonQuery() > 0)
{
MessageBox.Show("数据库初始化成功!");
}
else {
MessageBox.Show("数据库初始化失败!");
}
create_tables();
//string
createStatement = "CREATE TABLE "+ user_data_tebles_ck+" (Field1
VarChar(50), Field2 Integer)";
//string alterStatement
= "ALTER TABLE Test1 ADD Field3 Boolean";
//try
//{
// // 建表
// using
(MySqlCommand cmd1 = new MySqlCommand(createStatement, conn))
// {
//
cmd1.ExecuteNonQuery();
// }
// //
改表或者增加行
// //using
(MySqlCommand cmd = new MySqlCommand(alterStatement, conn))
// //{
// //
cmd.ExecuteNonQuery();
// //}
//}
//catch (MySqlException
ex)
//{
//
MessageBox.Show(ex.Message);
//
Application.Exit();//直接推出
//}
}
}
private void Form1_Load(object sender, EventArgs e)
{
string[] ports =
System.IO.Ports.SerialPort.GetPortNames();//获取电脑上可用串口号
comboBox1.Items.AddRange(ports);//给comboBox1添加数据
comboBox1.SelectedIndex =
comboBox1.Items.Count > 0 ? 0 : -1;//如果里面有数据,显示第0个
comboBox2.Text =
"115200";/*默认波特率:115200*/
comboBox3.Text = "1";/*默认停止位:1*/
comboBox4.Text = "8";/*默认数据位:8*/
comboBox5.Text = "无";/*默认奇偶校验位:无*/
init_mysql();//初始化数据库
// radioButton1.ForeColor =
Color.Red;
// radioButton1.Checked = true;
// dataGridView1.RowHeadersVisible =
false; //隐藏首列
//String sqlConn =
"server="+ server_ip +
";port=3306;user=root;password=licoo1128;database=test;Charset=utf8;";//定义连接字符串,Charset=utf8使可以填充中文字符不出现乱码
String sqlConn = "server='"
+ server_ip + "';port='" + server_port + "';user='" +
mysql_user +
"';password='" + mysql_pass + "'; database='" +
mysql_dataname + "';" + "Charset=utf8;";
conn = new
MySqlConnection(sqlConn);//
conn.Open();
try
{
cmd.Connection = conn;
adapter = new
MySqlDataAdapter("select * from " + user_data_tebles_ck, conn);
DataSet ds = new
DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource = ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource = bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource = bindingSource1;//为DataGridView数据控件绑定数据
dataGridView1.Columns[0].ReadOnly = true;//设置第1列,即id列不可编辑
dataGridView1.Columns[0].Width = 40;//设置列宽度
dataGridView1.Columns[1].Width
= 50;//设置列宽度
dataGridView1.Columns[2].Width = 115;//设置列宽度
//dataGridView1.Columns[3].Width = 120;//设置列宽度、
this.dataGridView1.FirstDisplayedScrollingRowIndex = this.dataGridView1.Rows.Count
- 1;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
Application.Exit();//直接推出
}
/*****************非常重要************************/
//serialPort1.DataReceived += new
SerialDataReceivedEventHandler(port_DataReceived);//必须手动添加事件处理程序
}
private void Form1_FormClosed(object sender,
FormClosedEventArgs e)
{
rec_start_falg = false;
try
{//防止意外错误
serialPort1.Close();//关闭串口
}
catch (Exception) { }
timer1.Enabled = false;
conn.Close();
try
{
}
catch (MySqlException ex)
{
Console.WriteLine(ex.Message);
Application.Exit();//直接推出
}
Application.Exit();//直接推出
}
private void btnDelete_Click(object sender,
EventArgs e)
{
foreach (DataGridViewRow dgr in
dataGridView1.SelectedRows)//注意,我们删除的是整行选择的记录,选择某个单元格不算选择
{
cmd.CommandText =
string.Format("DELETE FROM " + user_data_tebles_ck + " WHERE
id='{0}';", dgr.Cells[0].Value.ToString());
if (cmd.ExecuteNonQuery()
> 0)
dataGridView1.Rows.Remove(dgr);//如果成功从数据中删除了记录,则从列表中同步删除。
else
MessageBox.Show(string.Format("从数据库中删除id为{0}的记录失败",
dgr.Cells[0].Value.ToString()));
}
}
private void btnFind_Click(object sender,
EventArgs e)
{
string sql =
string.Format("select * from " + user_data_tebles_ck + " where 序列号 like '%{0}%' or 商品名称 like
'%{0}%' or 商品价格 like '%{0}%';", tbInfo.Text);
adapter = new MySqlDataAdapter(sql,
conn);
DataSet ds = new DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource =
ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource =
bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource =
bindingSource1;//为DataGridView数据控件绑定数据
dataGridView1.Columns[0].ReadOnly =
true;//设置第1列,即id列不可编辑
//
Console.WriteLine(bindingSource1.DataSource.ToString());
//dataGridView1.Columns[0].Width =
80;//设置列宽度
//dataGridView1.Columns[1].Width =
120;//设置列宽度
//dataGridView1.Columns[2].Width =
120;//设置列宽度
//dataGridView1.Columns[3].Width =
120;//设置列宽度
}
private void backgroundWorker1_DoWork(object
sender, DoWorkEventArgs e)
{
dtStart = DateTime.Now;
BackgroundWorker worker = sender as
BackgroundWorker;
for (int i = 0; i < sum; i++)
{
cmd.CommandText =
string.Format("INSERT INTO " + user_data_tebles_ck + " (序列号, 商品名称, 商品价格) VALUES ('南京{0}', '徐{0}', '18012341234');", i);
cmd.ExecuteNonQuery();
worker.ReportProgress(i);
}
}
private void backgroundWorker1_ProgressChanged(object
sender, ProgressChangedEventArgs e)
{
//labelSum.Text =
string.Format("已添加{0}条记录", (e.ProgressPercentage + 1).ToString());
//progressBar1.Value++;
}
private void backgroundWorker1_RunWorkerCompleted(object
sender, RunWorkerCompletedEventArgs e)
{
dtEnd = DateTime.Now;
TimeSpan ts = dtEnd - dtStart;
string sInfo = string.Format("添加完毕!用时:{0}天{1}小时{2}分{3}秒{4}毫秒", ts.Days, ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
MessageBox.Show(sInfo);
cmd.Connection = conn;
MySqlDataAdapter adp = new
MySqlDataAdapter("select * from " + user_data_tebles_ck, conn);
DataSet ds = new DataSet();
adp.Fill(ds);
bindingSource1.DataSource =
ds.Tables[0];
bindingNavigator1.BindingSource =
bindingSource1;
dataGridView1.DataSource =
bindingSource1;
}
private void btnClearAll_Click(object sender,
EventArgs e)
{
cmd.CommandText =
string.Format("delete from " + mysql_dataname + "." +
user_data_tebles_ck);
if (cmd.ExecuteNonQuery() > 0)
MessageBox.Show("清空数据库成功");
else
MessageBox.Show("操作失败");
adapter = new
MySqlDataAdapter("select * from " + user_data_tebles_ck, conn);
DataSet ds = new DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource =
ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource =
bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource =
bindingSource1;//为DataGridView数据控件绑定数据
}
/// 获取当前系统时间的方法
/// 当前时间
static DateTime GetCurrentTime()
{
DateTime currentTime = new
DateTime();
currentTime = DateTime.Now;
return currentTime;
}
private void button2_Click(object sender,
EventArgs e)
{
//string sql = string.Format("select
* from " + user_data_tebles_log + " where 交易时间 like '%{0}%' or 支付金额 like
'%{0}%';", tbInfo.Text);
string sql =
string.Format("select * from " + user_data_tebles_ck);
adapter = new MySqlDataAdapter(sql,
conn);
DataSet ds = new DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource =
ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource =
bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource = bindingSource1;//为DataGridView数据控件绑定数据
dataGridView1.Columns[0].ReadOnly =
true;//设置第1列,即id列不可编辑
// dataGridView1.Columns[0].Width =
60;//设置列宽度
// dataGridView1.Columns[1].Width =
180;//设置列宽度
//// dataGridView1.Columns[3].Width =
80;//设置列宽度
// dataGridView1.Columns[2].Width =
200;//设置列宽度
}
private void button1_Click_1(object sender,
EventArgs e)
{
cmd.CommandText =
string.Format("delete from " + mysql_dataname + "." +
user_data_tebles_log);
if (cmd.ExecuteNonQuery() > 0)
MessageBox.Show("清空数据库成功");
else
MessageBox.Show("操作失败");
adapter = new
MySqlDataAdapter("select * from " + user_data_tebles_log, conn);
DataSet ds = new DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource =
ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource =
bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource = bindingSource1;//为DataGridView数据控件绑定数据
}
String serialPortName;
private void button3_Click(object sender, EventArgs
e)
{
if (button3.Text == "打开串口")
{//如果按钮显示的是打开
try
{
serialPort1.PortName = comboBox1.Text;//获取comboBox1要打开的串口号
serialPortName = comboBox1.Text;
serialPort1.BaudRate = int.Parse(comboBox2.Text);//获取comboBox2选择的波特率
serialPort1.DataBits = int.Parse(comboBox4.Text);//设置数据位
/*设置停止位*/
if
(comboBox3.Text == "1") { serialPort1.StopBits = StopBits.One; }
else if
(comboBox3.Text == "1.5") { serialPort1.StopBits =
StopBits.OnePointFive; }
else if
(comboBox3.Text == "2") { serialPort1.StopBits = StopBits.Two; }
/*设置奇偶校验*/
if
(comboBox5.Text == "无") { serialPort1.Parity
= Parity.None; }
else if
(comboBox5.Text == "奇校验") {
serialPort1.Parity = Parity.Odd; }
else if
(comboBox5.Text == "偶校验") {
serialPort1.Parity = Parity.Even; }
serialPort1.Open();//打开串口
button3.Text = "关闭串口";//按钮显示关闭串口
timer1.Enabled = true;
}
catch (Exception err)
{
MessageBox.Show("打开失败" + err.ToString(),
"提示!");//对话框显示打开失败
}
}
else
{//要关闭串口
try
{//防止意外错误
serialPort1.Close();//关闭串口
}
catch (Exception) { }
button3.Text = "打开串口";//按钮显示打开
rec_start_falg = false;
timer1.Enabled = false;
}
}
void real_time_addmysql(bool sta)
{
if (sta)
{
cmd.CommandText =
string.Format("INSERT INTO " + mysql_dataname + "." +
user_data_tebles_ck2 + "(value,time) values('{0}','{1}');", "有人", GetCurrentTime());
}
else
{
cmd.CommandText =
string.Format("INSERT INTO " + mysql_dataname + "." +
user_data_tebles_ck2 + "(value,time) values('{0}','{1}');", "无人", GetCurrentTime());
}
if (cmd.ExecuteNonQuery() > 0)
Console.WriteLine("添加成功");
else
Console.WriteLine("添加失败");
}
void trigger_addmysql() //有人触发了
{
cmd.CommandText = string.Format("INSERT
INTO " + mysql_dataname + "." + user_data_tebles_ck +
"(value,time) values('{0}','{1}');", "有人",
GetCurrentTime());
if (cmd.ExecuteNonQuery() > 0)
Console.WriteLine("添加成功");
else
Console.WriteLine("添加失败");
adapter = new
MySqlDataAdapter("select * from " + user_data_tebles_ck, conn);
DataSet ds = new DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource =
ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource =
bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource =
bindingSource1;//为DataGridView数据控件绑定数据
}
private void button4_Click_1(object sender,
EventArgs e)
{
cmd.CommandText =
string.Format("INSERT INTO " + mysql_dataname + "." +
user_data_tebles_ck + "(value,time) values('{0}','{1}');", "有人", GetCurrentTime());
if (cmd.ExecuteNonQuery() > 0)
MessageBox.Show("添加成功");
else
MessageBox.Show("添加失败");
adapter = new
MySqlDataAdapter("select * from " + user_data_tebles_ck, conn);
DataSet ds = new DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource = ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource =
bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource =
bindingSource1;//为DataGridView数据控件绑定数据
}
bool rec_start_falg = false;
bool lock_flag = false;
bool rt_glo_status=false;//人体感应全局状态
private void serialPort1_DataReceived(object
sender, SerialDataReceivedEventArgs e)
{
Byte[] InputBuf = new Byte[10];
//开辟接收缓冲区
byte[] ReDatas = new
byte[serialPort1.BytesToRead];
//从串口读取数据
serialPort1.Read(ReDatas, 0,
ReDatas.Length);
if (ReDatas.Length == 3 &&
ReDatas[0] == 0xAA && ReDatas[2] == 0xFA)
{
rec_start_falg = true;
Console.WriteLine("okoko");
rt_glo_status =
ReDatas[1] > 0 ? true : false;
Invoke((new Action(()
=>
{
if
(ReDatas[1] == 1)
{
rt_radio.Checked = true;
if (lock_flag == false)
{
lock_flag = true;//锁定
trigger_addmysql();//添加一条记录
}
}
else
{
rt_radio.Checked = false;
lock_flag = false;//取消锁定
}
})));
}
}
private void timer1_Tick(object sender,
EventArgs e)
{
if (rec_start_falg) //可以开始保存数据了
{
real_time_addmysql(rt_glo_status);
}
}
private void
tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
if (tabControl1.SelectedIndex == 0)//也可以判断tabControl1.SelectedTab.Text的值
{
//执行相应的操作
//
tabPageSubject.Parent = tabControlExtract;//显示
adapter = new
MySqlDataAdapter("select * from " + user_data_tebles_ck, conn);
DataSet ds = new
DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource = ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource = bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource = bindingSource1;//为DataGridView数据控件绑定数据
this.dataGridView1.FirstDisplayedScrollingRowIndex =
this.dataGridView1.Rows.Count - 1;
}
else if (tabControl1.SelectedIndex ==
1)
{
//执行相应的操作
//
tabPageSubject.Parent = null; dataGridView2 查询历史记录
cmd.Connection = conn;
adapter = new
MySqlDataAdapter("select * from " + user_data_tebles_ck2, conn);
DataSet ds = new
DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource = ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource = bindingSource1;//为导航控件绑定数据
dataGridView2.DataSource = bindingSource1;//为DataGridView数据控件绑定数据
dataGridView2.Columns[0].ReadOnly = true;//设置第1列,即id列不可编辑
dataGridView2.Columns[0].Width = 40;//设置列宽度
dataGridView2.Columns[1].Width = 50;//设置列宽度
dataGridView2.Columns[2].Width
= 115;//设置列宽度
this.dataGridView2.FirstDisplayedScrollingRowIndex =
this.dataGridView2.Rows.Count - 1;
}
}
int delcnt = 0;
private void button6_Click(object sender, EventArgs
e)
{
int idex = 0;
if (++delcnt > 3)
{
delcnt = 0;
cmd.CommandText =
string.Format("delete from " + mysql_dataname + "." +
user_data_tebles_ck);
if
(cmd.ExecuteNonQuery() > 0)
idex++;
else
idex = 0;
cmd.CommandText =
string.Format("delete from " + mysql_dataname + "." +
user_data_tebles_ck2);
if
(cmd.ExecuteNonQuery() > 0)
idex++;
else
idex = 0;
if (idex >= 2)
MessageBox.Show("清空数据库成功!");
else
{
MessageBox.Show("清空数据库失败!");
}
adapter = new MySqlDataAdapter("select
* from " + user_data_tebles_ck, conn);
DataSet ds = new
DataSet();
adapter.Fill(ds);//填充数据至ds数据集
bindingSource1.DataSource = ds.Tables[0];//绑定数据
bindingNavigator1.BindingSource = bindingSource1;//为导航控件绑定数据
dataGridView1.DataSource = bindingSource1;//为DataGridView数据控件绑定数据
}
}
}
}
Zigbee终端节点代码
#include "OSAL.h"
#include "ZGlobals.h"
#include "AF.h"
#include "aps_groups.h"
#include "ZDApp.h"
#include "SampleApp.h"
#include "SampleAppHw.h"
#include "OnBoard.h"
#include <math.h>
#include "MT_UART.h"
#include "MT_APP.h"
#include "MT.h"
#include "hal_uart.h"
#include "hal_adc.h"
#include <stdio.h>
#include "string.h"
#include <stdlib.h>
#include "public.h"
#include <stdlib.h>
#include "hal_types.h"
#include "bh1750.h"
#include "dht11.h"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef unsigned int uint16_t;
void user_time_loop_task(void);
void App_GatherTask(void);
// This list should be filled with Application specific Cluster IDs.
const cId_t SD_App_ClusterList[SD_APP_MAX_CLUSTERS] =
{
SD_APP_BROADCAST_CLUSTERID,
SD_APP_POINT_TO_POINT_CLUSTERID
};//这就是每一个端点里面的簇有2个并且簇的ID分别是1,2
const SimpleDescriptionFormat_t SD_App_SimpleDesc =
{
SD_APP_ENDPOINT, //
int Endpoint;
SD_APP_PROFID, //
uint16 AppProfId[2];
SD_APP_DEVICEID, //
uint16 AppDeviceId[2];
SD_APP_DEVICE_VERSION, // int
AppDevVer:4;
SD_APP_FLAGS, //
int AppFlags:4;
SD_APP_MAX_CLUSTERS, // uint8
AppNumInClusters;
(cId_t *)SD_App_ClusterList, // uint8 *pAppInClusterList;
SD_APP_MAX_CLUSTERS, // uint8
AppNumInClusters;
(cId_t *)SD_App_ClusterList // uint8 *pAppInClusterList;
};
// This is the Endpoint/Interface description. It is defined here,
but
// filled-in in SD_App_Init(). Another way to go would be to fill
// in the structure here and make it a "const" (in code space).
The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t SD_App_epDesc;//定义的端点描述符
/*********************************************************************
* LOCAL VARIABLES
*/
uint8 SD_App_TaskID; // Task ID for internal task/event processing
// This variable will be received when
// SD_App_Init() is called.
devStates_t SD_App_NwkState;
uint8 SD_App_TransID; // This is the unique message ID (counter)
afAddrType_t SD_App_Broadcast_DstAddr;
afAddrType_t SD_App_Point_To_Point_DstAddr;
/*********************************************************************
* LOCAL FUNCTIONS
*/
void SD_App_MessageMSGCB( afIncomingMSGPacket_t *pckt );
/* 串口基本定义 */
#define MY_DEFINE_UART_PORT 0 //自定义串口号(0,1);
#define RX_MAX_LENGTH 20 //接收缓冲区最大值: 20个字节;
uint8 RX_BUFFER[RX_MAX_LENGTH]; //接收缓冲区;
void UartCallBackFunction(uint8 port , uint8 event); //回调函数声明,定义在最后面;
#define LED_PIN P1_1 //灯io
/* 配置串口 */
halUARTCfg_t uartConfig; //定义串口配置结构体变量;
void Uart_Config(void); //函数声明;
void Uart_Config(void) //函数定义;
{
uartConfig.configured = TRUE;
//允许配置;
uartConfig.baudRate =
HAL_UART_BR_115200;//波特率;
uartConfig.flowControl = FALSE;
uartConfig.flowControlThreshold = 64; //don't care - see
uart driver.
uartConfig.rx.maxBufSize = 128; //串口接收缓冲区大小
uartConfig.tx.maxBufSize = 128; //串口发送缓冲区大小
uartConfig.idleTimeout = 6;
//don't care - see uart driver.
uartConfig.intEnable = TRUE;
//使能中断
uartConfig.callBackFunc =
UartCallBackFunction; //指定回调函数名;
}
/*********************************************************************
* @fn SD_App_Init
*
* @brief Initialization function for the Generic App Task.
* This is called during initialization
and should contain
* any application specific
initialization (ie. hardware
* initialization/setup, table
initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by OSAL. This ID should
be
*
used to send messages and set timers.
*
* @return none
*/
void SD_App_Init( uint8 task_id )
{
SD_App_TaskID = task_id;
SD_App_NwkState = DEV_INIT;
SD_App_TransID = 0;
#if defined ( BUILD_ALL_DEVICES )
// The "Demo" target is setup to have BUILD_ALL_DEVICES and
HOLD_AUTO_START
// We are looking at a jumper (defined in SD_AppHw.c) to be jumpered
// together - if they are - we will start up a coordinator. Otherwise,
// the device will start as a router.
if ( readCoordinatorJumper() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES
#if defined ( HOLD_AUTO_START )
// HOLD_AUTO_START is a compile option that will surpress ZDApp
// from starting the device and wait for the application to
// start the device.
ZDOInitDevice(0);
#endif
/* 串口操作 */
Uart_Config(); //配置串口
HalUARTOpen(MY_DEFINE_UART_PORT , &uartConfig); //打开串口
HalUARTWrite(MY_DEFINE_UART_PORT ,"HAL_UART_OK\r\n" , 15);
// Setup for the periodic message's destination address
// Broadcast to everyone
SD_App_Broadcast_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//广播模式
SD_App_Broadcast_DstAddr.endPoint = SD_APP_ENDPOINT;
SD_App_Broadcast_DstAddr.addr.shortAddr = 0xFFFF;
SD_App_Point_To_Point_DstAddr.addrMode =
(afAddrMode_t)Addr16Bit;
SD_App_Point_To_Point_DstAddr.endPoint = SD_APP_ENDPOINT;
SD_App_Point_To_Point_DstAddr.addr.shortAddr = 0x0000;
// // Fill out the endpoint description.
SD_App_epDesc.endPoint = SD_APP_ENDPOINT;
SD_App_epDesc.task_id = &SD_App_TaskID;
SD_App_epDesc.simpleDesc
= (SimpleDescriptionFormat_t
*)&SD_App_SimpleDesc;
SD_App_epDesc.latencyReq = noLatencyReqs;
//
// // Register the endpoint description with the AF
afRegister( &SD_App_epDesc );
// Start sending the periodic message in a regular interval.
//这个定时器只是为发送周期信息开启的,设备启动初始化后从这里开始
//触发第一个周期信息的发送,然后周而复始下去
P0DIR&=~0x80;
P1DIR|=0x03;
//SYSTEM_TICK_Init(user_time_loop_task,20);
LED_PIN=0;
system_delay_ms(100);
LED_PIN=1;
osal_start_timerEx(SD_App_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT);
}
char rxbuffer[30]={0};
uint8 SendData[10]={0};//发送数据缓存区
#define RT_Input P0_7
char RT_InFlag=0;//感应标志
uint16 ifg_Rt =0;//计时
char Send_Flag=0;
uint8 delaycnt=0;
void App_GatherTask(void)
{
SendData[0]=0xAA;
SendData[2]=0xFA;//帧尾
if(++delaycnt>50) //上电延时一段时间
{
delaycnt=52;
if(RT_Input==1)
{
LED_PIN=0;//报警
SendData[1]=1; //有人
ifg_Rt=0;
//
HalUARTWrite(MY_DEFINE_UART_PORT ,"On\r\n", 4);
}
else
{
ifg_Rt++;
if(ifg_Rt>15)//计时
{
SendData[1]=0;//没人
ifg_Rt=0;
LED_PIN=1;//不报警
//
HalUARTWrite(MY_DEFINE_UART_PORT ,"Off\r\n", 4);
}
}
}
AF_DataRequest(&SD_App_Broadcast_DstAddr, //发送目的地址+端点地址和传送模式
&SD_App_epDesc,//源(答复或确认)终端的描述(比如操作系统中任务ID等)源EP
SD_APP_BROADCAST_CLUSTERID, //被Profile指定的有效的集群号
3, // 发送数据长度
SendData,// 发送数据缓冲区
&SD_App_TransID, // 任务ID号
AF_DISCV_ROUTE, // 有效位掩码的发送选项
AF_DEFAULT_RADIUS );//传送跳数,通常设置为AF_DEFAULT_RADIUS
}
//用户应用任务的事件处理函数
//task_id 任务id号,events 事件id号
uint16 SD_App_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG )//接收系统消息事件 再进行判断
{
//接收属于本应用任务SampleApp的消息,以SampleApp_TaskID标记
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SD_App_TaskID
);
//根据不同任务id号接收消息
在强制转换
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case CMD_SERIAL_MSG:
break;
// Received when a messages is received (OTA) for
this endpoint
case AF_INCOMING_MSG_CMD: //接收数据事件,调用函数AF_DataRequest()接收数据
//注册完了之后我们就能收到外面从这个端点进来的数据信息了
SD_App_MessageMSGCB( MSGpkt );//调用回调函数对收到的数据进行处理
break;
case ZDO_STATE_CHANGE: //只要网络状态发生改变,就通过ZDO_STATE_CHANGE事件通知所有的任务。
//同时完成对协调器,路由器,终端的设置
SD_App_NwkState =
(devStates_t)(MSGpkt->hdr.status);
if ((SD_App_NwkState == DEV_ZB_COORD)//判断是否为协调器
|| (SD_App_NwkState ==
DEV_ROUTER)
|| (SD_App_NwkState ==
DEV_END_DEVICE))
{
if(SD_App_NwkState == DEV_ZB_COORD)
{
// LS164_BYTE(11);//'C'协调器
HalUARTWrite(MY_DEFINE_UART_PORT
,"Coordinator_OK!!\r\n" , 18);
}
if(SD_App_NwkState == DEV_ROUTER)
{
// LS164_BYTE(12);//‘R’路由器
HalUARTWrite(MY_DEFINE_UART_PORT
,"Router_OK!!\r\n" , 13);
}
if(SD_App_NwkState == DEV_END_DEVICE)
{
// LS164_BYTE(13);//‘E’终端
HalUARTWrite(MY_DEFINE_UART_PORT
,"EndDevice_OK!!\r\n" ,16);
}
}
else
{
// Device is no longer
in the network
}
break;
default:
break;
}
// Release the memory 释放内存
osal_msg_deallocate( (uint8 *)MSGpkt );
// Next - if one is available 指针指向下一个放在缓冲区的待处理的事件,
//返回while ( MSGpkt )判断重新处理事件,直到缓冲区没有等待处理事件为止
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(
SD_App_TaskID );
}
// return unprocessed events返回未处理的事件
return (events ^ SYS_EVENT_MSG);
}
// Send a message out - This event is generated by a timer
// (setup in SampleApp_Init()).
if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )//发送消息-此事件由计时器生成
{
// Send the periodic message 处理周期性事件,
//利用SampleApp_SendPeriodicMessage()处理完当前的周期性事件,然后启动定时器
//开启下一个周期性事情,这样一种循环下去,也即是上面说的周期性事件了,
//可以做为传感器定时采集、上传任务
App_GatherTask();
// Setup to send message again in normal period (+ a little
jitter)
osal_start_timerEx( SD_App_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand()
& 0x00FF)) );//再次启动
// 返回未处理的事件
return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
}
return 0;
}
//接收数据,参数为接收到的数据
void SD_App_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
//收到广播数据
switch ( pkt->clusterId )//判断簇ID
{
case SD_APP_POINT_TO_POINT_CLUSTERID: //簇1
break;
case SD_APP_BROADCAST_CLUSTERID: //簇2
// osal_memset(rxbuffer,0,30);
//
osal_memcpy((uint8*)rxbuffer,&pkt->cmd.Data[0],pkt->cmd.DataLength);
//
break;
}
}
Zigbee协调器应用代码
char showbuff[16]={0};
uint8 sendblueFlag=0;//发送标志位
// This list should be filled with Application specific Cluster IDs.
const cId_t SD_App_ClusterList[SD_APP_MAX_CLUSTERS] =
{
SD_APP_BROADCAST_CLUSTERID,
SD_APP_POINT_TO_POINT_CLUSTERID
};//这就是每一个端点里面的簇有2个并且簇的ID分别是1,2
const SimpleDescriptionFormat_t SD_App_SimpleDesc =
{
SD_APP_ENDPOINT, //
int Endpoint;
SD_APP_PROFID, //
uint16 AppProfId[2];
SD_APP_DEVICEID, //
uint16 AppDeviceId[2];
SD_APP_DEVICE_VERSION, // int
AppDevVer:4;
SD_APP_FLAGS, //
int AppFlags:4;
SD_APP_MAX_CLUSTERS, // uint8
AppNumInClusters;
(cId_t *)SD_App_ClusterList, // uint8 *pAppInClusterList;
SD_APP_MAX_CLUSTERS, // uint8
AppNumInClusters;
(cId_t *)SD_App_ClusterList // uint8 *pAppInClusterList;
};
// This is the Endpoint/Interface description. It is defined here,
but
// filled-in in SD_App_Init(). Another way to go would be to fill
// in the structure here and make it a "const" (in code space).
The
// way it's defined in this sample app it is define in RAM.
endPointDesc_t SD_App_epDesc;//定义的端点描述符
/*********************************************************************
* LOCAL VARIABLES
*/
uint8 SD_App_TaskID; // Task ID for internal task/event processing
// This variable will be received when
// SD_App_Init() is called.
devStates_t SD_App_NwkState;
uint8 SD_App_TransID; // This is the unique message ID (counter)
afAddrType_t SD_App_Broadcast_DstAddr;
afAddrType_t SD_App_Point_To_Point_DstAddr;
/*********************************************************************
* LOCAL FUNCTIONS
*/
void SD_App_MessageMSGCB( afIncomingMSGPacket_t *pckt );
void SD_App_SendBroadcastMessage( void );
void SD_App_SendPointToPointMessage(void);
void App_KeyCheck(void);
/* 串口基本定义 */
#define MY_DEFINE_UART_PORT 0 //自定义串口号(0,1);
#define RX_MAX_LENGTH 30 //接收缓冲区最大值: 20个字节;
uint8 RX_BUFFER[RX_MAX_LENGTH]; //接收缓冲区;
void UartCallBackFunction(uint8 port , uint8 event); //回调函数声明,定义在最后面;
void App_userTask(void);
void sys_delay_us(unsigned int n);
/* 配置串口 */
halUARTCfg_t uartConfig; //定义串口配置结构体变量;
void Uart_Config(void); //函数声明;
void Uart_Config(void) //函数定义;
{
uartConfig.configured = TRUE;
//允许配置;
uartConfig.baudRate =
HAL_UART_BR_115200;//波特率;
uartConfig.flowControl = FALSE;
uartConfig.flowControlThreshold = 64; //don't care - see
uart driver.
uartConfig.rx.maxBufSize = 128; //串口接收缓冲区大小
uartConfig.tx.maxBufSize = 128; //串口发送缓冲区大小
uartConfig.idleTimeout = 6;
//don't care - see uart driver.
uartConfig.intEnable = TRUE;
//使能中断
uartConfig.callBackFunc =
UartCallBackFunction; //指定回调函数名;
}
/*********************************************************************
* @fn SD_App_Init
*
* @brief Initialization function for the Generic App Task.
* This is called during initialization
and should contain
* any application specific
initialization (ie. hardware
* initialization/setup, table
initialization, power up
* notificaiton ... ).
*
* @param task_id - the ID assigned by OSAL. This ID should
be
*
used to send messages and set timers.
*
* @return none
*/
void SD_App_Init( uint8 task_id )
{
SD_App_TaskID = task_id;
SD_App_NwkState = DEV_INIT;
SD_App_TransID = 0;
#if defined ( BUILD_ALL_DEVICES )
// The "Demo" target is setup to have BUILD_ALL_DEVICES and
HOLD_AUTO_START
// We are looking at a jumper (defined in SD_AppHw.c) to be jumpered
// together - if they are - we will start up a coordinator. Otherwise,
// the device will start as a router.
if ( readCoordinatorJumper() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES
#if defined ( HOLD_AUTO_START )
// HOLD_AUTO_START is a compile option that will surpress ZDApp
// from starting the device and wait for the application to
// start the device.
ZDOInitDevice(0);
#endif
/* 串口操作 */
Uart_Config(); //配置串口
HalUARTOpen(MY_DEFINE_UART_PORT , &uartConfig); //打开串口
// HalUARTWrite(MY_DEFINE_UART_PORT ,"HAL_UART_OK\r\n" , 15);
// Setup for the periodic message's destination address
// Broadcast to everyone
SD_App_Broadcast_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//广播模式
SD_App_Broadcast_DstAddr.endPoint = SD_APP_ENDPOINT;
SD_App_Broadcast_DstAddr.addr.shortAddr = 0xFFFF;
SD_App_Point_To_Point_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;//点对点模式
SD_App_Point_To_Point_DstAddr.endPoint = SD_APP_ENDPOINT;
SD_App_Point_To_Point_DstAddr.addr.shortAddr = 0x0000;//发送到目标的地址
// // Fill out the endpoint description.填写端点描述。
SD_App_epDesc.endPoint = SD_APP_ENDPOINT;
SD_App_epDesc.task_id = &SD_App_TaskID;
SD_App_epDesc.simpleDesc
= (SimpleDescriptionFormat_t
*)&SD_App_SimpleDesc;
SD_App_epDesc.latencyReq = noLatencyReqs;
//
// // Register the endpoint description with the AF向af注册端点描述。
afRegister( &SD_App_epDesc );
// Start sending the periodic message in a regular interval.
//这个定时器只是为发送周期信息开启的,设备启动初始化后从这里开始
//触发第一个周期信息的发送,然后周而复始下去
osal_start_timerEx(SD_App_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT);
//SYSTEM_TICK_Init(Key_Scan,20);//设置一个定时器 20ms运行一次
扫描按键
}
//32MHZ us延时函数;
#pragma optimize=none
void sys_delay_us(unsigned int n)
{
n>>=1;
while(n--)
{
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
asm("NOP");
}
}
//用户应用任务的事件处理函数
//task_id 任务id号,events 事件id号
uint16 SD_App_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
(void)task_id; // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG )//接收系统消息事件 再进行判断
{
//接收属于本应用任务SampleApp的消息,以SampleApp_TaskID标记
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SD_App_TaskID
);
//根据不同任务id号接收消息
在强制转换
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
case CMD_SERIAL_MSG:
break;
// Received when a key is pressed
case KEY_CHANGE://按键事件
break;
// Received when a messages is received (OTA) for
this endpoint
case AF_INCOMING_MSG_CMD: //接收数据事件,调用函数AF_DataRequest()接收数据
//注册完了之后我们就能收到外面从这个端点进来的数据信息了
SD_App_MessageMSGCB( MSGpkt );//调用回调函数对收到的数据进行处理
break;
case ZDO_STATE_CHANGE: //只要网络状态发生改变,就通过ZDO_STATE_CHANGE事件通知所有的任务。
//同时完成对协调器,路由器,终端的设置
SD_App_NwkState =
(devStates_t)(MSGpkt->hdr.status);
if ((SD_App_NwkState == DEV_ZB_COORD)//判断是否为协调器
|| (SD_App_NwkState ==
DEV_ROUTER)
|| (SD_App_NwkState ==
DEV_END_DEVICE))
{
if(SD_App_NwkState == DEV_ZB_COORD)
{
// );//'C'协调器
HalUARTWrite(MY_DEFINE_UART_PORT
,"Coordinator_OK!!\r\n" , 18);
}
if(SD_App_NwkState == DEV_ROUTER)
{
// ;//‘R’路由器
HalUARTWrite(MY_DEFINE_UART_PORT
,"Router_OK!!\r\n" , 13);
}
if(SD_App_NwkState == DEV_END_DEVICE)
{
// LS164_BYTE(13);//‘E’终端
HalUARTWrite(MY_DEFINE_UART_PORT
,"EndDevice_OK!!\r\n" ,16);
}
}
else
{
// Device is no longer
in the network
}
break;
default:
break;
}
// Release the memory 释放内存
osal_msg_deallocate( (uint8 *)MSGpkt );
// Next - if one is available 指针指向下一个放在缓冲区的待处理的事件,
//返回while ( MSGpkt )判断重新处理事件,直到缓冲区没有等待处理事件为止
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(
SD_App_TaskID );
}
// return unprocessed events返回未处理的事件
return (events ^ SYS_EVENT_MSG);
}
if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )//发送消息-此事件由计时器生成
{
// Send the periodic message 处理周期性事件,
//利用SampleApp_SendPeriodicMessage()处理完当前的周期性事件,然后启动定时器
//开启下一个周期性事情,这样一种循环下去,也即是上面说的周期性事件了,
//可以做为传感器定时采集、上传任务
App_userTask();
osal_start_timerEx( SD_App_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand()
& 0x00FF)) );//再次启动
// 返回未处理的事件
return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
}
return 0;
}
uint8 tx_flag=0;
uint8 uart_len=0;
uint8 rxbff[5]={0};//接收缓存
uint16 delayCnt=0;
void App_userTask(void) //显示任务
{
}
//接收数据,参数为接收到的数据
void SD_App_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
//收到数据
switch (pkt->clusterId)//判断簇ID
{
case SD_APP_POINT_TO_POINT_CLUSTERID: //簇1
break;
case SD_APP_BROADCAST_CLUSTERID: //簇2
if(pkt->cmd.Data[0]==0xAA&&pkt->cmd.Data[2]==0xFA)
{
osal_memcpy(rxbff,&pkt->cmd.Data[0],3);
HalUARTWrite(MY_DEFINE_UART_PORT , rxbff ,
3);//发送到上位机软件
}
break;
}
}
/*********************************************************************
*
* 函数名: UartCallBackFunction
* 函数功能:串口回调函数,接收到数据时会调用到该函数;
* 传入参数:port:串口号
event:事件
* 返回参数:无
*
*********************************************************************/
static void UartCallBackFunction(uint8 port , uint8 event)
{
uint8 RX_Length = 0; //接收到字符串大小;
RX_Length = Hal_UART_RxBufLen(MY_DEFINE_UART_PORT); //读取接收字符串大小;
if(RX_Length != 0) //有数据存在;
{
//读取串口数据;
HalUARTRead(MY_DEFINE_UART_PORT , RX_BUFFER ,
RX_Length);
uart_len = RX_Length;
// tx_flag=1;
delayCnt=0;
//发送回给电脑,使用 hal_uart.h 的接口函数:
//HalUARTWrite(MY_DEFINE_UART_PORT , RX_BUFFER ,
RX_Length);
}
}
以上为本设计所有应用代码为原创设计,可以用于个人学习使用,禁止用于学术论文使用,违者必究!
标签:zigbee,App,变电站,ds,user,new,监测,void,SD 来源: https://www.cnblogs.com/xhdz-LH/p/16272072.html