STM32F103C8T6 + SI24R1实现2.4G通信

原理图:

SPI时序

可以看的出来,SCK空闲时低电平,第一个跳变采样,高位先行,8Bit,HAL库可以这样配置

宏定义:

#define MY_RF_CH 69 #define RX_MODE 0 #define TX_MODE 1 #define SI24R1_CSN_LOW HAL_GPIO_WritePin(SI24R1_CSN_GPIO_Port, SI24R1_CSN_Pin, GPIO_PIN_RESET) #define SI24R1_CSN_HIGH HAL_GPIO_WritePin(SI24R1_CSN_GPIO_Port, SI24R1_CSN_Pin, GPIO_PIN_SET) #define SI24R1_CE_LOW HAL_GPIO_WritePin(SI24R1_CE_GPIO_Port, SI24R1_CE_Pin, GPIO_PIN_RESET) #define SI24R1_CE_HIGH HAL_GPIO_WritePin(SI24R1_CE_GPIO_Port, SI24R1_CE_Pin, GPIO_PIN_SET) // SI24R1 PIN DEFINITION #define MOSI P13 // Master Out, Slave In pin (output) #define MISO P10 // Master In, Slave Out pin (input) #define SCK P12 // Serial Clock pin, (output) #define CSN P15 // Slave Select pin, (output to CSN) #define CE P14 // Chip Enable pin signal (output) #define IRQ P11 // Interrupt signal, from nRF24L01 (input) #define TX_ADR_WIDTH 5 // 5字节宽度的发送/接收地址 #define TX_PLOAD_WIDTH 17 // 数据通道有效数据宽度 //********************************************************************************************************************// // SPI(SI24R1) commands #define SI24R1_READ_REG 0x00 // Define read command to register #define SI24R1_WRITE_REG 0x20 // Define write command to register #define RD_RX_PLOAD 0x61 // Define RX payload register address #define WR_TX_PLOAD 0xA0 // Define TX payload register address #define FLUSH_TX 0xE1 // Define flush TX register command #define FLUSH_RX 0xE2 // Define flush RX register command #define REUSE_TX_PL 0xE3 // Define reuse TX payload register command #define NOP 0xFF // Define No Operation, might be used to read status register //********************************************************************************************************************// // SPI(SI24R1) registers(addresses) #define CONFIG 0x00 // 'Config' register address #define EN_AA 0x01 // 'Enable Auto Acknowledgment' register address #define EN_RXADDR 0x02 // 'Enabled RX addresses' register address #define SETUP_AW 0x03 // 'Setup address width' register address #define SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address #define RF_CH 0x05 // 'RF channel' register address #define RF_SETUP 0x06 // 'RF setup' register address #define STATUS 0x07 // 'Status' register address #define OBSERVE_TX 0x08 // 'Observe TX' register address #define RSSI 0x09 // 'Received Signal Strength Indecator' register address #define RX_ADDR_P0 0x0A // 'RX address pipe0' register address #define RX_ADDR_P1 0x0B // 'RX address pipe1' register address #define RX_ADDR_P2 0x0C // 'RX address pipe2' register address #define RX_ADDR_P3 0x0D // 'RX address pipe3' register address #define RX_ADDR_P4 0x0E // 'RX address pipe4' register address #define RX_ADDR_P5 0x0F // 'RX address pipe5' register address #define TX_ADDR 0x10 // 'TX address' register address #define RX_PW_P0 0x11 // 'RX payload width, pipe0' register address #define RX_PW_P1 0x12 // 'RX payload width, pipe1' register address #define RX_PW_P2 0x13 // 'RX payload width, pipe2' register address #define RX_PW_P3 0x14 // 'RX payload width, pipe3' register address #define RX_PW_P4 0x15 // 'RX payload width, pipe4' register address #define RX_PW_P5 0x16 // 'RX payload width, pipe5' register address #define FIFO_STATUS 0x17 // 'FIFO Status Register' register address //********************************************************************************************************************// // STATUS Register #define RX_DR 0x40 /**/ #define TX_DS 0x20 #define MAX_RT 0x10 //********************************************************************************************************************// // FUNCTION's PROTOTYPES // //********************************************************************************************************************// // SI24R1 API Functions void Int_SI24R1_Init(uint8_t mode); // SI24R1 Pin Init uint8_t Int_SI24R1_Write_Reg(uint8_t reg, uint8_t value); uint8_t Int_SI24R1_Write_Buf(uint8_t reg, const uint8_t *pBuf, uint8_t bytes); uint8_t Int_SI24R1_Read_Reg(uint8_t reg); uint8_t Int_SI24R1_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t bytes); void Int_SI24R1_RX_Mode(void); void Int_SI24R1_TX_Mode(void); uint8_t Int_SI24R1_RxPacket(uint8_t *rxbuf); uint8_t Int_SI24R1_TxPacket(uint8_t *txbuf);

读写寄存器:

static uint8_t SPI_RW(uint8_t byte) { uint8_t rx_byte = 0; HAL_SPI_TransmitReceive(&hspi1, &byte, &rx_byte, 1, UINT32_MAX); return rx_byte; } /******************************************************** 函数功能:写寄存器的值(单字节) 入口参数:reg:寄存器映射地址(格式:SI24R1_WRITE_REG|reg) value:寄存器的值 返回 值:状态寄存器的值 *********************************************************/ uint8_t Int_SI24R1_Write_Reg(uint8_t reg, uint8_t value) { uint8_t status; SI24R1_CSN_LOW; status = SPI_RW(reg); SPI_RW(value); SI24R1_CSN_HIGH; return (status); } /******************************************************** 函数功能:写寄存器的值(多字节) 入口参数:reg:寄存器映射地址(格式:SI24R1_WRITE_REG|reg) pBuf:写数据首地址 bytes:写数据字节数 返回 值:状态寄存器的值 *********************************************************/ uint8_t Int_SI24R1_Write_Buf(uint8_t reg, const uint8_t *pBuf, uint8_t bytes) { uint8_t status, byte_ctr; SI24R1_CSN_LOW; status = SPI_RW(reg); for (byte_ctr = 0; byte_ctr < bytes; byte_ctr++) SPI_RW(pBuf[byte_ctr]); SI24R1_CSN_HIGH; return (status); } /******************************************************** 函数功能:读取寄存器的值(单字节) 入口参数:reg:寄存器映射地址(格式:SI24R1_READ_REG|reg) 返回 值:寄存器值 *********************************************************/ uint8_t Int_SI24R1_Read_Reg(uint8_t reg) { uint8_t value; SI24R1_CSN_LOW; SPI_RW(reg); value = SPI_RW(0); SI24R1_CSN_HIGH; return (value); } /******************************************************** 函数功能:读取寄存器的值(多字节) 入口参数:reg:寄存器映射地址(SI24R1_READ_REG|reg) pBuf:接收缓冲区的首地址 bytes:读取字节数 返回 值:状态寄存器的值 *********************************************************/ uint8_t Int_SI24R1_Read_Buf(uint8_t reg, uint8_t *pBuf, uint8_t bytes) { uint8_t status, byte_ctr; SI24R1_CSN_LOW; status = SPI_RW(reg); for (byte_ctr = 0; byte_ctr < bytes; byte_ctr++) pBuf[byte_ctr] = SPI_RW(0); // 读取数据,低字节在前 SI24R1_CSN_HIGH; return (status); }

SI24R1的SPI通信前三位是固定的,读是000,写是001,后五位是对应寄存器地址,所以写命令可以用0x20+寄存器地址进行

SI24R1接收模式初始化:

uint8_t TX_ADDRESS[TX_ADR_WIDTH] = {0x0A, 0x01, 0x07, 0x0E, 0x01}; // 定义一个静态发送地址

这里的静态地址,需要接收端和发送端相同

void Int_SI24R1_RX_Mode(void) { SI24R1_CE_LOW; Int_SI24R1_Write_Buf(SI24R1_WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 接收设备接收通道0使用和发送设备相同的发送地址 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + EN_AA, 0x01); // 使能接收通道0自动应答 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + EN_RXADDR, 0x01); // 使能接收通道0 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_CH, MY_RF_CH); // 选择射频通道(信道)69 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH); // 接收通道0选择和发送通道相同有效数据宽度 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_SETUP, 0x0f); // 数据传输率2Mbps,发射功率7dBm Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + CONFIG, 0x0f); // CRC使能,16位CRC校验,上电,接收模式 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + STATUS, 0xff); // 清除所有的中断标志位 Int_SI24R1_Write_Reg(FLUSH_RX, 0xff); // 为了解决硬件BUG SI24R1_CE_HIGH; // 拉高CE启动接收设备 }

SI24R1发送模式初始化:

void Int_SI24R1_TX_Mode(void) { SI24R1_CE_LOW; Int_SI24R1_Write_Buf(SI24R1_WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写入发送地址 Int_SI24R1_Write_Buf(SI24R1_WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 为了应答接收设备,接收通道0地址和发送地址相同 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + EN_AA, 0x01); // 使能接收通道0自动应答 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + EN_RXADDR, 0x01); // 使能接收通道0 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + SETUP_RETR, 0x0a); // 自动重发延时等待250us+86us,自动重发10次 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_CH, MY_RF_CH); // 选择射频通道69 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_SETUP, 0x0f); // 数据传输率2Mbps,发射功率7dBm Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + CONFIG, 0x0e); // CRC使能,16位CRC校验,上电 // SI24R1_CE_HIGH; }

SI24R1初始化:

void Int_SI24R1_Init(uint8_t mode) { // 检查有没有上电成功(启动) while (1) { Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + RF_CH, MY_RF_CH); uint8_t res = Int_SI24R1_Read_Reg(RF_CH); if (res == MY_RF_CH) { break; } } if (mode == RX_MODE) { Int_SI24R1_RX_Mode(); } else if (mode == TX_MODE) { Int_SI24R1_TX_Mode(); } }

先读取状态寄存器判断是否启动,通过传参配置SI24R1模式

读取接受数据:

/******************************************************** 函数功能:读取接收数据 入口参数:rxbuf:接收数据存放首地址 返回 值:0:接收到数据 1:没有接收到数据 *********************************************************/ uint8_t Int_SI24R1_RxPacket(uint8_t *rxbuf) { uint8_t state; state = Int_SI24R1_Read_Reg(STATUS); // 读取状态寄存器的值 Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + STATUS, state); // 清除RX_DR中断标志 if (state & RX_DR) // 接收到数据 { Int_SI24R1_Read_Buf(RD_RX_PLOAD, rxbuf, TX_PLOAD_WIDTH); // 读取数据 Int_SI24R1_Write_Reg(FLUSH_RX, 0xff); // 清除RX FIFO寄存器 return 0; } return 1; // 没收到任何数据 }

发送数据包:

/******************************************************** 函数功能:发送一个数据包 入口参数:txbuf:要发送的数据 返回 值:0x10:达到最大重发次数,发送失败 0x20:发送成功 0xff:发送失败 *********************************************************/ uint8_t Int_SI24R1_TxPacket(uint8_t *txbuf) { uint8_t state; SI24R1_CE_LOW; // CE拉低,使能SI24R1配置 Int_SI24R1_Write_Buf(WR_TX_PLOAD, txbuf, TX_PLOAD_WIDTH); // 写数据到TX FIFO,32个字节 SI24R1_CE_HIGH; // CE置高,使能发送 while (1) { // 读取状态寄存器的值 state = Int_SI24R1_Read_Reg(STATUS); Int_SI24R1_Write_Reg(SI24R1_WRITE_REG + STATUS, state); // 清除TX_DS或MAX_RT中断标志 if (state & MAX_RT) // 达到最大重发次数 { Int_SI24R1_Write_Reg(FLUSH_TX, 0xff); // 清除TX FIFO寄存器 return MAX_RT; } if (state & TX_DS) // 发送完成 { return TX_DS; } }; // 等待发送完成 }

发送端配置:

uint8_t absda[17] = "HELLO WORLD!!!!!"; while (1) { Int_SI24R1_TxPacket(absda); }

接收端配置:

uint8_t rx_buf[32]; while(1){ uint8_t res = Int_SI24R1_RxPacket(rx_buf); if (res == 0){ printf("Comm_Task: %s\n", rx_buf); } }

最终效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1010593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

昇腾Ascend C Add算子开发实战-从理论到代码的完整构建

目录 1 摘要 2 技术原理 2.1 架构设计理念解析 2.2 核心算法实现 2.2.1 核函数基础架构 2.2.2 三级流水线实现 2.3 性能特性分析 2.3.1 理论性能模型 2.3.2 实测性能数据 3 实战部分 3.1 完整可运行代码示例 3.2 分步骤实现指南 步骤1&#xff1a;环境配置与工程创…

AFE为何物

AFE 的全称是Analog Front-End&#xff0c;中文为模拟前端芯片&#xff0c;它是 BMS&#xff08;电池管理系统&#xff09;中负责电池核心参数采集与初步处理的关键专用芯片&#xff0c;也是高串数电池包&#xff08;如新能源车、储能电站电池&#xff09;的核心组件。 核心功…

实验实验实验实验。

这莫名其妙的问题还是没解决&#xff0c;不知道为什么这个路径没有&#xff0c;而且文章也被锁了。这是小程序运行时产生的文件夹。现在目录变了。太阴了充钱才给你看文件。小程序目录下的 1457 文件夹为空&#xff0c;核心是文件未同步/编译失败、路径指向错误、权限限制或文件…

代码随想录算法训练营第三十三天:零钱兑换,完全平方数,单词拆分

322.零钱兑换 文章讲解/视频讲解 题目描述&#xff1a; 给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1。 你可以认为每种硬币的数量是无限的。 示例 1…

令人“悲哀”的 C# 游戏生态 —— 主流引擎支持现状与现实困境

本文中所说的悲哀,是笔者个人的感受。我之所以认为“悲哀”,是因为没有这么一个/一种开源的,且对C#有着很完善的支持的游戏引擎。 头图与文无关 令人“悲哀”的 C# 游戏生态 —— 主流引擎支持现状与现实困境 前言…

工具分享:彻底解决Docker拉取慢/超时,解放双手!自动测速优选配置镜像源 代理切换脚本

背景与痛点 在国内使用 Docker&#xff0c;网络问题一直是初学docker小白的恶梦&#xff1a; docker pull 龟速&#xff1a;配置了几个国内加速器&#xff0c;但不知道哪个快&#xff0c;或者几天后突然全部失效。docker search 报错&#xff1a;搜索镜像时直接提示超时&…

单车慢跑中的节奏建议

单车定向的几个问题第21届智能车竞赛单车定向组比赛科目细则 01 单车定向中的慢跑 一、漫无目的 卓大单车还有如果这样跑可以吗&#xff1f; 我感觉这么跑的话就无线循环了&#xff0c;应该也在规则里ban了吧。 单车的两个公司的舵机可以混着用吗&#xff1f;   比如在k1车模…

CS配合CrossC2插件,实现MacOS/Linux上线

前言 我们知道CS原生只支持Windows上线&#xff0c;那么对于MacOS、Linux我们可以通过CrossC2插件实现上线下载地址&#xff1a;https://github.com/gloxec/CrossC2/releases我这里主要是演示上线MacOS&#xff0c;上线Linux是相同的&#xff0c;参考文章&#xff1a;https://…

1、掌握 Puppet 4:高效管理 IT 基础设施的秘诀

掌握 Puppet 4:高效管理 IT 基础设施的秘诀 1. Puppet 简介 在当今不断发展的软件行业中,DevOps 趋势正深刻改变着工作流程。开发者自行搭建和维护环境,运维人员则将自动化提升到新高度,把整个基础设施转化为代码。Puppet 作为一款新兴的服务器配置管理工具,凭借其独特的…

2、初探Puppet清单编写

初探Puppet清单编写 1. Puppet简介与重要性 在过去几年里,配置管理在IT领域变得越来越重要。特别是对于服务器操作而言,如果没有强大的管理基础设施,几乎无法进行。在众多可用的配置管理工具中,Puppet已成为最受欢迎和广泛使用的解决方案之一。它最初由Luke Kanies编写,…

无需运动恢复结构(SfM)的层级训练三维高斯溅射(3D Gaussian Splatting)

论文核心信息 论文题目&#xff1a;SfM-Free 3D Gaussian Splatting via Hierarchical Training&#xff08;基于分层训练的无 SfM 3D 高斯 splatting&#xff09;作者&#xff1a;Bo Ji、Angela Yao单位&#xff1a;新加坡国立大学会议&#xff1a;CVPR 2025&#xff08;计算机…

3、编写首个Puppet清单指南

编写首个Puppet清单指南 清单排序配置 Puppet的近期版本支持基于本地清单的排序方式。在 puppet.conf 配置文件中,可按如下方式配置基于清单的排序: ordering = manifest此设置在Puppet 4中为默认配置。不过,了解排序原则仍十分重要,因为在更复杂的清单中,隐式顺序难…

前端工程师必看:AI+前端+A/B测试 实战指南(小白友好版)

前端工程师必看&#xff1a;AI前端A/B测试 实战指南&#xff08;小白友好版&#xff09; 是不是总觉得“AI”“A/B测试”这些技术离自己很远&#xff1f;其实现在前端已经能直接对接AI能力、落地A/B测试了&#xff01;这篇文章会从**“是什么→前端要做什么→怎么实现”** 一步…

4、Puppet 入门:从基础使用到主从架构搭建

Puppet 入门:从基础使用到主从架构搭建 1. Puppet 类型文档与常用资源类型 Puppet 安装后,代码中内置了类型文档,可通过 puppet describe 命令在命令行打印: puppet describe <type> [-s]若不确定某个类型是否存在,可使用以下命令获取所有可用资源类型的完整列…

Notepad++紧急更新,且是两个版本,究竟修复了什么

开源文本编辑器 Notepad 接连发布了 v8.8.8/v8.8.9 更新&#xff0c;修复了更新组件 WinGUp 在对下载文件签名和证书校验不够严格的问题。 上月&#xff0c;Notepad 爆出了安全漏洞&#xff1a;在安装了 Notepad 的机器上&#xff0c;黑客劫持网络后&#xff0c;利用自动更新机…

5、Puppet 主节点与代理节点:全流程解析与性能优化

Puppet 主节点与代理节点:全流程解析与性能优化 在 Puppet 为中心的工作流里,服务器(甚至可能是工作站)配置的所有更改通常都源于 Puppet 主节点,并自动传播到代理节点。下面将详细介绍 Puppet 代理节点的生命周期、证书管理、运行方式、性能考量、不同运行方案对比、数据…

6、深入探究 Puppet:Facts、Types 与 Providers 详解

深入探究 Puppet:Facts、Types 与 Providers 详解 一、Facter 系统简介 在 Puppet 中,最初的解决方案虽然强大但成本高昂。主节点在编译过程中遇到特定表达式时需回调代理节点,编写能处理命令返回错误码的清单很费力,且 Puppet 可能变得像奇特的脚本引擎。 当使用 pupp…

C51_HC-05蓝牙通信

文章目录一、蓝牙   1、蓝牙的特点   2、蓝牙特性二、HC-05   1、简介   2、主要参数   3、引脚   4、模块原理图   5、工作模式     1&#xff09;、命令响应工作模式     2&#xff09;、自动连接工作模式     3&#xff09;、进入命令响应工作模式…

7、Puppet资源类型与模块:深入剖析与实践应用

Puppet资源类型与模块:深入剖析与实践应用 1. Puppet资源管理基础 在Puppet的资源管理体系中,资源类型和提供者是核心概念。资源类型定义了Puppet在DSL(领域特定语言)中暴露的接口,同时负责输入值的验证、转换等工作。而提供者则封装了实际操作系统及其工具链的知识,实…

8、利用类和自定义类型模块化清单

利用类和自定义类型模块化清单 编写综合类 许多类的编写目的是让 Puppet 在代理平台上执行重大任务。以 Apache 类为例,我们可以构思一个能被任何机器的清单包含的类,并确保满足以下条件: - 安装防火墙软件并配置默认规则集。 - 安装恶意软件检测软件。 - 定时任务按设定…