历史上的今天

今天是:2024年11月25日(星期一)

2019年11月25日 | NRF24L01无线模块多机通信单片机程序 上位机+下位机

发布者:delta14 来源: 51hei关键字:NRF24L01  无线模块  多机通信  单片机 手机看文章 扫描二维码
随时随地手机看文章

最近在接了一个项目,要求各个设备能够联网(不是互联网)控制。nrf24l01刚好有这个功能。但是之前只做过一对一的通信,还是用例程的那一种。我在想,用两个地址,共用同一个通道应该也可以完成。后来他又要求发过去的数据还要能回传,这下我只好来研究多通道通信了。

多机通信和一对一通信基本上相同,就是要配置其他通道的地址和使能其他通道的有效数据宽度,还有自动应答。

这是接收机的:

void NRF24L01_Init_RX(void)
{   
CE=0;   
CSN=1;   
SCK=0;   
SPI_Write_Buf(WRITE_REG + TX_ADDR, RX_ADDRESS, TX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P1, RX_ADDRESS1, RX_ADR_WIDTH);
SPI_Write_Reg(WRITE_REG + EN_AA, 0x3f);
SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x3f);
SPI_Write_Reg(WRITE_REG + RF_CH, 40);
SPI_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x0F);
SPI_Write_Reg(WRITE_REG + CONFIG, 0x0f);
}

由于我用的是KeilC51和MDK5共存的,所以注释复制过来之后就成了乱码,在此贴图一张:

NRF24L01_Init_Rx(void)
下面就到了发送机了的配置了:

void NRF24L01_Init_TX(uint8_t *ADDRn)
{   
CE=0;
CSN=1;
SCK=0;
SPI_Write_Buf(WRITE_REG + TX_ADDR, (uint8_t*)ADDRn, TX_ADR_WIDTH);
SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, (uint8_t*)ADDRn, RX_ADR_WIDTH);
SPI_Write_Reg(WRITE_REG + EN_AA, 0x3f);
SPI_Write_Reg(WRITE_REG + EN_RXADDR, 0x3f);
SPI_Write_Reg(WRITE_REG + RF_CH, 40);
SPI_Write_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + RX_PW_P1, RX_PLOAD_WIDTH);
SPI_Write_Reg(WRITE_REG + SETUP_RETR, 0xff);
SPI_Write_Reg(WRITE_REG + RF_SETUP, 0x0f);
SPI_Write_Reg(WRITE_REG + CONFIG, 0x0E);
}

同样:


NRF24L01_Init_TX(uint8_t *ADDRn)
发送给其他通道,只要改成其他通道的地址就可以了,不用改通道号,现在还不知道为什么。

接下来就是发送函数:

uint8_t nRF24L01_TxPacket(unsigned char * tx_buf)
{
uint8_t Return_Flag=0;
CE=0;
SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH);
Delayms(2);
Return_Flag = Check_ACK(1);
return Return_Flag;
}

由于我是通过电脑串口控制上位机,发给某一个下位机,然后再发回到我的上位机中,最后回传到电脑,所以没有数据抢答的问题。

最后再说一句,要配置第N个的通道,前N个通道也必须被配置,要不然配置不成功。

最后贴上上位机程序:

#include

#include

#include "nrf24l01.h"

#include "delay.h"

#define uint32_t unsigned int

#define uint8_t unsigned char


uint8_t const RX_ADDRESS[TX_ADR_WIDTH]= {0x01,0x13,0x5C,0x0C,0x03};        //本地地址

uint8_t const RX_ADDRESS1[TX_ADR_WIDTH]={0x02,0x13,0x5C,0x0C,0x03}; //本地地址1



extern uint8_t Rx_Buf[32];

extern uint8_t Tx_Buf[32];


/**********************************RNF24L01状态标志位************************************************/

uint8_t         bdata sta;   

sbit        RX_DR        =sta^6;

sbit        TX_DS        =sta^5;

sbit        MAX_RT        =sta^4;


/**********************************NRF24L01管脚与单片机接口定义**************************************/



sbit  MISO =P3^4;

sbit  MOSI =P3^6;

sbit SCK =P3^3;

sbit  CE =P3^2;

sbit CSN =P3^5;

sbit IRQ =P3^7;




/***************************************************************************

函数名称:uchar SPI_RW(uint8_t dat)

函数功能:NRF24L01的SPI写时序

函数备注:

***************************************************************************/

uint8_t SPI_RW(uint8_t dat)

{

        uint8_t i;

           for(i=0;i<8;i++) 

           {

                MOSI = (dat & 0x80);         

                dat = (dat << 1);           

                SCK = 1;                      

                dat |= MISO;                         

                SCK = 0;                              

           }

    return(dat);                             

}


/***************************************************************************

函数名称:uint8_t SPI_Read(uint8_t cmd_reg)

函数功能:NRF24L01的SPI读时序

函数备注:

***************************************************************************/

uint8_t SPI_Read(uint8_t cmd_reg)

{

        uint8_t value;

        

        CSN = 0;               

        SPI_RW(cmd_reg);            

        value = SPI_RW(0);    

        CSN = 1;                

        

        return(value);        

}


/***************************************************************************

函数名称:void SPI_Write_Reg(uint8_t cmd_reg, uint8_t value)

函数功能:写入NRF24L01寄寄存器和从NRF24L01寄存器中读出

函数备注:

***************************************************************************/

void SPI_Write_Reg(uint8_t cmd_reg, uint8_t value)

{        

        CSN = 0;                  

        SPI_RW(cmd_reg);     

        SPI_RW(value);            

        CSN = 1;                   

}


/***************************************************************************

函数名称:uint8_t SPI_Read_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)

函数功能:从NRF24L01寄存器中读出数据

函数备注:reg:为寄存器地址,pBuf:为待读出数据地址,uint8_t:读出数据的个数

***************************************************************************/

uint8_t SPI_Read_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)

{

        uint8_t status,i;

        

        CSN = 0;                                    

        status = SPI_RW(cmd_reg);                       

        for(i=0;i        CSN = 1;                           

        

        return(status);                    

}


/***************************************************************************

函数名称:void SPI_Write_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)

函数功能:在NRF24L01寄存器中写入数据

函数备注:reg:为寄存器地址,pBuf:为待写入数据地址,uint8_t:写入数据的个数

***************************************************************************/

void SPI_Write_Buf(uint8_t cmd_reg, uint8_t *pBuf, uint8_t num)

{

        uint8_t i;        

        CSN = 0;            //SPI使能       

        SPI_RW(cmd_reg);   

        for(i=0; i        CSN = 1;           //关闭SPI

}


/***************************************************************************

函数名称:uint8_t nRF24L01_RxPacket(uint8_t* rx_buf)

函数功能:数据读取后放入rx_buf接收缓冲区中

函数备注:

***************************************************************************/

uint8_t nRF24L01_RxPacket(uint8_t* rx_buf)

{

   uint8_t flag;

        CE = 1;                          //很重要!启动接收!

        Delayms(1);

        sta=SPI_Read(READ_REG+STATUS);        // 读取状态寄存其来判断数据接收状况           //寄存器前面要加是读还是写

        if(RX_DR)                                // 判断是否接收到数据  如果置1则说明接到数据并且放置在接收缓存器

        {

           CE = 0;                 

                SPI_Read_Buf(RD_RX_PLOAD,rx_buf,RX_PLOAD_WIDTH); //这本来就是指令,不用加,意思说去缓存器里读

                flag =1;                        //读取数据完成标志

        }

        SPI_Write_Reg(WRITE_REG+STATUS,sta);   //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,通过写1来清楚中断标志

        return flag;

}





/**************************************************

函数:Check_ACK(bit clear)

描述:检查接收设备有无接收到数据包,设定没有收到应答信

            号是否重发

/**************************************************/

uint8_t Check_ACK(bit clear)

{

        while(IRQ);

        sta = SPI_RW(NOP);                    // 返回状态寄存器

        if(MAX_RT)

                if(clear)                         // 是否清除TX FIFO,没有清除在复位MAX_RT中断标志后重发

                        SPI_RW(FLUSH_TX);   //清空寄存器,很重要!!!

        SPI_Write_Reg(WRITE_REG + STATUS, sta);  // 清除TX_DS或MAX_RT中断标志

        IRQ = 1;

        if(TX_DS)

                return(0x01);

        else

                return(0x00);

}



/***************************************************************************

函数名称:void nRF24L01_TxPacket(unsigned char * tx_buf)

函数功能:发送 tx_buf中数据

函数备注:

***************************************************************************/

[1] [2]
关键字:NRF24L01  无线模块  多机通信  单片机 引用地址:NRF24L01无线模块多机通信单片机程序 上位机+下位机

上一篇:按键PWM控制led亮度单片机源程序
下一篇:ESP8266无线18B20温度手机接收有源代码和开源

推荐阅读

中国机器人产业异军突起,引起了韩国官方人士的担忧。22日,韩国媒体“Economytalk News”将其国内近5年来的机器人产业发展形容为“原地踏步”。 报道提到了韩国机器人产业振兴院(Korea InsTItu for Robot Industry vancement,下称:KIRIA)的数据:2016年,韩国进口自中国的机器人零部件占比,从前一年的3.6%暴涨近8倍,份额达到27.1%,成为...
移动应用、基础设施与国防应用中核心技术与RF解决方案的领先供应商Qorvo®, Inc.(纳斯达克代码:QRVO)今日宣布,推出市场上性能最强大的MCU和集成电机控制和驱动控制产品---新型PAC5527电源应用控制器。Qorvo在单个片上系统(SoC)控制器可实现高效率、高性能和较长的电池寿命,采用无刷直流(BLDC)电机供电工具。 Qorvo电源管理和电机驱动产品总监Dav...
据韩国时报报道,尽管存储行业受疫情影响小于其他行业,但消费产品仍受到负面影响,外界对前景产生担忧。 而三星正利用这一时期扩大领先优势,三星计划明年将 DRAM、闪存和代工芯片的月晶圆产能分别扩大 3 万、6 万和 2 万片。 一位投资经理表示,明年全年 DRAM 和 NAND 的供应将严重不足,从而导致价格和利润回升。三星在这方面显示出非常有吸引力...
广告摘要声明广告撰文 | 潘敏瑶随着终端企业对工业机器人的了解和应用不断深入,对于工业机器人的要求也越来越高,如工业机器人精度要更高,效率要更高,应用性更高,智能化更高。对于配天机器人总经理索利洋而言,客户的“四高”理解和要求,时刻激励着配天机器人在行业内不断勇攀高峰,迭代出更好的产品。“十年磨一剑”,如今的配天机器人已参与制定国...

史海拾趣

问答坊 | AI 解惑

16舵机双足机器人-----全资料奉上!

本帖最后由 paulhyde 于 2014-9-15 03:33 编辑 来源:http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3648721&bbs_page_no=1&bbs_id=9999 暑假学校里做机器人比赛,就是做出一个人型机器人来互相对打,要求无线控制的。 我因为去年做过这个 ...…

查看全部问答∨

DIY微功耗基础无线网络

DIY微功耗基础无线网络…

查看全部问答∨

直流接触器和交流接触器的区别?

应用场合不同,选择交流或直流取决于线圈,直流接触器的线圈只能通直流,交流接触器的线圈只能通交流工作。一般来说,在交流回路当中,主回路用的交流,辅助助回路一般都是从主回路上取电做控制回路,那么控制回路显然也是交流的,那么就要用交流接 ...…

查看全部问答∨

请教原理图方面的问题

我有一个项目,这个项目需要有对火警报警器、煤气报警器、气体检测仪器的原理熟悉的人才,如果有请和我联系,我的MSN:sjm428124@msn.com …

查看全部问答∨

用过AT24C02的高手请指教!

#include <STM8S105C_S.h> #define uchar unsigned char #define uint unsigned int #define data_out PB_DDR|=0X04; #define data_in PB_DDR&=~0X04; #define scl_H PB_ODR|=0X02; #define scl_L PB_ODR&=~0X02; #define sda_ ...…

查看全部问答∨

【求助】【讨论】关于用149做交流电流0-5mA得采样电路问题

互感器输出为交流0-5mA,用149采样确定电流值!!!! 请高手指点!!!!…

查看全部问答∨

关于ucosii下的数据接收

在ucosii下面,我用UARTCharGet函数,可是都无法接收数据,但是用UARTCharPut却可以发送数据,请问这是为什么啊 ?…

查看全部问答∨

请问大家IAR和CCS哪个用的人数多?

新手问一下,IAR和CCS哪个用的人数多,哪个更好用一点?你们更喜欢哪一个?…

查看全部问答∨

lowlevel_init.S的system_clock_init函数放到C语言下面实现——更好处理

在uboot原来的代码里,有系统时钟的初始化函数,在board/samsung/smdkv210/lowlevel_init.S的system_clock_init函数,我大概看了一下,寄存器不一样,而且是汇编写的,所以我就改成用c语言来实现,在BL1阶段初始化一下,BL2阶段就不用重新初始化了 ...…

查看全部问答∨

运放构成的信号累加电路输入的三种分析法

两种加法电路与对应的描述方程。 先对第一种分析,图示第一种比较简单,我们知道运放的Vin-=Vin+。所以第一个电路图上三个电阻的公共节点电势Vin-=0. (V1/R1)+(V2/R2)=(0-Vout)/RF。移项处理后就得到了公式中的第一个:Vout=-(Rf/R1)*V1-(RF/R2 ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

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

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

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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