文章目录

  • 需求
  • 实现
    • 一、搭建工程
    • 二、修改代码
    • 三、上位机
  • 总结

需求

实现NRF24L01/SI24R1广播通讯

实现

一、搭建工程

使用STM32CUBEMX创建工程。

使用到的外设有:

USART1----DEBUG调试

SPI1----无线模块连接

USB----上位机通讯

二、修改代码

要使用广播通讯,就不能使用ACK模式,需使用NO ACK模式,注意修改寄存器。

且使用中断接收无线数据,注意中断数据处理

最终无线部分的代码如下

static uint8_t SPIx_ReadWriteByte(SPI_HandleTypeDef *hspi, uint8_t byte) {uint8_t d_read, d_send = byte;if (HAL_SPI_TransmitReceive(hspi, &d_send, &d_read, 1, 0xFF) != HAL_OK) {d_read = 0xFF;}return d_read;
}static uint8_t SI24R1_Write_Reg(uint8_t reg, uint8_t value) {uint8_t status;SI24R1_SPI_CS_ENABLE();status = SPIx_ReadWriteByte(&hspi1, reg);SPIx_ReadWriteByte(&hspi1, value);SI24R1_SPI_CS_DISABLE();return (status);
}static uint8_t SI24R1_Read_Reg(uint8_t reg) {uint8_t reg_val;SI24R1_SPI_CS_ENABLE();SPIx_ReadWriteByte(&hspi1, reg);reg_val = SPIx_ReadWriteByte(&hspi1, 0XFF);SI24R1_SPI_CS_DISABLE();return (reg_val);
}// 在指定位置读出指定长度的数据
static uint8_t SI24R1_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t len) {uint8_t status, uint8_t_ctr;SI24R1_SPI_CS_ENABLE();status = SPIx_ReadWriteByte(&hspi1, reg);for (uint8_t_ctr = 0; uint8_t_ctr < len; uint8_t_ctr++) {pBuf[uint8_t_ctr] = SPIx_ReadWriteByte(&hspi1, 0XFF);}SI24R1_SPI_CS_DISABLE();return status;
}// 在指定位置写指定长度的数据
static uint8_t SI24R1_Write_Buf(uint8_t reg, uint8_t *pBuf, uint8_t len) {uint8_t status, uint8_t_ctr;SI24R1_SPI_CS_ENABLE();status = SPIx_ReadWriteByte(&hspi1, reg);for (uint8_t_ctr = 0; uint8_t_ctr < len; uint8_t_ctr++) {SPIx_ReadWriteByte(&hspi1, *pBuf++);}SI24R1_SPI_CS_DISABLE();return status;
}void SI24R1_Config(void) {SI24R1_SPI_CS_ENABLE();SI24R1_CE_LOW();SI24R1_Write_Reg(NRF_WRITE_REG + SETUP_RETR, 0);SI24R1_Write_Reg(NRF_WRITE_REG + FEATURE, 0x01);SI24R1_Write_Reg(NRF_WRITE_REG + EN_AA, 0);SI24R1_Write_Reg(NRF_WRITE_REG + EN_RXADDR, 0x01);SI24R1_Write_Reg(NRF_WRITE_REG + RF_CH, 40);SI24R1_Write_Reg(NRF_WRITE_REG + RF_SETUP, 0x0f);SI24R1_Write_Reg(NRF_WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);SI24R1_Write_Buf(NRF_WRITE_REG + RX_ADDR_P0, (uint8_t *)RX_ADDRESS,RX_ADR_WIDTH);SI24R1_Write_Buf(NRF_WRITE_REG + TX_ADDR, (uint8_t *)TX_ADDRESS,TX_ADR_WIDTH);SI24R1_Write_Reg(STATUS, 0x70);SI24R1_Write_Reg(FLUSH_TX, 0xff);SI24R1_Write_Reg(FLUSH_RX, 0xff);SI24R1_CE_HIGH();SI24R1_SPI_CS_DISABLE();
}// 检测24L01是否存在
uint8_t SI24R1_Check(void) {uint8_t buf[5] = {0XA5, 0XA5, 0XA5, 0XA5, 0XA5};uint8_t i;SI24R1_Write_Buf(NRF_WRITE_REG + TX_ADDR, buf, 5);SI24R1_Read_Buf(TX_ADDR, buf, 5);for (i = 0; i < 5; i++)if (buf[i] != 0XA5) break;if (i != 5) return 1;  //检测24L01错误return 0;              //检测到24L01
}void SI24R1_TxPacket(uint8_t *txbuf) {SI24R1_CE_LOW();SI24R1_Write_Buf(WR_TX_PLOAD_NOACK, txbuf, TX_PLOAD_WIDTH);SI24R1_CE_HIGH();return;
}void SI24R1_RX_Mode(void) {SI24R1_CE_LOW();SI24R1_Write_Reg(NRF_WRITE_REG + CONFIG, 0x0F);SI24R1_CE_HIGH();
}void SI24R1_TX_Mode(void) {SI24R1_CE_LOW();SI24R1_Write_Reg(NRF_WRITE_REG + CONFIG, 0x0E);SI24R1_CE_HIGH();
}static uint8_t NRF_RX_DATA[RX_PLOAD_WIDTH + 1];
void SI24R1_RX_IQR(void) {uint8_t status = 0;SI24R1_CE_LOW();status = SI24R1_Read_Reg(STATUS);if (status & RX_OK) {SI24R1_Read_Buf(RD_RX_PLOAD, NRF_RX_DATA, RX_PLOAD_WIDTH);NRF_RX_DATA[RX_PLOAD_WIDTH] = SI24R1_Read_Reg(NRF_WRITE_REG + RSSI);extern MessageList si24r1RecvDataMessageList;AddMessageListMsgData(&si24r1RecvDataMessageList, NRF_RX_DATA,RX_PLOAD_WIDTH + 1);}if (status & 0xF0) {SI24R1_Write_Reg(NRF_WRITE_REG + STATUS, status);}SI24R1_Write_Reg(FLUSH_RX, 0xff);SI24R1_Write_Reg(FLUSH_TX, 0xff);SI24R1_CE_HIGH();
}

main.c代码如下

int main(void) {HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_IWDG_Init();MX_SPI1_Init();MX_TIM4_Init();MX_USART1_UART_Init();MX_USB_DEVICE_Init();while (SI24R1_Check()) {HAL_Delay(1000);printf("Si24r1 err !!\r\n");}SI24R1_Config();SI24R1_RX_Mode();printf("Si24r1 init ok!\r\n");CreatMessageList(&usbRecvDataMessageList);CreatMessageList(&si24r1RecvDataMessageList);Message msg;uint8_t recvDataBuf[32];uint8_t len;uint8_t whileCnt = 0;while (1) {if (GetMessageList(&usbRecvDataMessageList, &msg) != 0) {len = msg.messageSize;memset(recvDataBuf, 0, sizeof(recvDataBuf));len = len < 32 ? len : 32;memcpy(recvDataBuf, msg.message, len);SI24R1_TX_Mode();HAL_Delay(1);SI24R1_TxPacket(recvDataBuf);HAL_Delay(1);SI24R1_RX_Mode();HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);free(msg.message);}if (GetMessageList(&si24r1RecvDataMessageList, &msg) != 0) {CDC_Transmit_FS(msg.message, msg.messageSize);HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);free(msg.message);}if (whileCnt++ >= 100) {HAL_IWDG_Refresh(&hiwdg);whileCnt = 0;}HAL_Delay(1);}
}

三、上位机

STM32 这端会接收所有数据,并上传到上位机,具体业务可在上位机这端处理。

上位机是用C#写的,部分代码如下:

int portDataSend(int localAddr, int destAddr, int len, byte[] buf){if (!checkAddr(localAddr)) {return -1;}if (!checkAddr(destAddr)){return -2;}if (!checkLen(len)) {return -3;}byte[] serialSendBuf = new byte[64];serialSendBuf[0] = (byte)((localAddr & 0xFF00) >> 8);serialSendBuf[1] = (byte)((localAddr & 0x00FF));serialSendBuf[2] = (byte)((destAddr & 0xFF00) >> 8);serialSendBuf[3] = (byte)((destAddr & 0x00FF));serialSendBuf[4] = (byte)((len & 0x00FF));for (int i = 0; i < len; i++) {serialSendBuf[5 + i] = buf[i];}sptMain.Write(serialSendBuf,0, 64);return 0;}
private void portDataRecvived(Object sender, SerialDataReceivedEventArgs e){int n = sptMain.BytesToRead;byte[] data = new byte[n];sptMain.Read(data, 0, n);if (n < 32) {return;}if (data[4] > DATA_MAX_LEN) {return;}int srcAddr, desAddr, len;srcAddr = (data[0] << 8) + data[1];desAddr = (data[2] << 8) + data[3];len = data[4];string recvString = System.Text.Encoding.Default.GetString(data, 5, len);if (!chbData.Checked) {if ((desAddr != 0) && (desAddr != 0xFFFF) && (desAddr != localAddr)) {return;}}string nowTime = DateTime.Now.ToString("HH:mm:ss", DateTimeFormatInfo.InvariantInfo);if (n == 33) {string rssiString = "bad";if (data[32] == 0) {rssiString = "good";}txbRecvData.AppendText(nowTime + " -> Src:0x" + srcAddr.ToString("X") + ", Des:0x" + desAddr.ToString("X") + ", Data:" + recvString + ", Rssi:" + rssiString + "\r\n");}else if (n == 32){txbRecvData.AppendText(nowTime + " -> Src:0x" + srcAddr.ToString("X") + ", Des:0x" + desAddr.ToString("X") + ", Data:" + recvString + "\r\n");}}
private void btnSendData_Click(object sender, EventArgs e){if (!sptMain.IsOpen) {MessageBox.Show("请先打开串口", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);}if (txbSendData.Text == "") {MessageBox.Show("输入数据为空!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);return;}else {if (txbSendData.Text.Length > DATA_MAX_LEN) {MessageBox.Show("数据过长\r\n最大27Bytes", "错误", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);return;}}portDataSend(localAddr, destAddr, txbSendData.Text.Length, System.Text.Encoding.Default.GetBytes(txbSendData.Text));}private void txbLocal_KeyPress(object sender, KeyPressEventArgs e){if (e.KeyChar != '\b'){if (!(((e.KeyChar >= '0') && (e.KeyChar <= '9')) ||((e.KeyChar >= 'a') && (e.KeyChar <= 'f')) ||((e.KeyChar >= 'A') && (e.KeyChar <= 'F')))){e.Handled = true;}}}private void txbDest_KeyPress(object sender, KeyPressEventArgs e){if (e.KeyChar != '\b'){if (!(((e.KeyChar >= '0') && (e.KeyChar <= '9')) ||((e.KeyChar >= 'a') && (e.KeyChar <= 'f')) ||((e.KeyChar >= 'A') && (e.KeyChar <= 'F')))){e.Handled = true;}}}

STM32用的USB使用的CDC模拟串口,底层USB每次发送的包为64Bytes;

总结

使用这种NO ACK模式,就类似于广播,不在局限于芯片的6V1这种模式,可以各种自定义。

也就类似于 UDP之于TCP吧。

还有啥不明白的可以留言,我修改下。

NRF24L01/SI24R1广播通讯相关推荐

  1. NRF52832 + NRF24L01 通讯

    NRF52832 + NRF24L01 1.通讯地址 NRF2401   5字节 00 11 22 33 44  按照寄存器配置个通道的地址 NRF52832 add0{11 22 33 44} ad ...

  2. PWA(Progressive Web App)入门系列:消息通讯

    前言 serviceWorker 的能力决定它要处理的事情,网站页面的部分逻辑处理会转移到 serviceWorker 层进行处理,这里就要页面层和 serviceWorker 层进行交互来实现消息通 ...

  3. php网页怎么和PLC通讯,plc网络通讯方式和协议

    plc网络是由几级子网复合而成,各级子网的通讯过程是由通讯协议决定的,而通讯方式是通讯协议最核心的内容.通讯方式包括存取控制方式和数据传送方式.所谓存取控制(也称访问控制)方式是指如何获得共享通讯介质 ...

  4. 基于stm32与NRF24L01的无线门禁系统

    首先,需要说明梁只是一个小本科生,水平不高,许多错误请大家指教(qq1257681989).所写的内容是我自己做的,写此博客仅在于让自己在完成之后有个回顾和总结. 进入正文,这个小制作是我选择的一个比 ...

  5. 单播、广播、组播详解

    组播协议允许将一台主机发送的数据通过网络路由器和交换机复制到多个加入此组播的主机,是一种一对多的通讯方式. IP组播的好处.优势 组播协议与现在广泛使用的单播协议的不同之处在于,一个主机用单播协议向n ...

  6. WEB即时通讯/消息推送

    写在前面 通常进行的Web开发都是由客户端主动发起的请求,然后服务器对请求做出响应并返回给客户端.但是在很多情况下,你也许会希望由服务器主动对客户端发送一些数据. 那么,该如何实现这个需求,或者说该如 ...

  7. NRF24L01+实现一对一数据双向传输

    NRF24L01+实现一对一数据双向传输 目录 说明 带负载数据ACK的双向通信 配置NRF24L01+的收发程序 收发双方数据的处理 测试代码和结果 目录 说明 最近在diy四轴飞行器的时候,需要实 ...

  8. 三菱 fx2n 通信 linux 代码,三菱FX2N PLC串行通讯指令(FNC 80 RS)

    三菱FX2N PLC串行通讯指令(FNC 80 RS) 串行通讯指令(FNC 80 RS) 1.指令格式:    [RS     D0     K8     D10    K8] 发送数据帧起始地址和 ...

  9. ip网络广播对讲的特点

    随着科技的不断发展,通讯方式也在不断地变革.传统的对讲机已经无法满足现代化沟通的需求,特别是在大型企业.学校和安保等领域对讲机的局限性已经显现出来.而一种新型通讯方式:IP网络广播对讲正在逐渐受到人们 ...

  10. 为什么处理有序数组比无序数组快?

    本文由 伯乐在线 - Jerry 翻译自 stackoverflow.欢迎加入技术翻译小组.转载请参见文章末尾处的要求. GManNickG 提问: 于某些怪异的原因,下面这段C++代码表现的异乎寻常 ...

最新文章

  1. 深入了解db file parallel read等待事件
  2. UICollectionView(一)基本概念
  3. sql连oracle链接服务器
  4. 每天坚持一个CSS——社会人
  5. python模拟浏览器模块,python模块学习---mechanize(模拟浏览器)
  6. 完整的Ubuntu18.04深度学习GPU环境配置,英伟达显卡驱动安装、cuda9.0安装、cudnn的安装、anaconda安装
  7. 阿里云知位停车:让车主好停、车场好管
  8. ubuntu突然连不上-调试方式
  9. iframe vue 前进 后退_vue常见面试题
  10. jQuery 获取页面元素的属性值
  11. 相机标准之onvif---开放型网络视频接口论坛onvif 简介
  12. ASP.NET2.0中Calendar的使用(添加自己的日期备注)
  13. Linux_《Linux命令行与shell脚本编程大全》第十章学习总结
  14. 大数据可视化平台有什么特点
  15. OpenWrt常用命令总结
  16. java优化技巧_Java 性能优化的五大技巧
  17. 随机森林回归预测r语言_R语言 决策树和随机森林 回归分析
  18. 第十章《日期与时间》第6节:ZoneId、ZoneRegion和ZoneOffset
  19. 我的世界基岩JAVA附魔_我的世界1.2.5版本,基岩版的可以100级附魔吗,就是
  20. java照片水印怎么做的_java图片加水印_百度经验

热门文章

  1. MATLAB读取图像相关的一些操作
  2. 抽奖小程序可以用html写吗,jquery 抽奖小程序实现代码
  3. 联想笔记本免费WiFi上网详解
  4. Matlab抓取网页数据
  5. 华为软件测试笔试真题之变态逻辑推理题【二】华为爆火面试题
  6. python学强化学习
  7. 开源协议的比较(BSD,Apache,GPL,LGPL,MIT)
  8. Vue Elements 可用的省市县数据
  9. python快速编程入门教材免费阅读,Python快速编程入门(第2版)
  10. PLM系统的经济收益