STC8H开发(五): SPI驱动nRF24L01无线模块

发布者:数字火箭最新更新时间:2022-06-08 来源: eefocus关键字:SPI驱动  nRF24L01  无线模块 手机看文章 扫描二维码
随时随地手机看文章

nRF24L01模块

整体介绍和STM32F1, STM32F4, STC12的代码

https://www.cnblogs.com/milton/p/14999884.html

2x4pin模块和USB测试板, Arduino配置

https://www.cnblogs.com/milton/p/8807436.html

利用FIFO队列进行发送速度优化

https://www.cnblogs.com/milton/p/15259485.html

迁移到STC8H

只需要调整SPI发送部分, 为适应nRF24L01的发送方式, 增加了多字节发送方法(节省了字节间拉高拉低CS的GPIO操作)


uint8_t SPI_TxRx(uint8_t dat)

{

SPDAT = dat;

    while (!SPI_RxTxFinished());

    SPI_ClearInterrupts();

return SPDAT;

}


void SPI_TxRxBytes(uint8_t *pBuf, uint8_t len)

{

    while(len--)

    {

        *pBuf++ = SPI_TxRx(*pBuf);

    }

}


对应nRF24L01的SPI通信部分. 这里对发送作了一些优化


将命令和后续数据合并为字节数组一并发出, 节约发送开销

发送和接收使用同一段内存地址, 节约内存开销

每次交互后, 地址的第一个字节都是当前nRF24L01的状态数据, 在某些场景可以避免二次调用

void NRF24L01_WriteReg(uint8_t reg, uint8_t value)

{

    NRF_CSN = 0;

    xbuf[0] = reg;

    xbuf[1] = value;

    SPI_TxRxBytes(xbuf, 2);

    NRF_CSN = 1;

}


uint8_t NRF24L01_ReadReg(uint8_t reg)

{

    NRF_CSN = 0;

    xbuf[0] = reg;

    xbuf[1] = NRF24_CMD_NOP;

    SPI_TxRxBytes(xbuf, 2);

    NRF_CSN = 1;

    return xbuf[1];

}


void NRF24L01_ReadToBuf(uint8_t reg, uint8_t len)

{

    NRF_CSN = 0;

    memset(xbuf, NRF24_CMD_NOP, NRF24_PLOAD_WIDTH + 1);

    xbuf[0] = reg;

    SPI_TxRxBytes(xbuf, len + 1);

    NRF_CSN = 1;

}


void NRF24L01_WriteFromBuf(uint8_t reg, const uint8_t *pBuf, uint8_t len)

{

    NRF_CSN = 0;

    xbuf[0] = reg;

    memcpy(xbuf_data, pBuf, len);

    SPI_TxRxBytes(xbuf, len + 1);

    NRF_CSN = 1;

}


nRF24L01模块演示用例

接线方式

因为使用了20pin的 STC8H1K08, 所以可选的SPI引脚只有P3开头的这组, 连线方式如下

20pin的STC8H3K32S2的接线和这个一样. 如果使用的是32pin或者更多pin的型号, 可以选择其它组的SPI


/** 

 * Example code of SPI driving NRF24L01 module

 * 

 *    Pin connection:

 *    P35(SS, Ignored) => CSN

 *    P34(MOSI)        => MOSI

 *    P33(MISO)        => MISO

 *    P32(SPCLK)       => CLK

 *    P36(INT2)        => IRQ

 *    P37(IO)          => CE

 * 

 * test-board: Minimum System; test-MCU: STC8H1K08,STC8H3K32S2

 */


配置

接收和发送方的地址配置在 nrf24l01.c, 对于发送方和接收方, 需要将这两个地址互换.


const uint8_t TX_ADDRESS[NRF24_ADDR_WIDTH] = {0x32,0x4E,0x6F,0x64,0x22};

const uint8_t RX_ADDRESS[NRF24_ADDR_WIDTH] = {0x32,0x4E,0x6F,0x64,0x65};


pin脚的配置在 nrf24l01.h, 如果有变化, 这里要相应地调整


#define NRF_CSN  P35

#define NRF_MOSI P34

#define NRF_MISO P33

#define NRF_SCK  P32

#define NRF_IRQ  P36

#define NRF_CE   P37


初始化方法

如果只发送, 则只需要进行SPI和GPIO初始化


const NRF24_SCEN CURRENT_SCEN = NRF24_SCEN_HALF_DUPLEX;

extern uint8_t __IDATA xbuf[NRF24_PLOAD_WIDTH + 1];


void SPI_Init(void)

{

    // SPI预分频

    SPI_SetClockPrescaler(SPI_ClockPreScaler_16);

    // 时钟在空闲时保持低电平

    SPI_SetClockPolarity(HAL_State_OFF);

    // 由拉低SS脚触发数据传输

    SPI_SetClockPhase(SPI_ClockPhase_LeadingEdge);

    // 数据顺序MSB

    SPI_SetDataOrder(SPI_DataOrder_MSB);

    // 设定SPI的输出脚

    SPI_SetPort(SPI_AlterPort_P35_P34_P33_P32);

    // 忽略SS脚, 使用 MSTR 控制主从模式

    SPI_IgnoreSlaveSelect(HAL_State_ON);

    // 主模式

    SPI_SetMasterMode(HAL_State_ON);

    // 开启SPI

    SPI_SetEnabled(HAL_State_ON);

}


void GPIO_Init(void)

{

    // 在配置SPI之前配置GPIO

    // MISO(P33) MOSI(P34)

    GPIO_P3_SetMode(GPIO_Pin_4, GPIO_Mode_InOut_QBD);

    // SCLK(P32) CSN(P35) CE(P37)

    GPIO_P3_SetMode(GPIO_Pin_2|GPIO_Pin_5|GPIO_Pin_7, GPIO_Mode_Output_PP);

    // IRQ(P36)

    GPIO_P3_SetMode(GPIO_Pin_6, GPIO_Mode_Input_HIP);

}


如果需要接收, 则还需要初始化中断和中断处理方法


void INT_Init()

{

    EXTI_Int2_SetIntState(HAL_State_ON);

    EXTI_Global_SetIntState(HAL_State_ON);

}


INTERRUPT(Int2_Routine, EXTI_VectInt2)

{

    NRF24L01_HandelIrqFlag();

}


接收模式

main()

{

    ...

    NRF24L01_Init(NRF24_MODE_RX);

    INT_Init();

    while (1);


发送模式

发送部分使用了FIFO队列的快速写入模式


main()

{

    ...

    NRF24L01_Init(NRF24_MODE_TX);

    UART1_TxString("NRF24L01 Initializedrn");

    while (1)

    {

        if (NRF24L01_WriteFast(tmp) == 0)

        {

            NRF24L01_ResetTX();

            err++;

        }

        else

        {

            succ++;

        }

        if (err >= 255 || succ >= 255)

        {

            UART1_TxHex(err);

            UART1_TxHex(succ);

            UART1_TxChar('.');

            err = 0;

            succ = 0;

        }

        SYS_Delay(50);

    }


半双工模式

在半双工模式下, 使用的还是普通的发送方法. 空闲时处于接收状态, 只有当发送数据时切换到发送状态, 发送后自动回到接收状态.


main()

{

    ...

    NRF24L01_Init(NRF24_MODE_RX);

    INT_Init();

    while (1)

    {

        NRF24L01_Tx(tmp);

        SYS_Delay(1000);

    }


实际测试性能

使用 STC8H1K08 fastwrite发送, STC8H3K32S2 使用中断接收


以下都是不带内容输出的测试结果

发送间隔1ms时发送速率最高, 能达到720~748个package每秒, 每个package是32字节, 差不多23K字节每秒

发送间隔为0ms时速度下降明显, 只有1ms间隔时的80%

完整代码

GitHub FwLib_STC8/tree/master/demo/spi/nrf24l01

Gitee FwLib_STC8/tree/master/demo/spi/nrf24l01

关键字:SPI驱动  nRF24L01  无线模块 引用地址:STC8H开发(五): SPI驱动nRF24L01无线模块

上一篇:STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块
下一篇:STC8H开发(四): FwLib_STC8 封装库的介绍和注意事项

推荐阅读最新更新时间:2024-11-13 13:54

SPI_FLASH时序描述及驱动编程
Ⅰ、写在前面 前面文章讲述过关于SPI的驱动(硬件SPI 和 软件模拟SPI),本文接着那篇文章来讲述关于SPI应用中【FLASH时序描述及驱动编程】。 写这篇文章的目的有两点:1.让大家知道SPI在实际应用开发中的重要意义; 2.让大家掌握SPI FLASH存储芯片的时序及驱动编程。 市面上的SPI FLASH类型很多,但是绝大部的芯片在硬件和软件上都是兼容的。虽然本文是以华邦的W25X16芯片为例来讲述时序。其实,其它大部分SPI FLASH都适用。 有必要看芯片手册,按照手册一步一步写程序吗? 1、如果你是初学者,而且还有很多时间,建议花些时间掌握一下! 原因在于作为嵌入式开发者,需要对芯片的编程有一定了解,在以
[单片机]
<font color='red'>SPI</font>_FLASH时序描述及<font color='red'>驱动</font>编程
nRF24L01钢丝绳无损检测
提出一种基于nRF24L01的钢丝绳无损检测系统设计方法,利用该系统对在线钢丝绳进行无损检测,检测结果采用nRF24L01进行无线传输,克服了有线传输的应用弊端,解决了钢丝绳恶劣的工作环境和其无损检测有线传输方式的矛盾,提高了检测精度。可以保证在役钢丝绳的安全可靠,避免钢丝绳更换的盲目性,做到按照钢丝绳的运行状态进行预知维修。并重点讲述了系统的硬件和软件设计,给出了详细的结论。 nRF24L01是一款工作在2.4~2.5 GHz世界通用ISM频段的单片无线收发器芯片。无线收发器包括:频率发生器、增强型SehockBurst TM模式控制器、功率放大器、晶体振荡器、调制器、解调器。输出功率、频道选择和协议的设置可以通过SPI接口进行
[测试测量]
nRF24L01无线模块原理图和与5V单片机的连接
nRF24L01是由NORDIC生产的工作在2.4GHz~2.5GHz的ISM 频段的单片无线收发器芯片。 两块nrf24l01可以构成一个简单的收发器。一块用来做遥控器,另一块放在小车上做接收器。 输出功率频道选择和协议的设置可以通过SPI 接口进行设置。几乎可以连接到各种单片机芯片,并完成无线数据传送工作。 nRF24L01原理图: nRF24L01与5V单片机的连接(只适用于高阻口):
[单片机]
<font color='red'>nRF24L01</font><font color='red'>无线模块</font>原理图和与5V单片机的连接
51单片机与NRF24L01数据口连接问题解决
很多朋友在调试NRF24L01时,肯定遇到这样的问题,NRF24L01供电是3.3V,最大电压不能超过3.6V,但是89C51电压是5V。NRF24L01电源是好解决,加一个117(3.3V的LDO)就可以了,但是数据口电压怎么解决呢?在网上看到很多人说加一个限流电阻就可以,我在调试时,就用了这个方法,但是用万用表测数据口电压,竟然有4.几V。哎~~~~又报费了一个NRF24L01芯片,最后问了一个硬件工程师,他说是因为电流倒灌所致。解决方法:在每个数据口加一个10K下拉电阻即可,于是我按着他的方法试了一下,果然每个数据口的电压都在3.3V以下。希望朋友们能看到我这篇文章,按这种方法可以解决给你经济损失。 以下是连接图:
[单片机]
STM8S 硬件SPI驱动74HC595
简介:一直对STM8S的硬件SPI感兴趣,但没有真正使用过,以往都是用IO口模拟,这次刚好有个板子上有两个595驱动的8位LED数码管,就在上面试了一把,把过程记录一下。 硬件接线图: 595是数据接收器件,所以MCU只用了3条线与之相连,分别是MOSI接SER,SCK接CLK,NSS接RCK。其实这里RCK可以用其他的IO口的。 相关的代码: LOCAL uint8 DISP_BUF ={0,1,2,3,4,5,6,7}; //显示缓冲区 PUBLIC uint8 DISP_TAB = //显示码表 { 0x14,0xD7,0x4C,0x45,0x87,0x25,0x24,0x57,0x04,0x05,0x06,
[单片机]
STM8S 硬件<font color='red'>SPI</font><font color='red'>驱动</font>74HC595
470MHz无线模块在智能垃圾桶中的应用
垃圾箱随处可见,智能垃圾箱您又是否见过? 大街小巷中,垃圾箱是处处可见,然而目前城市对垃圾箱的管理还处于非智能状态,清洁工人得每天花大量精力去清理,对于很多地区,地广人稀,对垃圾箱的管理更是耗时耗力。很多情况是垃圾箱满了,得不到及时清理,垃圾苍蝇都满天飞;有时候环保车老远开来,垃圾箱却是空空如也;烟头落入垃圾箱,导致垃圾燃烧引起火灾更不容忽视。   图1:被称为小黄罐的传感器   而最早在芬兰,一家专注于垃圾管理和回收的创业公司(PS:可不是环卫所哦!),是一家软硬件结合的科技公司,一款名为Enevo ONe Collect的产品,旨在解决优化垃圾管理和回收问题。   图2:超声波检测   其实
[嵌入式]
STC8H开发(十四): I2C驱动RX8025T高精度实时时钟芯片
计时时钟芯片概览 常用的计时时钟芯片有 DS12C887, DS1302, DS1307, DS3231, RX8025, 各型号还有衍生型号. 可以看到到大部分是Dallas生产的芯片, RX8025的厂商是Epson. 其中 DS1302 和 DS1307 可以看成是同一芯片的不同协议版本(SPI和I2C), 需要外接晶振, 如果晶振不带温补, 计时误差受温度影响较大. DS12C887是内建晶振的DS12C885, 在出厂时已经经过校准, 在+25°C时误差为±1分钟/月. DS12C887使用并口, 比较浪费IO资源, 另外体积也较大, 现在大都用于DIY用途. DS3231 自带温补晶振, 精度很高, 在 范围内误差
[单片机]
<font color='red'>STC8H</font>开发(十四): I2C<font color='red'>驱动</font>RX8025T高精度实时时钟芯片
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved