【WCH蓝牙系列芯片】-基于CH592开发板—2.4G模拟BLE广播发送
-------------------------------------------------------------------------------------------------------------------------------------
在RF_PHY程序的初始化中,需要依据BLE的核心规范,将接入地址设为蓝牙包的接入地址0x8e89bed6,rf_Config.accessAddress = 0x8E89BED6;
void RF_Init(void) { uint8_t state; rfConfig_t rf_Config; tmos_memset(&rf_Config, 0, sizeof(rfConfig_t)); taskID = TMOS_ProcessEventRegister(RF_ProcessEvent); //依据BLE的核心规范,填写Access Address 和 CRC24 的入值. rf_Config.accessAddress = 0x8E89BED6; // BLE广播的固定访问地址 // 禁止使用0x55555555以及0xAAAAAAAA ( 建议不超过24次位反转,且不超过连续的6个0或1 ) rf_Config.CRCInit = 0x555555; // BLE CRC校验的初始值 rf_Config.Channel = 37; // 配置射频信道为BLE广播信道37 // rf_Config.Frequency = 2480000; #if(RF_AUTO_MODE_EXAM) rf_Config.LLEMode = LLE_MODE_AUTO; #else // rf_Config.LLEMode = LLE_MODE_BASIC | LLE_MODE_EX_CHANNEL; // 使能 LLE_MODE_EX_CHANNEL 表示 选择 rf_Config.Frequency 作为通信频点 rf_Config.LLEMode = LLE_MODE_BASIC; //基础模式 #endif rf_Config.rfStatusCB = RF_2G4StatusCallBack; rf_Config.RxMaxlen = 251; //最大接收长度为251字节 state = RF_Config(&rf_Config); PRINT("rf 2.4g init: %x\n", state); uint8_t mac_addr[8]; GetMACAddress(mac_addr); // 获取MAC地址 tmos_memcpy(&TX_DATA[0], mac_addr, 6); //获取MAC地址并复制到TX_DATA hex_dump(mac_addr, 6); //十六进制打印MAC地址 // { // RX mode //#if(RF_AUTO_MODE_EXAM) // rx_end_flag = FALSE; //#endif // state = RF_Rx(TX_DATA, 10, 0xFF, 0xFF); // PRINT("RX mode.state = %x\n", state); // } { // TX mode tmos_set_event( taskID , SBP_RF_PERIODIC_EVT ); } }

在TMOS任务中,通过RF_Shut(); 先关闭射频模块:在切换射频状态前先关闭当前射频操作,避免冲突,然后再调用ble_Broadcast_tx()函数,模拟BLE的广播帧,发送BLE广播包,执行BLE广播发送操作。

构造BLE的广播测试数据,按照广播的内容格式,一包广播数据最大是31个字节,不能超过31个字节就可以
0x99,0x88,0x77, 0xE4, 0xC2, 0x84,——————设置的广播的MAC地址
9,0x09,'B','L','E','-','T','E','S','T',————设置蓝牙的广播名字(长度+类型+数据。其中长度是包含数据+类型(一个字节长度))
8,0xFF,0x11,0x22,0x33,0x44,0x55,0x66,0x77 ————设置的厂商自定义数据

然后通过调用RF_TX接口函数,将分别控制发送数据、长度、发送类型和接收类型,
RF_Tx( ble_adv_test_data,sizeof(ble_adv_test_data), 0x02, 0xFF );这里设置发送类型为0X02,是非连接广播,接收类型设置为0xff, 接收所有 “匹配类型” 的应答包。
通过BLE调试工具软件,可以观察到2.4G模拟BLE发送的蓝牙广播包数据


附件程序:
#include "CONFIG.h" #include "RF_PHY.h" extern uint8_t ble_Broadcast_tx(void); // 外部声明BLE广播发送函数 //将传入的字节数组以十六进制格式打印出来 void hex_dump(uint8_t* data,uint32_t length) { for(uint32_t i=0;i<length;i++) { PRINT("%02x ",*data); data++; } PRINT("\r\n"); } /********************************************************************* * GLOBAL TYPEDEFS */ #define RF_AUTO_MODE_EXAM 0 // 射频模式选择:0=手动模式,1=自动模式(发送后自动等待接收应答) uint8_t taskID; // 任务ID,用于TMOS操作系统的事件管理 uint8_t TX_DATA[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; // 默认发送数据缓冲区 //ble adv data for RF-PHY test // BLE广播测试数据(用于RF-PHY层测试) static uint8_t ble_adv_test_data[] = { 0x99,0x88,0x77, 0xE4, 0xC2, 0x84, //MAC ADDR 9,0x09,'B','L','E','-','T','E','S','T', //ADV name 8,0xFF,0x11,0x22,0x33,0x44,0x55,0x66,0x77 // Manufacturer data }; volatile uint8_t tx_end_flag=0; // 发送完成标志 volatile uint8_t rx_end_flag=0; // 接收完成标志 /********************************************************************* * @fn RF_Wait_Tx_End * * @brief 手动模式等待发送完成,自动模式等待发送-接收完成,必须在RAM中等待,等待时可以执行用户代码,但需要注意执行的代码必须运行在RAM中,否则影响发送 * * @return none */ __HIGH_CODE // 声明函数在高地址RAM中执行(确保快速访问,不被Flash读取延迟影响) __attribute__((noinline)) // 禁止编译器内联(保证函数独立存在于RAM) void RF_Wait_Tx_End() { uint32_t i=0; while(!tx_end_flag) // 循环等待发送完成标志置位 { i++; __nop(); // 空操作(延迟) __nop(); // 约5ms超时保护(防止无限等待,FREQ_SYS为系统时钟频率) if(i>(FREQ_SYS/1000)) // FREQ_SYS/1000 ≈ 5ms对应的时钟周期数 { tx_end_flag = TRUE; // 超时后强制置位标志 } } } /********************************************************************* * @fn RF_Wait_Rx_End * * @brief 自动模式等待应答发送完成,必须在RAM中等待,等待时可以执行用户代码,但需要注意执行的代码必须运行在RAM中,否则影响发送 * * @return none */ __HIGH_CODE __attribute__((noinline)) void RF_Wait_Rx_End() { uint32_t i=0; while(!rx_end_flag) // 循环等待接收完成标志置位 { i++; __nop(); __nop(); // 约5ms超时 if(i>(FREQ_SYS/1000)) { rx_end_flag = TRUE; // 超时后强制置位标志 } } } /********************************************************************* * @fn RF_2G4StatusCallBack * * @brief RF 状态回调,此函数在中断中调用。注意:不可在此函数中直接调用RF接收或者发送API,需要使用事件的方式调用 * 在此回调中直接使用或调用函数涉及到的变量需注意,此函数在中断中调用。 * * @param sta - 状态类型 * @param crc - crc校验结果 * @param rxBuf - 数据buf指针 * * @return none */ void RF_2G4StatusCallBack(uint8_t sta, uint8_t crc, uint8_t *rxBuf) { switch(sta) { case TX_MODE_TX_FINISH: // 发送模式:发送完成 { #if(!RF_AUTO_MODE_EXAM) // 手动模式下:设置发送完成标志 tx_end_flag = TRUE; #endif break; } case TX_MODE_TX_FAIL: // 发送模式:发送失败 { tx_end_flag = TRUE; // 无论模式,发送失败均置位标志 break; } case TX_MODE_RX_DATA: // 发送模式:接收到应答数据(自动模式) { #if(RF_AUTO_MODE_EXAM) // 自动模式下处理 tx_end_flag = TRUE; // 置位发送完成标志 if (crc == 0) { // CRC校验通过 uint8_t i; PRINT("tx recv,rssi:%d\n", (int8_t)rxBuf[0]); // 打印接收信号强度(RSSI) PRINT("len:%d-", rxBuf[1]); // 打印数据长度 for (i = 0; i < rxBuf[1]; i++) { // 打印接收数据 PRINT("%x ", rxBuf[i + 2]); } PRINT("\n"); } else { // CRC校验失败 if (crc & (1<<0)) { PRINT("crc error\n"); // CRC错误 } if (crc & (1<<1)) { PRINT("match type error\n"); // 数据类型匹配错误 } } #endif break; } case TX_MODE_RX_TIMEOUT: // 发送模式:接收应答超时(约200us) { #if(RF_AUTO_MODE_EXAM) // 自动模式下置位发送完成标志 tx_end_flag = TRUE; #endif break; } case RX_MODE_RX_DATA: // 接收模式:接收到数据 { if (crc == 0) { // CRC校验通过 uint8_t i; #if(RF_AUTO_MODE_EXAM) RF_Wait_Rx_End(); // 自动模式下等待接收完成 #endif PRINT("rx recv, rssi: %d\n", (int8_t)rxBuf[0]); // 打印RSSI PRINT("len:%d-", rxBuf[1]); // 打印数据长度 for (i = 0; i < rxBuf[1]; i++) { // 打印接收数据 PRINT("%x ", rxBuf[i + 2]); } PRINT("\n"); } else { // 校验失败 if (crc & (1<<0)) { PRINT("crc error\n"); } if (crc & (1<<1)) { PRINT("match type error\n"); } } #if(!RF_AUTO_MODE_EXAM) // 手动模式下:触发接收事件(在事件处理函数中处理) tmos_set_event(taskID, SBP_RF_RF_RX_EVT); #endif break; } case RX_MODE_TX_FINISH: // 接收模式:应答发送完成 { #if(RF_AUTO_MODE_EXAM) // 自动模式下:置位接收完成标志并触发事件 rx_end_flag = TRUE; tmos_set_event(taskID, SBP_RF_RF_RX_EVT); #endif break; } case RX_MODE_TX_FAIL: // 接收模式:应答发送失败 { #if(RF_AUTO_MODE_EXAM) // 自动模式下:置位接收完成标志并触发事件 rx_end_flag = TRUE; tmos_set_event(taskID, SBP_RF_RF_RX_EVT); #endif break; } } } /********************************************************************* * @fn RF_ProcessEvent * * @brief RF 事件处理 * * @param task_id - 任务ID * @param events - 事件标志 * * @return 未完成事件 */ // 射频事件处理函数,用于处理与射频相关的各类事件 uint16_t RF_ProcessEvent(uint8_t task_id, uint16_t events) { // 处理系统消息事件(SYS_EVENT_MSG):系统级别的消息通知 if(events & SYS_EVENT_MSG) { uint8_t *pMsg; // 消息指针,用于接收系统消息 // 接收当前任务的消息:tmos_msg_receive从消息队列中获取指定任务的消息 if((pMsg = tmos_msg_receive(task_id)) != NULL) { tmos_msg_deallocate(pMsg); // 释放消息内存:处理完消息后必须释放,避免内存泄漏 } return (events ^ SYS_EVENT_MSG); // 返回未处理的事件:清除已处理的SYS_EVENT_MSG,保留其他事件 } // 处理设备启动事件(SBP_RF_START_DEVICE_EVT):设备初始化完成后触发 if(events & SBP_RF_START_DEVICE_EVT) { tmos_start_task(taskID, SBP_RF_PERIODIC_EVT, 1000); // 启动周期性任务:在当前任务(taskID)中注册SBP_RF_PERIODIC_EVT事件,延迟1000个时间单位(通常为ms)后触发 return events ^ SBP_RF_START_DEVICE_EVT; // 清除已处理的启动事件,返回剩余事件 } // 处理周期性事件(SBP_RF_PERIODIC_EVT):按固定周期执行的射频操作 if(events & SBP_RF_PERIODIC_EVT) { RF_Shut(); // 关闭射频模块:在切换射频状态前先关闭当前射频操作,避免冲突 tx_end_flag = FALSE; // 重置发送结束标志:标记发送过程未完成 if(!RF_Tx( ble_adv_test_data,sizeof(ble_adv_test_data), 0x02, 0xFF )) // 发送数据:通过RF_Tx函数发送ble_adv_test_data缓冲区,后两个参数可能为目标地址(0x02通常(非连接广播)) { RF_Wait_Tx_End(); // 等待发送完成:如果发送函数需要阻塞等待,调用此函数确保数据发送完毕 } ble_Broadcast_tx(); // 发送BLE广播包:执行BLE广播发送操作,可能是模拟BLE的广播帧 tmos_start_task(taskID, SBP_RF_PERIODIC_EVT, 1000); // 重新启动周期性任务:设置下一次周期性事件在1000个时间单位后触发,形成循环 return events ^ SBP_RF_PERIODIC_EVT; // 清除已处理的周期性事件,返回剩余事件 } // 处理射频接收事件(SBP_RF_RF_RX_EVT):接收到数据时触发 if(events & SBP_RF_RF_RX_EVT) { uint8_t state; // 接收状态变量,用于存储RF_Rx的返回状态 RF_Shut(); // 关闭射频模块:在切换到接收模式前关闭当前操作 TX_DATA[0]++; // 更新发送缓冲区首字节:可能用于标记接收计数或状态(示例中简单递增) // 如果开启自动模式示例(RF_AUTO_MODE_EXAM宏定义),则重置接收结束标志 #if(RF_AUTO_MODE_EXAM) rx_end_flag = FALSE; #endif state = RF_Rx(TX_DATA, 10, 0xFF, 0xFF); // 进入接收模式:通过RF_Rx函数接收数据到TX_DATA缓冲区(最多10字节),后两个参数可能为接收地址过滤 PRINT("RX mode.state = %x\n", state); // 打印接收状态:调试用,输出当前接收模式的状态值 return events ^ SBP_RF_RF_RX_EVT; // 清除已处理的接收事件,返回剩余事件 } // 所有事件均已处理,返回0 return 0; } /********************************************************************* * @fn RF_Init * * @brief RF 初始化 * * @return none */ void RF_Init(void) { uint8_t state; rfConfig_t rf_Config; tmos_memset(&rf_Config, 0, sizeof(rfConfig_t)); taskID = TMOS_ProcessEventRegister(RF_ProcessEvent); //依据BLE的核心规范,填写Access Address 和 CRC24 的入值. rf_Config.accessAddress = 0x8E89BED6; // BLE广播的固定访问地址 // 禁止使用0x55555555以及0xAAAAAAAA ( 建议不超过24次位反转,且不超过连续的6个0或1 ) rf_Config.CRCInit = 0x555555; // BLE CRC校验的初始值 rf_Config.Channel = 37; // 配置射频信道为BLE广播信道37 // rf_Config.Frequency = 2480000; #if(RF_AUTO_MODE_EXAM) rf_Config.LLEMode = LLE_MODE_AUTO; #else // rf_Config.LLEMode = LLE_MODE_BASIC | LLE_MODE_EX_CHANNEL; // 使能 LLE_MODE_EX_CHANNEL 表示 选择 rf_Config.Frequency 作为通信频点 rf_Config.LLEMode = LLE_MODE_BASIC; //基础模式 #endif rf_Config.rfStatusCB = RF_2G4StatusCallBack; rf_Config.RxMaxlen = 251; //最大接收长度为251字节 state = RF_Config(&rf_Config); PRINT("rf 2.4g init: %x\n", state); uint8_t mac_addr[8]; GetMACAddress(mac_addr); // 获取MAC地址 tmos_memcpy(&TX_DATA[0], mac_addr, 6); //获取MAC地址并复制到TX_DATA hex_dump(mac_addr, 6); //十六进制打印MAC地址 // { // RX mode //#if(RF_AUTO_MODE_EXAM) // rx_end_flag = FALSE; //#endif // state = RF_Rx(TX_DATA, 10, 0xFF, 0xFF); // PRINT("RX mode.state = %x\n", state); // } { // TX mode tmos_set_event( taskID , SBP_RF_PERIODIC_EVT ); // 初始触发周期性事件 } } // BLE广播发送函数 uint8_t ble_Broadcast_tx(void) { RF_Shut( ); // 关闭当前射频操作(确保状态干净) //tx type :0X02 for no connected adv // 发送BLE广播测试数据:类型0x02(非连接广播),目标地址0xFF(广播) return RF_Tx( ble_adv_test_data,sizeof(ble_adv_test_data), 0x02, 0xFF ); }
浙公网安备 33010602011771号