xukai871105 发表于 2013-8-11 17:39:54

CC2530学习笔记——点对点收发程序【附视频】

本帖最后由 xukai871105 于 2013-8-11 18:04 编辑

http://player.youku.com/player.php/sid/XNTk0NTg4MTQ0/v.swf
1.前言
本文将分析一个利用CC2530实现无线串口的程序,文中将会列举部分代码并对CC2530的具体操作进行分析,完整的代码请参考百度网盘的链接地址。本文的具体的内容包括以下几个部分
n CC2530是符合802.15.4标准的无线收发芯片,但是本文并没有遵守802.15.4协议规则,在发送过程中忽略了网络ID、源地址和目标地址等参数,在接收的过程中禁止了帧过滤。通过发送和接收过程的处理使得CC2530无线部分的使用尽可能的简单清晰,通过最少的代码说明问题。n 无线芯片的调试具有一定的难度,一般存在发送设备和接收设备。为了通过最简单的代码说明无线芯片的使用,本文中仅编写一个设备的代码同时实现发送和接收功能。设备代码的功能也相对简单,CC2530从串口接收数据并把数据通过RF部分原分不动地发送出去,于此同时CC2530把从RF部分接收的数据原分不动的通过串口发送出去,通过这样的方式实现无线串口。n 串口数据属于“流”型数据包,RF部分属于“帧”型数据包。在串口数据处理与分析中,一般采用特定的串口头和长度的方式解析数据,但是本文采用通过串口时间间隔的方式解析数据,这种方法等同于modbus-RTU串口数据处理的方法。通过这种检测字节数据时间间隔的方法使得CC2530的串口部分可以接收无特殊格式要求的数据,真正实现无线串口功能。完整代码百度网盘
http://pan.baidu.com/share/link?shareid=2495312973&uk=3707837393
1.1实验准备为了实现无线串口功能,需要准备两套CC2530模块和一个仿真器。如果条件允许可以增加一个仿真器,仿真器可以是CC Debugger也可以是SmartRF04EB,同时也可以准备一套CC2531 USBDongle做为嗅探器,抓取RF发送数据做调试分析。1.2实验结果
本文主要实现了无线串口功能,通过串口调试助手发送字节数据。例如通过串口向设备A发送Hello CC2530,设备B可收到Hello CC2530,并把该字符串通过串口调试助手打印至屏幕。设备B发送Hello RF,设备A同样可以收到数据并打印至屏幕。
                               图1.2.1(a-b) 设备A和设备B串口调试界面      图中中括号包含的数字为RSSI结果,RSSI表示接收信号强度,例如图中的-28。RSSI结果的单位为dBm,dBm为绝对单位且参考的标准为1mW。
2.初始化
RF部分的寄存器较多,需要耐心阅读数据手册和相关工具才可以完成设置。虽然RF部分的寄存器较多,但是还是借助smartRF工具、数据手册和示例代码,依然可以总结出使用CC2530无线部分的一般方法。
初始化部分包括接受数据包帧过滤控制,发射功率控制和信道选择;借助smartRF工具生成若干推荐值;打开接收终端并进入接收状态。
2.1 代码void rf_init(){ FRMFILT0= 0x0C;               // 静止接收过滤,即接收所有数据包    TXPOWER   = 0xD5;               // 发射功率为1dBm FREQCTRL= 0x0B;               // 选择通道11 CCACTRL0= 0xF8;               // 推荐值 smartRF软件生成 FSCAL1 =    0x00;                TXFILTCFG = 0x09; AGCCTRL1 =0x15; AGCCTRL2 =0xFE;       TXFILTCFG = 0x09;                RFIRQM0 |= (1<<6);                // 使能RF数据包接收中断IEN2 |= (1<<0);                   // 使能RF中断 RFST = 0xED;                      // 清除RF接收缓冲区 ISFLUSHRXRFST = 0xE3;                      // RF接收使能 ISRXON }2.2 分析
FRMFILT0的默认值为0x0D,该寄存器的最后一位为FRAME_FLITER_EN,该位的具体含义为使能帧过滤,该位在接收过程中发挥重要的作用。CC2530是符合802.15.4协议的RF芯片,在802.15.4协议中,MAC层有固定的协议格式和不同种类的命令,协议中包括命令类型、源地址和目标地址等重要信息,使能该位CC2530可以自动过滤不需要接收的无线数据帧,例如无线数据帧的目标地址和CC2530寄存器中的自身地址不符合,那么CC2530可以忽视该无线数据帧且不会触发中断。具体的过滤过程可以查看数据手册,在这里不详细解释。为了实现最简单的应用,禁止该位使得CC2530可以接收任意无线数据帧。
关于FRMCTRL0,本程序中保留了默认值所以并没有在代码中体现。从网上查找的代码中,绝大多数代码使能了AUTO_ACK标志位,即使得CC2530芯片可以自动应答无线数据帧。从表面上看,CC2530的应答机制可以保证无线通信的可靠性,但是这种应答机制需要遵循802.15.4标准,若使能自动应答,那么CC2530发送的数据包也必须符合802.15.4标准。为了尽可能的简单,本程序禁止了该位。
关于FRMCTRL0,AUTOCRC默认为使能状态,CC2530会自动进行CRC校验的计算和解析。
smartRF可以帮助用于生成若干比较冷门的寄存器的建议值,这些寄存器关系到CC2530无线调试和解调相关部分,在实际使用的过程中可以采纳建议值不做深究。
在初始化的最后,使能RF接收终端。并通过RFST寄存器写入清空接收缓冲区和进入接收状态命令。
3.发送过程
3.1代码void rf_send( char *pbuf , int len){RFST = 0xE3;                      // RF接收使能 ISRXON // 等待发送状态不活跃 并且 没有接收到SFDwhile( FSMSTAT1 & (( 1<<1 ) | ( 1<<5 ))); RFIRQM0 &= ~(1<<6);            // 禁止接收数据包中断IEN2 &= ~(1<<0);                  // 清除RF全局中断 RFST = 0xEE;                      // 清除发送缓冲区 ISFLUSHTX RFIRQF1 = ~(1<<1);                // 清除发送完成标志 // 填充缓冲区 填充过程需要增加2字节,CRC校验自动填充RFD = len + 2;       for (int i = 0; i < len; i++) {    RFD= *pbuf++;} RFST = 0xE9;                      // 发送数据包 ISTXONwhile (!(RFIRQF1 & (1<<1)));      // 等待发送完成 RFIRQF1 = ~(1<<1);                // 清除发送完成标志位 RFIRQM0 |= (1<<6);                // RX接收中断IEN2 |= (1<<0); }3.2 分析      
发送过程本身不困难,大致可分为侦听SFD清除信道,关闭接收中断,填充缓冲区,启动发送并等待发送完成,最后恢复接收中断。在这几个过程中唯一需要说明的便是填充缓冲区过程,在初始化过程中提到FRMCTRL0寄存器,该寄存器中AUTO_CRC标志位默认为使能状态,阅读数据手册不难发现,CC2530的物理层负载部分第一个字节为长度域,填充实际负载之前需要先填充长度域,而物理层负载在原长度的基础上增加2。长度域数值增加2的原因是由于自动CRC的存在,CRC部分占两个字节CC2530会把这两个字节填充至发送缓冲区。如果能顺利理解这个+2,那么发送部分代码是很好理解的。接下来可以分析接收过程。
4.接收过程   
和发送部分略有不同,接收部分可以分为接收中断部分和接收数据帧处理部分。
4.1 代码#pragma vector=RF_VECTOR__interrupt void rf_isr(void) {EA = 0; // 接收到一个完整的数据包if (RFIRQF0 & ( 1<<6 )) {   rf_receive_isr();                           // 调用接收中断处理函数   S1CON = 0;                                 // 清除RF中断标志   RFIRQF0 &= ~(1<<6);                         // 清除RF接收完成数据包中断}EA = 1;}void rf_receive_isr(){int rf_rx_len = 0;int rssi = 0;char crc_ok = 0; rf_rx_len = RFD - 2;                        // 长度去除两字节附加结果 rf_rx_len &= 0x7F;for (int i = 0; i < rf_rx_len; i++){   rf_rx_buf[i] = RFD;                     // 连续读取接收缓冲区内容}rssi = RFD - 73;                            // 读取RSSI结果 crc_ok = RFD;                               // 读取CRC校验结果 BIT7RFST = 0xED;                              // 清除接收缓冲区 if( crc_ok & 0x80 ){   uart0_sendbuf( rf_rx_buf , rf_rx_len);    // 串口发送   printf("[%d]",rssi);}else{   printf("\r\nCRC Error\r\n");}}4.2 分析      
无线接收部分可以分为两块内容,一块是无线接收中断处理,一块是无线数据帧处理。在前者中仅需查询标志位即可,RFIRQF0的第6位为完整数据包接收中断标志,若CC2530接收到一个完整的无线数据包,该标志位便会置位。由于CC2530存在多种RF中断类型,例如接收到一个完整的帧,帧通过过滤等,那么在进入中断服务函数之后可以通过查询标志位的方法进入相应的处理任务,接收过程中便是采用的这种方式。
      进入数据包处理函数之后,首先读取接收缓冲区的第一个字节,第一个字为数据包长度,在这里需要减去2。长度域减去2的原理和发送过程相似,最后两个字节原位CRC校验,但是在CC2530处理过程中填充了更有用的信息,例如RSSI结果,而CRC校验只返回结果而不返回数值,CRC校验的结果只占用一位。
      如果CRC校验成功,那么就依次读取接收缓冲区字节数据,通过串口发送这些字节数据,并附加一个RSSI结果且RSSI被中括号包围。如果CRC校验失败则通过串口打印CRCError。在程序刚开始调试的过程中,原先认为CRC校验结果是个“花架子”,但是实际中却发现当CC2530处于接收状态时,会不时的收到数据。这些数据杂乱无章,唯一的特征便是CRC校验结果错误。通过CRC校验结果可以有效的剔除数据,保证系统的可靠性。例如本文提供的程序,若CC2530一直处于接收状态,那么每隔半个小时便会出现一次CRC Error。


图4.2.1 CRC Error现象5.串口部分      
串口部分的内容其实和RF部分无关,但是为了方便调试还是列举了该部分的代码。串口部分的代码包括定时器T1和UART两部分,UART中断中往接收缓冲区中填充数据并重新启动定时器,在定时器中断中指示串口数据接收完毕,改变一个软件标志位is_serial_receive。
5.1 代码void uart0_init(){ PERCFG = 0x00;            // UART0 选择位置0 TX@P0.3 RX@P0.2P0SEL|= 0x0C;            // P0.3 P0.2选择外设功能U0CSR|= 0xC0;            // UART模式 接收器使能U0GCR|= 11;                // 查表获得 U0GCR 和 U0BAUD U0BAUD = 216;               // 115200 UTX0IF = 1; URX0IE = 1;                  // 使能接收中断 IEN0@BIT2}void timer1_init(){T1CTL= 0x0C;                // @DIV分频系数 128 @MODE暂停运行 T1CCTL0 = 0x44;             // @IM通道0中断使能 @MODE比较匹配模式 T1STAT = 0x00;               // 清除所有中断标志T1IE = 1;               // IEN1@BIT1 使能定时器1中断 T1CC0L = 250;                // 溢出周期为2ms T1CC0H = 0; } void timer1_disbale(){T1CTL&= ~( 1<< 1);      // 恢复为停止模式} void timer1_enable(){T1CTL|= ( 1 << 1 );       // 改变模式为比较匹配模式 MODE = 0x10; T1STAT = 0x00;               // 清除中断标志位 T1CNTH = 0;               // 重新开始计数 T1CNTL = 0;} #pragma vector=URX0_VECTOR__interrupt void UART0_ISR(void){ URX0IF = 0;                                 // 清除接收中断标志 serial_rxbuf[serial_rxpos] = U0DBUF;    // 填充缓冲区 serial_rxpos++; serial_rxlen++; timer1_enable();                              // 定时器重新开始计数} #pragma vector=T1_VECTOR__interrupt void Timer1_ISR(void){ T1STAT &= ~( 1<< 0);                        // 清除定时器T1通道0中断标志 is_serial_receive = 1;                     // 串口数据到达 timer1_disbale();}6.总结   
大多数RF芯片都可以分为初始化,接收和发送这三个过程。而初始化过程可包括设置信道、功率、帧过滤等参数,由于RF芯片寄存器较多,可以通过官方的软件生成推荐值。发送过程可以采用等待方法,而接收过程往往使用中断方法。

shpan_111 发表于 2013-8-13 23:47:33

请问代码编辑器是用的什么?颜色好像不错

xukai871105 发表于 2013-8-14 09:18:37

shpan_111 发表于 2013-8-13 23:47 static/image/common/back.gif
请问代码编辑器是用的什么?颜色好像不错

notepad++ -> 插件 -> nppexport ->

shpan_111 发表于 2013-8-15 21:53:01

xukai871105 发表于 2013-8-14 09:18 static/image/common/back.gif
notepad++ -> 插件 -> nppexport ->

你好,我也用过notepad,我自己写的函数怎么设置颜色啊。找不到啊。请指教

xukai871105 发表于 2013-8-15 23:01:31

shpan_111 发表于 2013-8-15 21:53 static/image/common/back.gif
你好,我也用过notepad,我自己写的函数怎么设置颜色啊。找不到啊。请指教
...



请参考图片,耐心调整直到您满意为止。

shpan_111 发表于 2013-8-16 22:17:06

本帖最后由 shpan_111 于 2013-8-16 22:19 编辑

xukai871105 发表于 2013-8-15 23:01 static/image/common/back.gif
请参考图片,耐心调整直到您满意为止。

哥哥,你确定你是从这里设置的???我是希望函数名字颜色改变。

1. comment是注释的意思吧?这是不是设置注释的颜色么?
2. 你的这个贴图里颜色设置的是青色,但是实际上你的函数名字不是这个颜色啊?
3. 事实上,我打开设置一看,默认的我得comment颜色跟你的一样,而我得函数颜色是黑色。。。

xukai871105 发表于 2013-8-18 11:21:42

shpan_111 发表于 2013-8-16 22:17 static/image/common/back.gif
哥哥,你确定你是从这里设置的???我是希望函数名字颜色改变。

1. comment是注释的意思吧?这是不是设 ...

好像函数名称该不过来,只能是黑色的。
如果需要的话,只能使用其他工具了

DCJ 发表于 2013-8-18 17:11:26

赞一个,谢谢分享!

Contiki 发表于 2013-9-10 19:21:04

你好,请问你的CC2530用的是什么编译器,怎么才能直接调用printf打印呢

xukai871105 发表于 2013-9-11 08:48:16

Contiki 发表于 2013-9-10 19:21 static/image/common/back.gif
你好,请问你的CC2530用的是什么编译器,怎么才能直接调用printf打印呢

IAR编译 具体版本为8.1

你可以到百度网盘下载代码,至于如何使用printf功能向串口打印内容,其实就是重写或者叫重定义putchar函数

Contiki 发表于 2013-9-22 10:15:07

xukai871105 发表于 2013-9-11 08:48 static/image/common/back.gif
IAR编译 具体版本为8.1

你可以到百度网盘下载代码,至于如何使用printf功能向串口打印内容,其实就是重 ...

谢谢楼主,我使用的是7.51版本,之前printf重定义的是fputc函数没能成功,改成重定义putchar函数成功搞定

sy007 发表于 2013-11-4 12:22:35

感谢分享

ljmdzyx 发表于 2013-11-4 13:08:05

mark         

miaomiao1121 发表于 2013-11-8 20:55:31

楼主怎么收藏这个帖子啊

qdw325 发表于 2013-11-13 21:44:23

mark~!谢谢楼主的分享

xingyuezh 发表于 2013-11-22 20:41:32

不知道楼主的模块用的是什么,RSSI值达到-28,比较感兴趣,望告知,谢谢。

XIUQIN 发表于 2014-2-14 20:11:29

谢谢分享,最近也在弄CC2530

XIUQIN 发表于 2014-2-14 20:16:44

看到你推荐的那本介绍物联网的书我也果断买了一本,一个月看完了感觉是本很好的书,只是吸收很少准备再看一遍,谢谢。

XIUQIN 发表于 2014-4-9 19:00:38

我使用官网的基础BasicRF 点对点收发不知为何运行时间不定就会出现故障,经查是无法进入接收中断。纠结几天了

supermantv 发表于 2014-4-10 11:11:14

mark下正在学

xingyuezh 发表于 2014-4-14 20:32:32

楼主,这个代码为什么rssi读出来是164左右呢,哪有问题呢

xukai871105 发表于 2014-4-15 21:51:22

xingyuezh 发表于 2014-4-14 20:32
楼主,这个代码为什么rssi读出来是164左右呢,哪有问题呢

是不是用我发布的程序???

xingyuezh 发表于 2014-4-15 22:35:02

xukai871105 发表于 2014-4-15 21:51
是不是用我发布的程序???

恩,用你的程序,后来用协议栈中的pkt测了下,好像也差不多,减去255后结果差不多。

184747694 发表于 2014-4-20 16:54:11

你好楼主请教一个问题:
现在准备用2530设计低功耗的节点;准备2个小时发送一次数据包,平时时间处于低功耗模式,外部中断唤醒,计高脉冲数;并且把两个小时内的脉冲数发出去;现在要计算功耗;想请问一下,2530 发送一个10字节的数据包给2530接收器,所需多少时间?不甚感谢

xuanfong1 发表于 2014-4-21 16:05:18

学习了。很不错。good

green-hand 发表于 2014-9-26 14:33:18

大虾,你分享的百度网盘链接失效了。可否更新个?

green-hand 发表于 2014-9-26 19:08:32

DCJ 发表于 2013-8-18 17:11
赞一个,谢谢分享!

能否把代码发我一份!楼主的链接已经失效了!谢谢!470327489@qq.cm

suxiaobo 发表于 2014-9-26 21:16:17

讲得很详细。

xukai871105 发表于 2014-9-28 12:39:27

green-hand 发表于 2014-9-26 19:08
能否把代码发我一份!楼主的链接已经失效了!谢谢!

到我的博客里面找吧,里面有代码仓库。请看我的签名。

green-hand 发表于 2014-9-29 13:28:03

xukai871105 发表于 2014-9-28 12:39
到我的博客里面找吧,里面有代码仓库。请看我的签名。

搞定~谢谢楼主。。

shin555 发表于 2014-9-30 14:27:22

透传,cc2530

wdmg2004 发表于 2014-10-29 09:09:54

谢谢楼主分享,非常详细

xly2014 发表于 2014-11-6 14:56:13

CC2530学习笔记 点对点收发程序

我是前行的狮子 发表于 2015-7-12 16:03:48

谢谢楼主分享,楼主真的是我的偶像,努力膜拜中!
页: [1]
查看完整版本: CC2530学习笔记——点对点收发程序【附视频】