完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
需求
实现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 != 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 !!rn"); } SI24R1_Config(); SI24R1_RX_Mode(); printf("Si24r1 init ok!rn"); CreatMessageList(&u***RecvDataMessageList); CreatMessageList(&si24r1RecvDataMessageList); Message msg; uint8_t recvDataBuf[32]; uint8_t len; uint8_t whileCnt = 0; while (1) { if (GetMessageList(&u***RecvDataMessageList, &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; } 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 + "rn"); } else if (n == 32){ txbRecvData.AppendText(nowTime + " -> Src:0x" + srcAddr.ToString("X") + ", Des:0x" + desAddr.ToString("X") + ", Data:" + recvString + "rn"); } } 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("数据过长rn最大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吧。 还有啥不明白的可以留言,我修改下。 |
|
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1097 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1111 浏览 1 评论
549 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
415 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
996 浏览 2 评论
1593浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
262浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
275浏览 3评论
245浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
238浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-8-16 14:26 , Processed in 0.976978 second(s), Total 80, Slave 64 queries .
Powered by 电子发烧友网
© 2015 www.ws-dc.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号