目录
基于协议栈的UART实验
前言
协议栈中的TI自带UART的使用实验
UART配置基本步骤
串口初始化
串口发送
串口接收回显
实验效果
拓展
移植我们自己UART串口
移植配置过程
实验效果
基于协议栈的UART实验
前言
与之前的Zigbee裸机实验不同,我们既可以使用CC2530的裸机串口实验的UART作为BSP支持包移植到我们的Zstack协议栈中来使用,也可以使用TI协议栈自带的UART。但这两种方法都需要进行配置。
我今天在做Zigbee单播实验的过程中就想把前面学习的裸机串口直接改改来过来用,结果发现根本用不了,不仅串口收发不了数据,还导致CC2530模块卡死,连协议栈的其它功能也被毁掉了。
后来通过查阅资料和自己一晚上的琢磨,成功实现了协议栈中UART的使用,实现了串口与电脑上位机的收发通信。
接下来进行Zigbee协议栈中的UART的两种使用方法的讲解。
注:本文参考于:
https://www.cnblogs.com/sjsxk/p/5365705.html
ZigBee组网学习笔记(三 )--协议栈串口实验_协议栈 ztool_p1_李国冬的博客-CSDN博客
学习记录 | ZigBee协议栈实践——串口收发数据_keil zigbee_智慧益力多的博客-CSDN博客
协议栈中的TI自带UART的使用实验
UART配置基本步骤
我们裸机使用串口功能的步骤是:
(1) 串口初始化;
(2) 执行任务(发送/接收)。
其实,跟裸机实验里的串口实验一样,本实验也是按照同样的步骤来进行的,第(1)步不变;在第(1)步和第(2)步之间需要多做了一步,就是:给它登记一下;第(2)步照样执行。所以,本实验使用串口的具体步骤是:
(1) 串口初始化;
(2) 登记任务号;
(3) 执行任务。
下面分别介绍各个步骤。
串口初始化
以前,配置串口号、波特率、流控、校验位,配置好寄存器,然后使用。
现在,在workspace下找到HAL\Target\CC2530EB\drivers的hal_uart.c文件,可以看到里面已经包括了串口初始化、发送、接收等函数。
workspace上的MT层,发觉有很多基本函数,前面带MT。包括MT_UART.C,我们打开这个文件。看到MT_UartInit()函数,这里也有一个串口初始化函数,没错Z-stack上有一个MT层,用户可以选用MT层配置和调用其他驱动。进一步简化了操作流程。
跟裸机的实验一样,我们也要配置串口号、波特率、流控,校验位等,以前我们要配置相关的寄存器,现在我们可以直接通过库函数来控制。打开MT_UART.c。然后找到MT_UartInit ()函数。
MT_UartInit ()函数如下面的代码所示
我们可以看出,这跟我们普通的串口配置没有太大区别,都是要配置串口所需要的初始化,在这个实验中,我们要修改的就是波特率和流控制,波特率要修改和配置成115200,和连接串口的上位机保持一致,流控制也要关闭,赋值false,因为我们只需要用到RX、TX 两根线,所以不需要额外的流控制。
通过定位跳转,我们可以发现波特率有以下选择
同样定位发现TRUE是1,FALSE是0,所以放心修改。
注意:
#define MT_UART_DEFAULT_BAUDRATE HAL_UART_BR_38400 默认的波特率是 38400bps,波特率不能设置太低,会导致收发数据出现过高延时。
#define MT_UART_DEFAULT_OVERFLOW TRUE
默认是打开串口流控的,如果你是只连了 TX/RX 2 根线的方式务必关流控,本功能底板只连了 TX/RX 2 根线,要改为FALSE
#define MT_UART_DEFAULT_OVERFLOW FALSE
此外再次强调:2 根线的通讯连接务必关流控,不然是永远收发不了信息的。
修改完之后,我们在SampleApp_Init( uint8 task_id )函数调用配置好的MT_UartInit ()函数;然后,记得在SampleApp.c 文件开头的地方将图所示的头文件include 进去。
(由于我的Zstack被我移植过了,所有的SampleApp都被我修改成了StarryApp)
登记任务号
这也是跟裸机串口发送有所区别的地方,只有登记了任务号,系统才会执行这个函数的功能,相当于去旅店住房要去登记一样,服务员会根据客房情况给你安排房间。登记任务号我们是用MT_UartRegisterTaskID(task_id)函数,来登记串口方面的任务号。
串口发送
使用语句: HalUARTWrite(0,”Hello World\n”,12); //(串口 0,‘字符’,字符个数(不包括'\0')。)
也可以写成 HalUARTWrite(0,”Hello World\n”,sizeof("Hello World\n")-1);
我这里再main函数中调用
该函数在hal_uart.c中被定义
注意:发现烧入程序后,串口打印出来的 Hello World 后面有一小段乱码。这是 Z-stack MT 层定义的串口发送格式,还有液晶提示信息。
我们可以在预编译地方把 MT 和 LCD 相关内容 注释掉(IAR 与 KEIL 中的STM32的预定义宏有些类似)。如下:
ZTOOL_P1
xMT_TASK
xMT_SYS_FUNC
xMT_ZDO_FUNC
xLCD_SUPPORTED=DEBUG
xMT_TASK:表示没有定义 MT_TASK,也就是不定义了。
修改前:
修改后:
用 ZTOOL,串口 0。我们可以在 option——C/C++ 的 CompilerPreprocessor 里 面看到,已经默认添加 ZTOOL_P1 预编译。
(其中ZTOOL_P1 --- 串口0 ZTOOL_P2 --- 串口1 )
改好的重新编译再下载,按复位键,观察串口已经没有乱码了。
串口接收回显
下面我们继续来实现将串口收到的数据发送回给发送方上位机。
首先这里需要自己写一个串口接收回调函数,函数名可以自定义
void My_UART_RxReturn( uint8 port, uint8 event )
{unsigned char buf[30];unsigned char len;len = HalUARTRead(0, buf, 30);//读取串口数据,返回数据长度if(len){HalUARTWrite(0, buf, len);//通过串口原样返回数据 也可以修改数据返回用于区分数据len = 0;}
}
然后将其定义在hal_uart.c中,还要注意要在头文件声明
最后一定要记得把MT_UartInit中的串口回调函数改成自己刚刚定义的串口接收回调函数
实验效果
拓展
我们在协议栈里再做一个测试,在 osal_start_system()函数里 for(;;)里加入:
HalUARTWrite(0,”Hello,World\n”,12);
下载运行后发现串口不停地接收到 Hello,World。
这就证明了前一节的协议栈运行后会在这个函数里不停地循环查询任务、执行任务。
这只是一个演示用的方法,实际应用中你可 千万不能有把串口发送函数弄到这个位置,然后给 PC 发信息。
因为这 破坏了协议栈任务轮询的工作原则,相当于我们普通单片机不停用 Delay 延时函数一样,是极其低效的。
移植我们自己UART串口
移植配置过程
我们将自己的串口BSP文件拷贝并添加到工程中来,以便于与上面的TI串口收发做区分,我们自己的串口初始化使用9600波特率。
starry_uart.h
#ifndef _STARRY_UART_H
#define _STARRY_UART_H
#include <iocc2530.h>void delay_us(void);
void Init32M(void);
void delay_ms(int ms);
void Uart_Config(void);
void String_Print(unsigned char *str);
#endif
starry_uart.c
#include "starry_uart.h"
void delay_us(void)
{char k=63;while(k--);
}
void Init32M(void)
{SLEEPCMD &= ~(0x01<<1); //1111 1110 寮€鍚袱涓珮棰戞椂閽熸簮while(SLEEPSTA & 0x40==0);//0100 0000 绛夊緟32M绋冲畾delay_us();CLKCONCMD &= 0xF8;//浣?浣嶆竻闆?涓嶅垎棰戣緭鍑? CLKCONCMD &= 0xBF; //1011 1111 璁剧疆32M涓虹郴缁熶富鏃堕挓while(CLKCONSTA & 0x40); //0100 0000 绛夊緟32M鎴愬姛閰嶇疆涓哄綋鍓嶇郴缁熶富鏃堕挓
}void delay_ms(int ms)
{int i,j;for(i=ms;i>0;i--)for(j=587;j>0;j--);
}
void Uart_Config()
{//Baud :9600PERCFG &= 0xFE;//1111 1110 P0SEL |= 0x0C; //0000 1100 U0CSR |= 0xC0;U0GCR = 8;U0BAUD = 59; //9600EA=1;URX0IE=1;
}
void String_Print(unsigned char *str)
{for(;*str!='\0';str++){U0DBUF=*str;while(UTX0IF==0);UTX0IF=0;}
}#pragma vector=URX0_VECTOR
__interrupt void UART0_IRQ(void)
{char ch;URX0IF = 0;ch = U0DBUF;U0DBUF = ch;while(UTX0IF == 0);UTX0IF = 0;
}
将串口初始化在main函数末尾调用,并调用我们自己扳机支持包里的串口字符串发送函数
进入main函数中的HalDriverInit驱动初始化函数中
找到TI串口配置的宏定义
将宏定义改为FALSE,从而取消TI默认对串口的配置
最后下载程序即可