一、架构说明
【注意】 CMSIS版本不能低于5.8.0,否则程序将不正常运行。 ARM.CMSIS.5.8.0.pack
5.8.0更新了 [GCC LinkerDescription,GCC 汇编程序启动] [为工具链 ARM、GCC 添加了 ARMv8-M 堆栈密封(到链接器、启动)]
[项目结构]
+---Master_Slave(alone)
| +---app
| | +---app_led [LED线程任务]
| | +---led_gpio [LED_GPIO操作]
| | +---app_adc [将ADC值进行计算]
| | +---app_soft_voltameter [软电量计算法]
| | ---app_key [按键扫描]
| +---bsp
| | ---nrf52 [BSP层公共接口函数]
| +---chip
| | +---nRF_Drivers [芯片驱动函数]
| | +---nRF_Libraries [芯片支持函数]
| | ---nRF5_SDK_17.0.2_d674dde [芯片SDK版本]
| +---lib
| | ---queue [消息队列]
| +---os
| | ---rtx5 [OS层公共接口函数]
| +---platform
| | +---log [日记函数]
| | ---SEGGER_RTT [RTT库]
| +---sys
| | ---nrf52 [SYS层公共接口函数]
| +---main_HandWriteBoard [项目业务层]
| │ sdk_config.h (NRF功能配置)
| │ business_gpio.h (引脚定义)
| │ business_function.h (功能定义/业务宏)
| │ app_main.c (主业务功能)
| │ biz_led.c (灯光功能:电量灯/射频灯)
| │ biz_key.c (按钮功能:电源键)
| │ biz_power.c (电源管理:充放电状态/电池信息/电源开关)
| │ biz_uart.c (串口数据接收:决定串口通道对应的协议)
| │ biz_flash.c (Flash信息存储和读取)
| +---public [项目公共层]
| │ biz_esb.c (2.4G功能函数:发送端/接收端)
| │ biz_fds.c (重新封装fds函数)
| │ biz_low_power.c (空闲检测逻辑)
[FLASH结构]
nRF52810 192 KB Flash, 24 KB RAM
0x30000 0x6000
使用boot时:keil需要在Options-c/c++-Define 添加宏定义 MBR_PRESENT
boot文件:public_codenrf52810_boot_uart.hex
名称 地址 大小(字节)
|----------------------------------------------------------
MBR: 0x0000 0x1000 (mbr_nrf52_2.4.1_mbr.hex)
APP: 0x1000 0x30000 - boot_size - RSV1_SIZE - RSV2_SIZE - mbr_size = 0x27000
Boot: 0x28000 0x6000
RSV1: 0x2E000 0x1000 (settings.hex)--Bootloader setting
RSV2: 0x2F000 0x1000 (settings.hex)--MBR parameters
END: 0x30000
|-----------------------------------------------------------
boot+app addr: 0x0
fds addr:0x27000 - 0x0C00 = 0x26400
fds_size: 3 * 0x0400 = 0x0C00
二、ESB工作原理
RADIO 数据包配置
PREAMBLE: 前导码或者说帧头,一个字节长度(除了2M/s 蓝牙模式),前导码自动配置的,用户不用设置。
ADDRESS: 广播地址由基地址(base)+前缀地址(prefix )两部分组成。基地址长度:2-4字节,其长度可以通过寄存器PCNF1的BALEN位配置。
支持星状网络拓扑实现一拖多的双向链路是nrf52的一个特点,nrf52一个接收端能最多支持8个发送端。
8个逻辑通道(pipe)拥有单独特定的传输物理地址,所以保证了数据不会错乱。8个逻辑地址是如何和物理地址对应呢,如下图逻辑地址的定义,第一章我们说了物理地址由base+prefix组成,所以通道0的地址是BASE0+prefix[0],其他的地址是BASE1+prefix[1]~[7]。然后发送端发送自己逻辑地址,接收端接收判断收到数据包逻辑通道。
static nrf_esb_payload_t tx_payload = NRF_ESB_CREATE_PAYLOAD(0, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00);
static nrf_esb_payload_t rx_payload = {0};
// 下面四个数组可以通过uart或者其他方式来修改频率和地址
static uint8_t base_addr_0[4] = {0x20, 0x21, 0x05, 0x19};
static uint8_t base_addr_1[4] = {0x95, 0x81, 0x69, 0x6f};
static uint8_t addr_prefix[8] = {0x78, 0x75, 0x65, 0x6a, 0x69, 0x61, 0x6e, 0x71};
__attribute__((aligned(4))) uint8_t rf_freq_table[RF_FREQ_MAX_VAL] = {0x6c, 0x69, 0x73, 0x75, 0x6e};
1. 通道地址分配如下(主机和从机base_addr_0、base_addr_1、addr_prefix必须一致才能8组设备通信)
通道0:base_addr_0(4字节) + addr_prefix[0]
通道1:base_addr_1(4字节) + addr_prefix[1]
通道2:base_addr_1(4字节) + addr_prefix[2]
通道3:base_addr_1(4字节) + addr_prefix[3]
通道4:base_addr_1(4字节) + addr_prefix[4]
通道5:base_addr_1(4字节) + addr_prefix[5]
通道6:base_addr_1(4字节) + addr_prefix[6]
通道7:base_addr_1(4字节) + addr_prefix[7]
2. 每个设备必须编号0-7,且每个通道只能用特定编号通道发送。(例如:设备5,对通道5发送数据,则设备0-4,6-7,都能收到通道5发来的消息)
4. 自定义通信协议
字节0 字节1 字节2 字节3 -- (n-1) 字节n
要发送的通道(0-7) 命令值 数据长度 数据内容 校验合(数据内容累加,取低八位)
占用资源:
Radio (NRF_RADIO)
Timer: NRF_TIMER2 //这里用到了发送数据的时候等待应答以及延时重发过程
PPI channels 10, 11, 12, and 13 //与NRF_TIMER2联合用到发送数据的时候等待应答以及延时重发Software interrupt 0
如何判断数据来自来个通道?
/**@brief Enhanced ShockBurst payload.
* @details 所述有效载荷用于传输和确认带有有效载荷的接收数据包。
*/
typedef struct
{
uint8_t length; //报文长度(最大值为@ref NRF_ESB_MAX_PAYLOAD_LENGTH)。
uint8_t pipe; //当前消息通道号
int8_t rssi; //收到的报文为RSSI。
uint8_t noack; //指示此包将不被确认的标志。 当启用选择性自动应答时,该标志被忽略。
uint8_t pid; //在通信期间分配的PID。
uint8_t data[NRF_ESB_MAX_PAYLOAD_LENGTH]; //数据数组(可以是发送数据,也可以是接收数据)
} nrf_esb_payload_t;
----------------------------------
/**
* @brief [ESB回调事件] 接收通知收发事件,并处理事件
* @param *p_event: esb事件类型
*/
void nrf_esb_event_handler(nrf_esb_evt_t const *p_event)
{
switch (p_event->evt_id)
{
case NRF_ESB_EVENT_RX_RECEIVED:
if (nrf_esb_read_rx_payload(&rx_payload) == NRF_SUCCESS)
{
if (get_comm_connect_state() == SYS_CONNECT_TYPE_RF)
{
LOG_D("ESB_CH_RX:%drn", rx_payload.pipe);
esb_clean_rx_heart_time();
esb_set_rx_connect_state(true);
// 跳转业务处理函数
if (g_rx_dispose_callback)
{
g_rx_dispose_callback(rx_payload.data, rx_payload.length);
}
}
}
break;
}
}
如何给对应通道发送数据?
/**
* @brief [ESB操作][发送端][发送数据] 发送一包数据(异步)
* @note 异步发送
* @param *pdata: 待发送的数据指针
* @param len: 数据长度
* @retval 发送状态
*/
uint32_t esb_tx_send(uint8_t ch, uint8_t *pdata, uint8_t len)
{
tx_payload.pipe = ch;
tx_payload.length = len;
memcpy(tx_payload.data, pdata, len);
return nrf_esb_write_payload(&tx_payload);
}
/**
* @brief 处理消息队列中的消息,通过rf发送(放在空闲线程使用)
*/
bool rf_data_dispose(void)
{
if (!queue_de(&m_rf_tx_q, g_rf_tx_data))
上一篇:[nrf52820] DONGLE适配器 ESB(2.4G) 主从一体方案 多通道通信 动态调频
下一篇:[nrf51][nrf52] nrfconnect 安装说明指南
推荐阅读最新更新时间:2024-10-30 08:31
设计资源 培训 开发板 精华推荐
- 瑞萨电子最新触控微控制器R7F0C208入门套件免费申请,参与申请还能赢好礼!
- Intel有奖接力 白皮书下载进行到底
- 免费申请|基于STM32H7处理器的机器视觉微控制器板OpenMV4 Cam H7
- Maxim 利用nanoPower创新技术,致力于降低系统的静态功耗 看视频答题赢好礼! 还有免费开发板等你拿
- 福禄克明星款热像仪全新来袭,抢先免费体验赢好礼
- 有奖调查 | 您是如何采购或选择电子元器件的?
- 最后一周报名,STM32中国峰会暨粉丝狂欢节,5月12-13日深圳
- 【已结束】 电感应用知识分享|MPS 有奖直播
- 现场抽取PS5等诸多好礼 SiFive RISC-V 中国技术论坛 上海、北京、深圳 3场线下活动邀您出席!