目录
一、ZigBee引入
是一种低速短距离传输的无线局域网协议
他的大小还没一元硬币大,他的速度最大只有250kb/s
二、开发环境搭建
安装IAR写代码,安装协议栈支持使用
工程放到这个协议栈的路径下才能使用
选择协调器
打开这个.s文件
/*******************************************************************************
*
* Workaround for missing ?V1,?V2,... when linking. This is normally caused
* by using an older version of cstartup (pre 8.30) in your project.
*
* Add this file to your project.
*
* Copyright 2013 IAR Systems. All rights reserved.
*
******************************************************************************/;----------------------------------------------------------------;
; Virtual registers ;
; ================= ;
; Below is some segment needed for the IAR ICC C/EC++ compiler ;
; ;
; BREG : A segment for 8 bit registers for use by the compiler. ;
; ?B0 is the first register. ;
; VREG : Segment that holds up to 32 virtual registers for ;
; use by the compiler. ?V0 is the first register. ;
; PSP : Segment containing the PDATA stack pointer (?PSP) ;
; XSP : Segment containing the XDATA stack pointer (?XSP) ;
; ;
;----------------------------------------------------------------;
;----------------------------------------------------------------;PROGRAM VIRTUAL_REGISTERS
PUBLIC ?B0
PUBLIC ?V0
PUBLIC ?V1
PUBLIC ?V2
PUBLIC ?V3
PUBLIC ?V4
PUBLIC ?V5
PUBLIC ?V6
PUBLIC ?V7
PUBLIC ?V8
PUBLIC ?V9
PUBLIC ?V10
PUBLIC ?V11
PUBLIC ?V12
PUBLIC ?V13
PUBLIC ?V14
PUBLIC ?V15
PUBLIC ?V16
PUBLIC ?V17
PUBLIC ?V18
PUBLIC ?V19
PUBLIC ?V20
PUBLIC ?V21
PUBLIC ?V22
PUBLIC ?V23
PUBLIC ?V24
PUBLIC ?V25
PUBLIC ?V26
PUBLIC ?V27
PUBLIC ?V28
PUBLIC ?V29
PUBLIC ?V30
PUBLIC ?V31
PUBLIC ?PSP
PUBLIC ?XSP
RSEG BREG:BIT:NOROOT
?B0:
DS 8RSEG VREG:DATA:NOROOT
?V0:
DS 1
?V1:
DS 1
?V2:
DS 1
?V3:
DS 1
?V4:
DS 1
?V5:
DS 1
?V6:
DS 1
?V7:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V7
?V8:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V8
?V9:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V9
?V10:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V10
?V11:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V11
?V12:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V12
?V13:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V13
?V14:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V14
?V15:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V15
?V16:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V16
?V17:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V17
?V18:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V18
?V19:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V19
?V20:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V20
?V21:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V21
?V22:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V22
?V23:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V23
?V24:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V24
?V25:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V25
?V26:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V26
?V27:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V27
?V28:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V28
?V29:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V29
?V30:
DS 1RSEG VREG:DATA:NOROOT
REQUIRE ?V30
?V31:
DS 1RSEG PSP:DATA:NOROOT
EXTERN ?RESET_PSP
REQUIRE ?RESET_PSP
?PSP:
DS 1RSEG XSP:DATA:NOROOT
EXTERN ?RESET_XSP
REQUIRE ?RESET_XSP
?XSP:
DS 2ENDMOD ; VIRTUAL_REGISTERS
END
添加到文件末尾并删除end
现在就没有错误了
烧入不了
没安驱动
关闭流控,更改波特率
虽然乱码但是通了
三、协议栈系统工作原理
zigbee网络协议结构
zigbee对象:协调器(组网)、路由器(转发消息)、终端(具体干什么)。前面两个也可干终端的活,zigbee只在软件上区分,硬件上这三个都一样。
他们共同开发了SDK
协议栈是协议的具体实现形式,通俗点来理解就是协议栈是协议和用户之间的一个缺口,开发人员通过使用协议栈来使用这个协议的,进而实现无线数据收发。
hal是硬件接口,mac就是mac层,mt是串口、osal是操作系统
SDK中开源的代码都在components里
Documents里面都是文档,有哪些API参数是什么。有什么作用
projects是自己的工程
tools是工具
我们国家是半开源的,做成了一些库给我们使用
安全层内是一些机密算法,调制解调。
OSAL是zigbee的一个操作系统
三、串口实验
复制一份然后改名
打开后弹出界面选是
选择协调器
编译一下有个错误
把这个改成8
我们在他的应用层做开发具体就是这个文件
这些外设也由协议栈为我们写好了
在task_id的处理函数中case的选项都是宏
把这个宏注释掉这样串口就不会打印乱码
void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
uint8 i = 0;
uint8 rx_buf[MT_UART_DEFAULT_MAX_RX_BUFF], rx_len = 0;
(void)event;
while (Hal_UART_RxBufLen(port)){ //循环将 DMA 中接收到的串口数据读出来,并放入缓冲区 rx_buf;
HalUARTRead(port, &rx_buf[rx_len], 1);
rx_len++;
}
if (rx_len != 0) { //确保缓冲区中有数据;
pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof( mtOSALSerialData_t ) + rx_len + 1);//为消息分配内存空间;
pMsg->hdr.event = CMD_SERIAL_MSG; //指定了消息的类型,将串口数据复制到消息的数据区,数据的格式为:数据长度+数据
pMsg->msg = (uint8*)(pMsg + 1);
pMsg->msg[0] = rx_len;
for (i = 0; i < rx_len; i++){
pMsg->msg[i + 1] = rx_buf[i];
}
osal_msg_send( App_TaskID, (byte *)pMsg );//将消息发送给指定 task_id 的任务。
}
}
把这个又长又不好用的回调函数给注释掉
换成这个函数
这样就可以给他发送了
四、GPIO操作
依旧是复制一份这个然后改名叫风扇
选择终端然后operation里改成8
把前面串口的移植过来,不过那些协议栈文件不用改因为他们是共用的
PxSEL //决定IO⼝功能, 1表示⽚上外设,0表示普通IO⼝ PxDIR //决定输⼊还是输出, 1表示输出, 0表示输⼊
PxINP //决定是上下拉模式还是三态
注意:P2INP这个特殊寄存器,它的低四位是控制P2⼝上拉模式还是下拉模式,⽽⾼三位7,6,5是对应控制P2-P0的GPIO端⼝具体是上拉还是下拉
void FanConrtol( uint8 * pkt)
{
P1DIR |= (1<<3);
//消息--->pkt
//解析消息 strncmp 00--->打开风扇 11--->关闭风扇
if(strncmp(pkt,"00",2) == 0)//完全相等返回值为0
{
P1_3 = 0;
HalUARTWrite ( 0 ,"fan open!\n", sizeof("fan open!\n"));
//低电平打开风扇
}else{
P1_3 = 1;
HalUARTWrite ( 0 ,"fan close!\n", sizeof("fan close!\n"));
}
}
写一个风扇控制程序加到任务控制中
五、协议栈之无线数据透传
这次选择协调器
void UartWireless(uint8 * msg)
{
//调用发送APP
AF_DataRequest( &SampleApp_Flash_DstAddr,//填写目的地址+端口号
&SampleApp_epDesc,//源(答复和确认)终端的一个描述
SAMPLEAPP_FLASH_CLUSTERID,//簇ID
strlen(msg), //发送长度
msg, //发送缓冲区的第一个buf
&SampleApp_TransID, //任务ID号
AF_DISCV_ROUTE, //有效位掩码
AF_DEFAULT_RADIUS ); //传输跳转数
}
写完这个再切换成终端完成风扇功能
这些注释掉,我们不需要定时发送
复制一份改成协调器,不使用风扇功能
六、项目整合
因为我们的板子上没有串口助手所以需要自己实现一个,Linux中有一切皆文件的思想,所以我们插入USB串口后会生成一个ttyUSB0的文件直接操作它就行。
#ifndef __LINUX_UART_H_
#define __LINUX_UART_H_
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <termios.h>
#include <string.h>
#include "data_global.h"
extern int set_com_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits);
extern int open_port(char *com_port);
extern void USB_UART_Config(char* path, int baud_rate);
#endif
#include "linuxuart.h"
int set_com_config(int fd, int baud_rate, int data_bits, char parity, int stop_bits)
{
struct termios new_cfg, old_cfg;
int speed;
/*保存原有串口配置*/
if (tcgetattr(fd, &old_cfg) != 0){
perror("tcgetattr");
return -1;
}
new_cfg =old_cfg;
/*配置为原始模式*/
cfmakeraw(&new_cfg);
new_cfg.c_cflag &= ~CSIZE;
/*设置波特率*/
switch (baud_rate)
{
case 2400:{
speed = B2400;
break;
}
case 4800:{
speed = B4800;
break;
}
case 9600:{
speed = B9600;
break;
}
case 19200:{
speed = B19200;
break;
}
case 38400:{
speed = B38400;
break;
}
default:
case 115000:{
speed = B115200;
break;
}
}
cfsetispeed(&new_cfg, speed);
cfsetospeed(&new_cfg, speed);
/*设置数据位*/
switch (data_bits)
{
case 7:{
new_cfg.c_cflag |= CS7;
break;
}
default:
case 8:{
new_cfg.c_cflag |= CS8;
break;
}
}
/*设置奇偶校验位*/
switch (parity)
{
default:
case 'n':
case 'N':{
new_cfg.c_cflag &= ~PARENB;
new_cfg.c_iflag &= ~INPCK;
break;
}
case 'o':
case 'O':{
new_cfg.c_cflag |= (PARODD |PARENB);
new_cfg.c_iflag |= INPCK;
break;
}
case 'e':
case 'E':{
new_cfg.c_cflag |= PARENB;
new_cfg.c_cflag &= ~PARODD;
new_cfg.c_iflag |= INPCK;
break;
}
case 's':
case 'S':{
new_cfg.c_cflag &= ~PARENB;
new_cfg.c_cflag &= ~CSTOPB;
break;
}
}
/*设置停止位*/
switch (stop_bits)
{
default:
case 1:{
new_cfg.c_cflag &= ~CSTOPB;
break;
}
case 2:{
new_cfg.c_cflag |= CSTOPB;
break;
}
}
/*设置等待时间和最小接收字符*/
new_cfg.c_cc[VTIME] = 0;
new_cfg.c_cc[VMIN] = 1;
tcflush(fd, TCIFLUSH);
if ((tcsetattr(fd, TCSANOW, &new_cfg)) != 0)
{
perror("tcsetattr");
return -1;
}
return 0;
}
int open_port(char *com_port)
{
int fd;
/*打开串口*/
fd = open(com_port, O_RDWR|O_NOCTTY|O_NDELAY);
if (fd < 0){
perror("open serial port");
return -1;
}
/*恢复串口阻塞状态*/
if (fcntl(fd, F_SETFL, 0) < 0){
perror("fcntl F_SETFL\n");
}
/*判断是否为终端设备*/
if (isatty(fd) == 0){
perror("This is not a terminal device");
}
return fd;
}
/*--------------------CH340Ƥ׃---------------------------*/
void USB_UART_Config(char* path, int baud_rate)
{
int fd;
fd = open_port(path);
if(fd < 0){
printf("open %s failed\n",path);
return ;
}
if (set_com_config(fd, baud_rate, 8, 'N', 1) < 0)
{
perror("set_com_config");
return ;
}
close(fd);
return ;
}
讲个笑话,我大二做大数据课设的时候,用python写的串口读取显示函数只用一行
加上tcp通信和功能处理都不会超过20行代码,C写项目最明显的特征就是写的多,最终结果的体积却是最小的,因为你写了一堆可能也就几K,但是你用python写一句话可能就得30MB,所以嵌入式还是选C。
这三个是串口常用接口