完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
前言
经过分析,发现的nRF24L01的无线频段和调制方式和蓝牙是相同的,都是2.4GHz的和高斯键控频移,由此产生了是否可以使用的nRF24L01发送蓝牙数据的想法,在网络上搜索发现有人在Arduino 上实现了发送蓝牙广播,精彩内容使用 nrf24l01 发送蓝牙数据是音频的。 一、硬件平台 方便,减少接入的工作,本文使用正点原子的探索开发板,在《nrf24l01无线实验通信》工程下做修改。 二、扫描蓝牙通信代码 修改发送数据函数为蓝牙的形式: 其中主要的修改点是,修改同步同步地址为蓝牙广播的同步地址,由于nrf24l01的数据存储方式和蓝牙是对的,要所以颠倒位序;然后不使能crc void NRF24L01_TX_Mode(void) { NRF24L01_CE=0; //发送节点地址4 u8 addr[4]={0x6B,0x7D,0x91,0x71}; NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)addr,4); NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)addr,4); //禁止通道自动应答 NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x00); //使能通道0的接收地址 NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //禁止自动重发 NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x00); //设置RF通道为40 NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,2); //设置TX发射参数,0db增益,1Mbps,低噪声增益开启 NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x07); //配置基本工作模式的参数;PWR_UP,不启用CRC,接收模式,开启所有中断 NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x06); NRF24L01_CE=1;//CE为高,10us后启动发送 } 接下来依次照http://www.github.com/floe/BT中的ble.cpp文件写数据帧构造的相关代码。 新建ble.c和ble.h文件,在ble.h中添加代码如下: #include "sys.h" // advertisement PDU __packed struct btle_adv_pdu { // packet header uint8_t pdu_type; // PDU type uint8_t pl_size; // payload size 负载大小,包括6字节的mac // MAC address uint8_t mac[6]; // payload (including 3 bytes for CRC) uint8_t payload[24]; }; // payload chunk in advertisement PDU payload __packed struct btle_pdu_chunk { uint8_t size; uint8_t type; uint8_t data[]; }; typedef struct { struct btle_adv_pdu buffer; char *name; uint8_t current; // current channel index }ble_struct; //把无线模块初始化为蓝牙兼容的形式 void ble_begin( ble_struct *ble,char* _name ) ; //发送广播数据 int ble_advertise( ble_struct *ble,uint8_t data_type, void* buf, uint8_t buflen ) ; //改变信道 void ble_hopChannel(ble_struct *ble) ; #endif 在ble.c中添加如下代码: 主要需要构造广播数据帧,包括蓝牙的mac地址,蓝牙名称等,用户还可以添加其他数据,例如传感器的温度计算等,最后需要交换所有数据的步骤和“白化”操作 #include "ble.h" #include "string.h" #include "24l01.h" // This is a rather convoluted hack to extract the month number from the build date in // the __DATE__ macro using a small hash function + lookup table. Since all inputs are // const, this can be fully resolved by the compiler and saves over 200 bytes of code. #define month(m) month_lookup[ (( ((( (m[0] % 24) * 13) + m[1]) % 24) * 13) + m[2]) % 24 ] const uint8_t month_lookup[24] = { 0,6,0,4,0,1,0,17,0,8,0,0,3,0,0,0,18,2,16,5,9,0,1,7 }; const uint8_t channel[3] = {37,38,39}; // logical BTLE channel number (37-39) const uint8_t frequency[3] = { 2,26,80}; // physical frequency (2400+x MHz) void ble_preparePacket(ble_struct *ble) ; void ble_transmitPacket(ble_struct *ble) ; void ble_whiten( ble_struct *ble,uint8_t len ) ; void ble_swapbuf( ble_struct *ble,uint8_t len ) ; void ble_crc( ble_struct *ble,uint8_t len, uint8_t* dst ) ; //添加数据段,返回0,成功 int ble_addChunk(ble_struct *ble,uint8_t chunk_type, uint8_t buflen, const void* buf) { if (ble->buffer.pl_size + buflen + 2 > 21 + 6) // (buflen+2) is how much this chunk will take, 21 is payload size without crc and 6 is MAC size return -1; struct btle_pdu_chunk* chunk = (struct btle_pdu_chunk*) (ble->buffer.payload+ble->buffer.pl_size-6); chunk->type = chunk_type; for (uint8_t i = 0; i < buflen; i++) chunk->data = ((uint8_t*)buf); chunk->size = buflen + 1; ble->buffer.pl_size += buflen + 2; return 0; } void ble_hopChannel(ble_struct *ble) { ble->current++; if (ble->current >= sizeof(channel)) ble->current = 0; NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH, frequency[ble->current] ); } //发送一个广播包 int ble_advertise( ble_struct *ble,uint8_t data_type, void* buf, uint8_t buflen ) { ble_preparePacket(ble); // add custom data, if applicable if (buflen > 0) { int success = ble_addChunk(ble,data_type, buflen, buf); if (0!=success) { return -1; } } ble_transmitPacket(ble ); return 0; } void ble_preparePacket(ble_struct *ble) { // insert pseudo-random MAC address ble->buffer.mac[0] = ((__TIME__[6]-0x30) << 4) | (__TIME__[7]-0x30); ble->buffer.mac[1] = ((__TIME__[3]-0x30) << 4) | (__TIME__[4]-0x30); ble->buffer.mac[2] = ((__TIME__[0]-0x30) << 4) | (__TIME__[1]-0x30); ble->buffer.mac[3] = ((__DATE__[4]-0x30) << 4) | (__DATE__[5]-0x30); ble->buffer.mac[4] = month(__DATE__); ble->buffer.mac[5] = ((__DATE__[9]-0x30) << 4) | (__DATE__[10]-0x30) | 0xC0; // static random address should have two topmost bits set //ble->buffer.pdu_type = 0x42; // PDU type: ADV_NONCONN_IND, TX address is random ble->buffer.pdu_type = 0x02; ble->buffer.pl_size = 6; //including MAC // add device descriptor chunk uint8_t flags = 0x05; ble_addChunk(ble,0x01, 1, &flags); // add "complete name" chunk if (strlen(ble->name) > 0) { ble_addChunk(ble,0x09, strlen(ble->name), ble->name); } } void ble_transmitPacket(ble_struct *ble) { uint8_t pls = ble->buffer.pl_size - 6; // calculate CRC over header+MAC+payload, append after payload uint8_t* outbuf = (uint8_t*)&ble->buffer; ble_crc( ble,pls+8, outbuf+pls+8); // whiten header+MAC+payload+CRC, swap bit order ble_whiten(ble, pls+11 ); ble_swapbuf( ble,pls+11 ); // flush buffers and send //radio->stopListening(); //radio->write( outbuf, pls+11 ); NRF24L01_TxPacket(outbuf,32); } // change buffer contents to "wire bit order" void ble_swapbuf( ble_struct *ble,uint8_t len ) { uint8_t* buf = (uint8_t*)&ble->buffer; while (len--) { uint8_t a = *buf; uint8_t v = 0; if (a & 0x80) v |= 0x01; if (a & 0x40) v |= 0x02; if (a & 0x20) v |= 0x04; if (a & 0x10) v |= 0x08; if (a & 0x08) v |= 0x10; if (a & 0x04) v |= 0x20; if (a & 0x02) v |= 0x40; if (a & 0x01) v |= 0x80; *(buf++) = v; } } // see BT Core Spec 4.0, Section 6.B.3.2 void ble_whiten( ble_struct *ble,uint8_t len ) { uint8_t* buf = (uint8_t*)&ble->buffer; // initialize LFSR with current channel, set bit 6 uint8_t lfsr = channel[ble->current] | 0x40; while (len--) { uint8_t res = 0; // LFSR in "wire bit order" for (uint8_t i = 1; i; i <<= 1) { if (lfsr & 0x01) { lfsr ^= 0x88; res |= i; } lfsr >>= 1; } *(buf++) ^= res; } } void ble_crc( ble_struct *ble,uint8_t len, uint8_t* dst ) { uint8_t* buf = (uint8_t*)&ble->buffer; // initialize 24-bit shift register in "wire bit order" // dst[0] = bits 23-16, dst[1] = bits 15-8, dst[2] = bits 7-0 dst[0] = 0xAA; dst[1] = 0xAA; dst[2] = 0xAA; while (len--) { uint8_t d = *(buf++); for (uint8_t i = 1; i; i <<= 1, d >>= 1) { // save bit 23 (highest-value), left-shift the entire register by one uint8_t t = dst[0] & 0x01; dst[0] >>= 1; if (dst[1] & 0x01) dst[0] |= 0x80; dst[1] >>= 1; if (dst[2] & 0x01) dst[1] |= 0x80; dst[2] >>= 1; // if the bit just shifted out (former bit 23) and the incoming data // bit are not equal (i.e. bit_out ^ bit_in == 1) => toggle tap bits if (t != (d & 1)) { // toggle register tap bits (=XOR with 1) according to CRC polynom dst[2] ^= 0xDA; // 0b11011010 inv. = 0b01011011 ^= x^6+x^4+x^3+x+1 dst[1] ^= 0x60; // 0b01100000 inv. = 0b00000110 ^= x^10+x^9 } } } } void ble_begin( ble_struct *ble,char* _name ) { ble->name = _name; NRF24L01_CE=0; //发送节点地址4 // u8 addr[4]={0x6B,0x7D,0x91,0x71}; u8 addr[4]={0x71,0x91,0x7D,0x6B}; NRF24L01_Write_Buf(NRF_WRITE_REG+TX_ADDR,(u8*)addr,4); NRF24L01_Write_Buf(NRF_WRITE_REG+RX_ADDR_P0,(u8*)addr,4); //禁止通道自动应答 NRF24L01_Write_Reg(NRF_WRITE_REG+EN_AA,0x00); //使能通道0的接收地址 NRF24L01_Write_Reg(NRF_WRITE_REG+EN_RXADDR,0x01); //禁止自动重发 NRF24L01_Write_Reg(NRF_WRITE_REG+SETUP_RETR,0x00); //设置RF通道为40 NRF24L01_Write_Reg(NRF_WRITE_REG+RF_CH,frequency[ble->current]); //设置TX发射参数,0db增益,1Mbps,低噪声增益开启 NRF24L01_Write_Reg(NRF_WRITE_REG+RF_SETUP,0x07); //配置基本工作模式的参数;PWR_UP,不启用CRC,接收模式,开启所有中断 NRF24L01_Write_Reg(NRF_WRITE_REG+CONFIG,0x06); NRF24L01_CE=1;//CE为高,10us后启动发送 } 三、调用 在主函数中添加如下代码: int index=0; //初始化ble对象 ble_begin(&ble,"ble_chuan"); while(1) { //在屏幕上显示发送次数 sprintf (TEXT_Buffer,"Tx runed:%d",index); LCD_ShowString(30,150,200,16,16,(u8 *)TEXT_Buffer); //发送广播 ble_advertise(&ble,0xff,0,0); //蓝牙广播信道有3个,这里切换广播信道 ble_hopChannel(&ble); index++; LED0=!LED0; delay_ms(300); }; 四、现象 手机端搜索到如下设备: 其中“ble_chuan”和程序中设置的名称相同,实验成功。 五、总结 由于nrf24l01的数据只有32字节,每次广播的数据非常有限,而且没有同步地址匹配中断等细化的功能,也不能做蓝牙的无线收发器,因此实现蓝牙数据广播有很多的使用意义,实现本程序的意义在于学习蓝牙协议。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1869浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
652浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
520浏览 3评论
539浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
508浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 03:59 , Processed in 0.866652 second(s), Total 77, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号