切换到宽版
  • 6996阅读
  • 31回复

[STM]STM8学习之——再战2.4G CYRF6936 [复制链接]

上一主题 下一主题
离线zeze10000
 

发帖
2787
M币
8914
专家
33
粉丝
75
— 本帖被 發騷友 设置为精华,作者+3000M币+5专家(2018-09-15) —
最近在调nRF24L01和LT8920,两个都是2.4G无线模块。
群里有人看到我在玩2.4G无线就把几片带2.4G无线模块的玩具遥控主板给了我。
上面的芯片是CYRF6936.
模块还带简易的信号放大,估计传输距离应该不错。
之前有了调试nRF24L01和LT8920的经验,估计这个模块应该不难,应该是轻车熟路了。

但是到手才发现是坑。40页的英文手册,信息满满,看了整整一晚上才有点眉目。
按照自己的理解一点点的配置寄存器,因为网上也很少发现有用的信息。
配置好之后进行通讯,结果一直通讯不成功。
真是令人郁闷。

最开始不知道咋回事,通讯不上,逻辑分析仪挂上,发现SPI有问题,SPI数据还在传输,SS引脚就拉高了。
之前使用的很久的函数了,都没问题,今天居然不行了。
仔细检查发现之前为了连续写入,只判断了buffer是不是空的,空的就直接写入,不等待发送完成。
今天不行了,今天把SPI时钟降低了些,结果导致数据没传完,SS被拉高了。
后面每个字节都等待传输完成后才进行下一字节的写入,终于是成功了。
先写个通道,在读出来。发现信息一致,通信成功!

接着是收发函数,这个芯片比较坑的地方就是收发的buffer只有16字节。
16个字节以内的操作简单。发送就是写完再启动发送。
接收就是接收完毕再读出。
但是超过16个字节就好玩了。
需要边发送边写入,接收是要边接收,边读出。
当buffer满了,还继续写入或者接收数据就会产生buffer错误。
当还在发送,发送字节数没到设定的字节数时,buffer空了,也会出现buffer错误。

好玩的就是这个地方。调了三天,一天半多的时间在处理这个。
发送还算简单,只要buffer不满就写入。开始是读状态寄存器,但是这样太慢了。直接用模块的中断引脚。
因为模块有16个字节buffer,前16个直接写满,后面的等buffer不满时让模块引脚输出一个中断信号,继续写入,直到写完。
发送还算顺利,没多大问题。
接收就好玩了,首先单片机对接收的响应要非常及时,还不能被打断。
这个可以用中断做,但是为了实验简单,我就一直查询。
一开始我以为应该很简单,当buffer不为空就读呗,让模块产生中断信号,单片机读。
但是这里是个坑,调了很久,废了九牛二虎之力才算是基本解决问题。
使用buffer非空这个中断最坑的就是在读取过程中中断引脚信号没了。。。
就这么没了。。。

一开始不管怎么读都只读出16个字节,其它全是错的。
后面进入接收后不管这个引脚状态连续读,也不行,读到的都是同一个字节。。。
弄了好久,又是改初始化参数,又是逻辑分析仪抓手柄的原机信号,改来改去都没用。
没办法,后面使用一个buffer半满中断进行检测。这个也是奇葩。半满,就是buffer里是字节数超过或者等于8.
中断触发后,开始读buffer,读第一个字节,中断引脚电平变高,等一下,电平变低,载读,这次读出8个字节,引脚变高,
再变低,又能读出8个字节。奇葩的是,最后的,buffer里还剩十几个没读时,引脚也变高了,说好的半满呢?
咋办呢?后面想到,既然后面的不足16个字节,等着接收完成再读不就好了。
直接把半满和接收完成中断都打开,总算是顺利接收到所有字节。

好了,3天,总算是搞定了。中间几次想放弃超过16个字节的发送接收。

实验思路很简单,主机发送一串字符,从机接收后将字符返回给主机。
这样主机和从机都有发送接收的机会,也可以测试发送和接收的转换操作。
数据最终回到主机,可以检测信息传递的完整性。
看寄存器的时候发现个有趣的地方RSSI,接收信号指示寄存器。
会记录上次接收时的信号强度。这个不错,顺便把这个信号也返回。


结构框图


这芯片支持4种信号的调制方式
这里用的GFSK,和24L01一样的调制方式

读写时序,用来配置SPI时序




数据包结构



引导码加上两个开始码,加上数据长度,加上数据,再加上CRC数据。
下面是应答数据包。

两个模块要通讯,首先是频段一致,然后是两个开始码要相同,相当于地址。
然后CRC计算的初始值要相同,不然会报CRC错误。

寄存器总览


寄存器讲解还算挺详细的
有趣的是这个模块的电源管理能给其它外设供电。
还有几个引脚能当GPIO使用。

比较不好的地方就是没有一个流程图,怎样收发,状态转换什么的。
有个参考的配置流程就更好了。

调试时抓的波形


数据发送时
IRQ为低就表示buffer没满,这里是能连续写入


接收数据


这里看到IRQ时高时低,低时表示buff半满,进行连续读取。
这里可以看到,读了8个字节后IRQ变高,等一段时间,又能读8个字节。
最后的十几个字节其实是接收完成信号拉低的IRQ。
同样能顺利读完。
使用buffer不空则不行。

看看效果

正常接收


接收乱码

自动复位模块,重新接收正常。


从机断开

接收超时


自动运行

从错误中恢复


附上C文件
  1. #include<cyrf6936.h>
  2. #include<iostm8s105k4.h>
  3. #include<spi.h>
  4. #include<delay.h>
  5. #include<string.h>
  6. int sta_s,sta_r;
  7. unsigned char SOP_CODE[8]={0x44,0xF6,0x16,0xAD,0x44,0xF6,0xE1,0x5C};    //开始码,身份识别
  8. /*
  9. **读寄存器
  10. **addr:寄存器地址
  11. */
  12. unsigned char R_REG(unsigned char addr)
  13. {
  14.   unsigned char dat;
  15.   SS=0;
  16.   SPI_RW(addr);
  17.   dat=SPI_RW(0x00);
  18.   SS=1;
  19.   return dat;
  20. }
  21. /*
  22. **写寄存器
  23. **addr:寄存器地址,dat:写入值
  24. */
  25. void W_REG(unsigned char addr,unsigned char dat)
  26. {
  27.   SS=0;
  28.   SPI_RW(0x80|addr);
  29.   SPI_RW(dat);
  30.   
  31.   SS=1;
  32. }
  33. /*
  34. **读buffer
  35. **addr:buffer入口,*pBuf:接收数组,len:长度
  36. */
  37. void R_BUF(unsigned char addr,unsigned char* pBuf,unsigned char len )
  38. {
  39.   SS=0;
  40.   SPI_RW(addr);
  41.   while(len--)
  42.     *pBuf++=SPI_RW(0x00);  
  43.   
  44.   SS=1;
  45. }
  46. /*
  47. **写buffer
  48. **addr:buffer入口,*pBuf:写入数组,len:长度
  49. */
  50. void W_BUF(unsigned char addr,unsigned char* pBuf,unsigned char len)
  51. {
  52.   SS=0;
  53.   SPI_RW(0x80|addr);
  54.   while(len--)
  55.     SPI_RW(*pBuf++);
  56.   
  57.   SS=1;
  58. }
  59. /*
  60. **发送数据
  61. ***pBuf:发送数组
  62. */
  63. void cyrf6936_send(unsigned char *pBuf)
  64. {
  65.   unsigned int count;
  66.   unsigned char len;
  67.   
  68.   len=strlen((char const*)pBuf);        //发送长度
  69.   if(len>40) len=40;                     //限定长度
  70.   W_REG(TX_LENGTH_ADR,len);              //写入长度
  71.   
  72.   W_REG(TX_CTRL_ADR,0x40);               //清写入buffer
  73.   
  74.   if(len>16)                             //长数据处理
  75.   {
  76.     W_BUF(TX_BUFFER_ADR,pBuf,16);        //buffer长度为16字节,一次写入
  77.     len-=16;
  78.     pBuf+=16;
  79.   }else                                 //短数据处理
  80.   {
  81.     W_BUF(TX_BUFFER_ADR,pBuf,len);      //一次写入完成
  82.     len=0;
  83.   }
  84.   
  85.   W_REG(TX_CTRL_ADR,0xa0);              //启动发送
  86.   
  87.   SS=0;
  88.   SPI_RW(0x80|TX_BUFFER_ADR);           //写buffer地址
  89.   while(len--)                            //剩余数据写入
  90.   {
  91.     count=0;
  92.     while(IRQ)                          //等待buffer有空闲
  93.     {
  94.       if(count++>10000) break;          //超时处理
  95.     }
  96.       
  97.     SPI_RW(*pBuf++);                     //写入数据
  98.     
  99.   }
  100.   SS=1;
  101.   count=0;
  102.   while(!(sta_s=R_REG(TX_IRQ_STATUS_ADR)&0x03))      //等待发送完成,错误时退出
  103.   {
  104.     if(count++>2000) break;              //超时处理
  105.   }
  106.   W_REG(TX_CTRL_ADR,0x40);                //清buffer
  107. }
  108. /*
  109. **接收数据
  110. ***pBuf:接收数组
  111. */
  112. void cyrf6936_recive(unsigned char* pBuf)
  113. {
  114.   unsigned int count;
  115.   unsigned char len;
  116.   len=R_REG(RX_LENGTH_ADR);             //读数据长度
  117.   if(len>40) len=40;
  118.   
  119.   SS=0;
  120.   SPI_RW(RX_BUFFER_ADR);              //读取入口
  121.   while(len--)                         //循环接收
  122.   {
  123.     count=0;
  124.     
  125.     while(IRQ)                          //buffer为空时等待
  126.     {
  127.       if(count++>2000) break;          //超时退出
  128.     }
  129.     
  130.     *pBuf++=SPI_RW(0x00);               //读取数据
  131.   }
  132.   SS=1;
  133.   sta_r=R_REG(RX_IRQ_STATUS_ADR);
  134. }
  135. /*
  136. **器件初始化
  137. */
  138. void cyrf6936_init()
  139. {
  140.   RST=0;
  141.   SS=1;
  142.   PC_DDR_DDR4=1;        //SS
  143.   PC_CR1_C14=1;
  144.   PC_CR2_C24=0;
  145.   
  146.   PC_DDR_DDR3=0;        //IRQ
  147.   PC_CR1_C13=1;
  148.   PC_CR2_C23=0;
  149.   
  150.   PD_DDR_DDR2=1;        //RST
  151.   PD_CR1_C12=1;
  152.   PD_CR2_C22=0;
  153.   
  154.   RST=1;
  155.   delayms(5);
  156.   RST=0;
  157.   delayms(5);
  158.   
  159.   W_REG(MODE_OVERRIDE_ADR,0x01);        //reset
  160.   delayms(3);
  161.   W_REG(CHANNEL_ADR,0x30);              //chanel 48
  162.   W_REG(TX_CFG_ADR,0x06);               //GFSK,0DB
  163.   W_REG(RX_CFG_ADR,0x8a);               //AGC_EN,FAST TURN MODE EN,RXOW_EN
  164.   W_REG(XACT_CFG_ADR,0x05);             //END STATE IDLE,ACK TIME OUT X8
  165.   W_REG(FRAMING_CFG_ADR,0xa4);          //SOP_EN,SOP LEN:32,LEN_EN,SOP_THRESHOLD:04
  166.   W_REG(CRC_SEED_LSB_ADR,0x5a);         //CRC_SEED_LSB
  167.   W_REG(CRC_SEED_MSB_ADR,0xa5);         //CRC_SEED_MSB
  168.   W_REG(TX_OFFSET_LSB_ADR,0x55);        //TX_OFFSET_LSB
  169.   W_REG(TX_OFFSET_MSB_ADR,0x05);        //TX_OFFSET_MSB
  170.   W_REG(XTAL_CFG_ADR,0x08);             //Crystal Startup Delay
  171.   W_REG(AUTO_CAL_TIME_ADR,0x3c);        //AUTO_CAL_TIME
  172.   W_REG(AUTO_CAL_OFFSET_ADR,0x14);      //AUTO_CAL_OFFSET
  173.   W_REG(ANALOG_CTRL_ADR,0x01);          //ALL SLOW
  174.   W_BUF(SOP_CODE_ADR,SOP_CODE,8);       //SOP_CODE
  175.   delayms(10);
  176.   
  177. }



最后提供源码,供参考



THE END!





STM8学习之——DHT11
http://bbs.mydigit.cn/read.php?tid=2506640

STM8学习之——nRF24L01
http://bbs.mydigit.cn/read.php?tid=2526017

STM8学习之 WS2812 TCS2300
http://bbs.mydigit.cn/read.php?tid=2518843

STM8学习之——LT8920
http://bbs.mydigit.cn/read.php?tid=2527719

STM8学习之——再战2.4G CYRF6936
http://bbs.mydigit.cn/read.php?tid=2531787
本文内容包含图片或附件,获取更多资讯,请 登录 后查看;或者 注册 成为会员获得更多权限
本帖最近打赏记录:共21条打赏M币+273专家+2
ch104517745 专家 +1 歡迎探討 09-22
ch104517745 M币 +20 歡迎探討 09-22
snowrose2000 M币 +13 謝謝分享,高手! 09-18
q版虎斑猫 M币 +13 - 09-18
rallyezhang 专家 +1 原創內容 09-18
rallyezhang M币 +20 原創內容 09-18
xiaoxuanfeng M币 +13 原創內容 09-18
weizaisifang M币 +13 謝謝分享 09-17
udcs M币 +15 謝謝分享 09-17
eros8269 M币 +13 謝謝分享 09-16
离线keye

发帖
1671
M币
5431
专家
3
粉丝
47
只看该作者 1楼 发表于: 09-15
謝謝分享,谢谢分享
离线2545889167

发帖
12572
M币
15036
专家
287
粉丝
4668
只看该作者 2楼 发表于: 09-15
厉害大佬,感谢分享
离线0720

发帖
4590
M币
4082
专家
81
粉丝
206
只看该作者 3楼 发表于: 09-15
你是夜猫吗?单片机的不会
离线mousebat04

发帖
15679
M币
7561
专家
8
粉丝
82
只看该作者 4楼 发表于: 09-15
试试把数据分包发送,16字节一包,收到后返回ack,再发下一帧
在线jsycwnw

发帖
9880
M币
20374
专家
362
粉丝
270
只看该作者 5楼 发表于: 09-15
謝謝分享!专业玩家,遥拜
离线zeze10000

发帖
2787
M币
8914
专家
33
粉丝
75
只看该作者 6楼 发表于: 09-15
回 mousebat04 的帖子
mousebat04:试试把数据分包发送,16字节一包,收到后返回ack,再发下一帧 (2018-09-15 08:48) 回 mousebat04 的帖子

嗯,16字节以内的数据收发肯定会更稳定些
离线阿甲

发帖
2431
M币
9248
专家
12
粉丝
51
只看该作者 7楼 发表于: 09-15
专业,看的似懂非懂
离线mckk520

发帖
130
M币
1567
专家
9
粉丝
20
只看该作者 8楼 发表于: 09-15
天天发这些代码,你最起码要写明白,用的什么单片机,什么编译器,,代码一大通,我看只有你本人有用处,别人丈二和尚
离线xiaocake

发帖
206
M币
3657
专家
12
粉丝
15
只看该作者 9楼 发表于: 09-15
優秀文章!