基於rt-thread使用nrf24l01實現多點通信

基於rt-thread使用nrf24l01實現多點通信

前言

本文檔爲 基於 RT-Thread 的分佈式無線溫度監控系統DIY項目的第二週任務:使用 nrf24l01 軟件包發送與接收溫度數據。關於如何獲取nrf24l01軟件包,如何使用消息隊列、郵箱來實現線程間的通信等知識就不在此贅述了,官方教程寫得很詳細,這裏主要講一下如何使用I/O設備模型框架來管理設備。還有nrf24l01無線模塊的通信機制、配置設置也不多講,芯片數據手冊寫得很詳細,網上資料一大堆。這裏就只重點記錄幾個我自己在調試過程中遇過的坑!!!

主要內容如下:

  • rt-thread I/O設備模型框架了解
  • 如何將nrf24l01註冊到I/O設備管理器
  • 修改nrf24l01軟件包,實現多點通信功能
  • nrf24l01使用注意事項

rt-thread I/O設備模型框架了解

介紹(rt-thread官方講得很詳細,先抄爲敬)

1、RT-Thread 的 I/O 設備模型框架位於硬件和應用程序之間,共分成三層,從上到下分別是 I/O設備管理層、設備驅動框架層、設備驅動層。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6PfThq2d-1574685658040)(87AE7CE9DB884C40B219927D3B52AFD4)]

2、應用程序通過 I/O 設備管理接口獲得正確的設備驅動,然後通過這個設備驅動與底層 I/O 硬件設備進行數據(或控制)交互
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-VcvdiQvY-1574685658041)(BD4053A5A2A44440AE658BFB23A3031A)]

3、設備驅動框架層是對同類硬件設備驅動的抽象,將不同廠家的同類硬件設備驅動中相同的部分抽取出來,將不同部分留出接口,由驅動程序實現。使用設備驅動框架層可以簡單快速的將實體設備註冊到I/O設備管理層中

4、設備驅動層是一組驅使硬件設備工作的程序,實現訪問硬件設備的功能。它負責創建和註冊 I/O 設備

創建I/O設備:rt_device_create(int type, int attach_size)

rt_device_register(rt_device_t dev, const char* name, rt_uint8_t flags)

  • 對於操作邏輯簡單的設備,可以不經過設備驅動框架層,直接將設備註冊到 I/O 設備管理器
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-H09siO92-1574685658041)(847E0152BF8C4B26B4E1BFA9F1F9E8ED)]

  • 對於另一些設備,如看門狗、SPI、傳感器等,則會將創建的設備實例先註冊到對應的設備驅動框架中,再由設備驅動框架向 I/O 設備管理器進行註冊
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yzmhCutu-1574685658041)(4B58D37B5199440BB8F080E6DAAE5C32)]

SPI FLASH設備驅動使用流程

  • 梳理SPI FLASH設備的使用流程,爲後面將nrf24l01無線設備註冊到系統中做準備
  • 要將SPI FLASH設備用起來,需要先將spi總線(如:spi1)和spi設備(如:spi10)通過spi設備驅動框架(spi_core.c、spi_dev.c)註冊到I/O設備管理器中;很nice的是rtt在給我們提供的spi驅動drv_spi.c中已經全部都做好了,具體流程如下的第1、2步
  • 註冊好spi總線和spi設備後,還需將FLASH作爲塊設備註冊到直接註冊到I/O設備管理器中,以w25qxx爲例,該系列的FLASH驅動rtt也已經在spi_flash_w25qx.c中給我們寫好了,是不是很爽!具體流程如下的第3步

1、註冊spi總線到I/O設備管理器中

int rt_hw_spi_init(void)
{
    stm32_get_dma_info();
    return rt_hw_spi_bus_init();
}
INIT_BOARD_EXPORT(rt_hw_spi_init);

這裏已經使用rt_hw_spi_init自動將選擇的spi總線註冊到了系統中,所以不再需要手冊註冊。函數調用流程爲:

rt_hw_spi_bus_init()--->
/* register a SPI bus */
rt_err_t rt_spi_bus_register(struct rt_spi_bus       *bus,
                             const char              *name,
                             const struct rt_spi_ops *ops) --->
/*將spi總線定義爲RT_Device_Class_SPIBUS類型註冊到系統中*/
rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name) --->
/* register to device manager */
rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
                            

2、註冊spi設備到I/O設備管理器中,並附加到一個spi總線上,函數調用流程爲:

/** 1、調用rt_spi_bus_attach_device(spi_device, device_name, bus_name, (void *)cs_pin)
    2、attach a device on SPI bus 
*/
rt_err_t rt_hw_spi_device_attach(const char *bus_name, 
                                 const char *device_name,
                                 GPIO_TypeDef *cs_gpiox, 
                                 uint16_t cs_gpio_pin) -->
/** 1、根據bus_name找到spi_bus設備
    2、將spi_bus設備賦值給spi_dev設備的bus
    3、調用rt_spidev_device_init
    4、將user_data賦值給device->parent.user_data
        struct rt_spi_device
        {
            struct rt_device parent;
            struct rt_spi_bus *bus;
        
            struct rt_spi_configuration config;
            void   *user_data;
        };
*/                                 
rt_err_t rt_spi_bus_attach_device(struct rt_spi_device *device,
                                  const char           *name,
                                  const char           *bus_name,
                                  void                 *user_data)-->
                            
/*將spi_dev設備RT_Device_Class_SPIDevice註冊到系統中*/      
rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name) --->
/* register to device manager */
rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);

使用示例:rt_hw_spi_device_attach(“spi1”,“spi10”,GPIOA,GPIO_PIN_5);

3、註冊FLASH設備到系統中,並附加到一個spi設備上

struct spi_flash_device
{
    struct rt_device                flash_device;
    struct rt_device_blk_geometry   geometry;
    struct rt_spi_device *          rt_spi_device;
    struct rt_mutex                 lock;
    void *                          user_data;
};

/** 1、根據spi_device_name找到spi_dev設備
    2、將spi_dev設備賦值給spi_flash_device設備的rt_spi_device
    3、將spi_flash_device設備RT_Device_Class_SPIDevice註冊到系統中
*/
rt_err_t w25qxx_init(const char * flash_device_name, const char * spi_device_name) -->
rt_device_register(&spi_flash_device.flash_device,flash_device_name,RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);

使用示例:
1、w25qxx_init(“w25q128”,“spi10”); /* 使用spi_flash_w25qxx驅動 /
2、rt_sfud_flash_probe(“w25q128”,“spi10”); /
使用spi_flash_sfud驅動 */


如何將nrf24l01註冊到I/O設備管理器

  • 原nrf24l01軟件包,在nrfl24_port.c中完成了hal_nrf24l01_port芯片spi驅動的移植,在nrf24l01.c中使用hal_nrf24l01_port完成了芯片初始化、芯片讀寫操作等API的封裝。只需要修改hal_nrf24l01_port就可以很方便的移植到其他的rtos中了,且提供了sample使用起來非常簡單。
  • 但是nrf24l01軟件包沒有使用I/O設備框架模型,感覺少了一點rtt的味道;然後也是爲了練習下如何將設備註冊到I/O設備管理器中。所以想在nrf24l01軟件包基礎上,將nrf24l01作爲網絡設備(RT_Device_Class_NetIf)註冊到了I/O設備管理器中,然後有了本節內容

將nrf24l01文件自動添加至工程中

1、在rt-thread\components\drivers\Kconfig中添加如下字段,就可在env中選擇配置nrf24l01了

config RT_USING_SPI_NRF24L01
    bool "Using nRF24L01 SPI 2.4G wireless interface"
    default n

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-y7WXMj0E-1574685658042)(4C410952BE33460EA26C0E8A199A156F)]

2、在rt-thread\components\drivers\spi\SConscript中添加如下字段,在scons編譯的時候就能自動將spi_wire_24l01.c添加至工程中了

if GetDepend('RT_USING_SPI_NRF24L01'):
    src_device += ['spi_wire_24l01.c']

創建spi無線設備

/* nrf24l01配置內容 */
struct nrf24_cfg
{
    struct nrf24_esb esb;        //自動重發
    nrf24_role_et    role;       //角色選擇 (PTX、PRX)
    nrf24_power_et   power;      //功率選擇
    nrf24_adr_et     adr;        //空中速率(1Mbps、2Mbps)
    nrf24_crc_et     crc;        //crc長度選擇(1byte、2bytes)
    char             selchx;     //選用通道:bit0->pipe0,..bit3->pipe3,..bit5->pipe5
    char             ch0t1revaddr[2][5]; //ch0 to ch1 接收地址 (address[0]爲最低字節)
    char             ch2t5revaddr[4][1]; //ch2 to ch5 接收地址 (address[0]爲最低字節)
    char             sendaddr[5];//發送地址
    uint8_t          channel;    //頻率選擇(0 : 125 對應 2.4GHz : 2.525GHz)
    uint8_t          use_irq;    //是否使用中斷
    void             *ud;        //用來傳遞對底層的配置 struct hal_nrf24l01_port_cfg
};

/* nrf24l01操作接口 */
struct nrf24_ops
{
	int (*nrf_init)   (struct nrf24_cfg cfg, rt_base_t pin_ce, rt_base_t pin_irq);
    int (*ptx_run)    (uint8_t *pb_rx, const uint8_t *pb_tx, uint8_t tlen);
    int (*prx_cycle)  (uint8_t *pb_rx, const uint8_t *pb_tx, uint8_t tlen, uint8_t *rx_chnum);
	int (*irq_ptx_run)(uint8_t *pb_rx, const uint8_t *pb_tx, uint8_t tlen);
    int (*irq_prx_run)(uint8_t *pb_rx, const uint8_t *pb_tx, uint8_t tlen, uint8_t *rx_chnum);
};

/* nrf24l01私有結構 */
struct nrf24
{
	rt_base_t                pin_ce; //CE引腳
	rt_base_t                pin_irq;//IRQ引腳
	struct nrf24_cfg         cfg;    //nrf24l01配置內容
	struct nrf24_ops        *ops;	//nrf24l01操作接口
};

/* spi無線設備(這裏是我自己這麼叫的哈 哈哈)*/
struct spi_wire_device
{
    struct rt_device         wire_device;
    struct rt_spi_device    *rt_spi_device;
    struct rt_mutex          lock;
	struct rt_semaphore      irq_sem;
	struct nrf24             nrf24l01; /* nrf24l01私有結構 */
    void                    *user_data;
};

封裝nrf24l01操作接口

這裏就是直接將nrf24l01軟件包中的操作接口copy過來了,然後修改了init函數,使支持多通道通信;在prx_cycle函數和irq_prx_cycle函數中增加了rx_chnum字段,用以獲取接收數據的通道號

static struct nrf24_ops nrf24l01_ops =
{
	nrf24l01_init,
    nrf24l01_ptx_run,
    nrf24l01_prx_cycle,
    nrf24l01_irq_ptx_run,
    nrf24l01_irq_prx_run,
};

新增spi無線設備註冊函數

rt_err_t nrf24xx_init(const char * wire_device_name, const char * spi_device_name)
{
	struct rt_spi_device * rt_spi_device;

	/* initialize mutex */
	if (rt_mutex_init(&spi_wire_nrf24l01.lock, spi_device_name, RT_IPC_FLAG_FIFO) != RT_EOK)
	{
		rt_kprintf("init wire lock mutex failed\n");
		return -RT_ENOSYS;
	}

	rt_spi_device = (struct rt_spi_device *)rt_device_find(spi_device_name);
	if(rt_spi_device == RT_NULL)
	{
		rt_kprintf("spi device %s not found!\r\n", spi_device_name);
		return -RT_ENOSYS;
	}
	spi_wire_nrf24l01.rt_spi_device = rt_spi_device;

	/* register device */
	spi_wire_nrf24l01.wire_device.type	  = RT_Device_Class_NetIf;
#ifdef RT_USING_DEVICE_OPS
	spi_wire_nrf24l01.wire_device.ops	  = &spi_device_ops;
#else
	spi_wire_nrf24l01.wire_device.init	  = spi_wire_init;
	spi_wire_nrf24l01.wire_device.open	  = spi_wire_open;
	spi_wire_nrf24l01.wire_device.close   = spi_wire_close;
	spi_wire_nrf24l01.wire_device.read	  = spi_wire_read;
	spi_wire_nrf24l01.wire_device.write   = spi_wire_write;
	spi_wire_nrf24l01.wire_device.control = spi_wire_control;
#endif
	/* private */
	spi_wire_nrf24l01.nrf24l01.ops = &nrf24l01_ops;
	spi_wire_nrf24l01.user_data    = RT_NULL;

	rt_device_register(&spi_wire_nrf24l01.wire_device, wire_device_name,
					   RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);

	return RT_EOK;

}

使用示例:rt_hw_nrf24l01_port

static int rt_hw_nrf24l01_port(void)
{
	__HAL_RCC_GPIOA_CLK_ENABLE();
	rt_hw_spi_device_attach("spi1", SPI_DEV_NAME, GPIOA, GPIO_PIN_4);
	nrf24xx_init(SPI_WIRE_DEV_NAME, SPI_DEV_NAME);
    return RT_EOK;
}

修改nrf24l01軟件包,實現多點通信功能

  • 修改nrf24l01_default_param函數,給6個pipe的RX_ADDR,和TX_ADDR賦初值
  • 修改init函數,使能和配置selchx選中的通道
  • 修改prx_cycle和irq_prx_cycle接收函數,添加rx_chnum字段獲取接收通道號
  • 配置示例,如何使用selchx來選擇想要的pipe

修改nrf24l01_default_param

void nrf24l01_default_param(struct nrf24_cfg *pt)
{
	const char ch0t1addr0[5] = {0xE7,0xE7,0xE7,0xE7,0xE7};
	const char ch0t1addr1[5] = {0xC2,0xC2,0xC2,0xC2,0xC2};
	const char ch2t5addr2[1] = {0xC3};
	const char ch2t5addr3[1] = {0xC4};
	const char ch2t5addr4[1] = {0xC5};
	const char ch2t5addr5[1] = {0xC6};
	const char sendaddr[5]   = {0xE7,0xE7,0xE7,0xE7,0xE7};
	
    pt->power = RF_POWER_0dBm;
    pt->esb.ard = 5;        // (5+1)*250 = 1500us
    pt->esb.arc = 6;        // up to 6 times
    pt->crc = CRC_2_BYTE;   // crc; fcs is two bytes
    pt->adr = ADR_1Mbps;    // air data rate 1Mbps
    pt->channel = 6;        // rf channel 6
	pt->selchx  = 0x01;     // select pipe,bit0->pipe0,..bit3->pipe3,..bit5->pipe5,default : pipe 0
	
	rt_strncpy(pt->ch0t1revaddr[0],ch0t1addr0,5);
	rt_strncpy(pt->ch0t1revaddr[1],ch0t1addr1,5);
	rt_strncpy(pt->ch2t5revaddr[0],ch2t5addr2,1);
	rt_strncpy(pt->ch2t5revaddr[1],ch2t5addr3,1);
	rt_strncpy(pt->ch2t5revaddr[2],ch2t5addr4,1);
	rt_strncpy(pt->ch2t5revaddr[3],ch2t5addr5,1);
	rt_strncpy(pt->sendaddr,sendaddr,5);
}

修改nrf24l01_init

static int nrf24l01_init(struct nrf24_cfg cfg, rt_base_t pin_ce, rt_base_t pin_irq)
{
	RT_ASSERT(&cfg);
    RT_ASSERT(pin_ce >= 0);
	char i =0;
	rt_err_t err = RT_EOK;
		
	/* config spi */
	{
		struct rt_spi_configuration spi_cfg;
		spi_cfg.data_width = 8;
		spi_cfg.mode       = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
		spi_cfg.max_hz     = 5 * 1000 * 1000; /* 50M */
		rt_spi_configure(spi_wire_nrf24l01.rt_spi_device, &spi_cfg);
	}

	/* ce config*/
	{
		rt_pin_mode(pin_ce, PIN_MODE_OUTPUT);

		rt_pin_write(pin_ce, PIN_LOW);
	}

	/* if irq, config irq pin*/
	{
		if (pin_irq)
		{
			err = rt_sem_init(&spi_wire_nrf24l01.irq_sem, "nrfIRQ", 0, RT_IPC_FLAG_FIFO);
			if (err != RT_EOK)
			{
				rt_kprintf("init wire irq sem failed\n");
				return -RT_ENOSYS;
			}
			rt_pin_attach_irq(pin_irq, PIN_IRQ_MODE_FALLING, nrf24l01_irqsem_release, 0);
			rt_pin_irq_enable(pin_irq, PIN_IRQ_ENABLE);
		}
	}
	
	if ((cfg.role != ROLE_PTX) && (cfg.role != ROLE_PRX))
    {
        rt_kprintf("[nrf24-warning]: unknown ROLE\r\n");
        _reset_reg_bits(NRF24REG_CONFIG, NRF24BITMASK_PWR_UP);
        return -1;
    }
	
    send_activate_command(); // it doesn't work?

	set_address_width5();//設置地址位寬

	enable_dpl();
	
	for (i=0; i<6; i++)
	{
		if ((cfg.selchx >> i) & 0x01)
		{
			enable_chx_ackpayload(i);//允許pipe:0--5自動應答和接收數據
			
			if (i < 2) 
			{
				rt_strncpy(&cfg.sendaddr[0], cfg.ch0t1revaddr[i], 5);
			}
			else 
			{
				rt_strncpy(&cfg.sendaddr[0], cfg.ch2t5revaddr[i-2], 1);
				rt_strncpy(&cfg.sendaddr[1], cfg.ch0t1revaddr[1], 4);
			}
			set_tx_address5(&cfg.sendaddr[0]);//設置發送地址
			
			set_chx_rx_address5(i,(i<2? cfg.ch0t1revaddr[i]:cfg.ch2t5revaddr[i-2]));//設置pipe0--5接收節點地址
			if (cfg.role == ROLE_PTX)
			{
				//發送模式下需要將pipe0地址設置爲TX_ADDR,因爲發送模式下pipe0是用於接收應答信號的,否則會收不到應答信號而發送失敗
				set_chx_rx_address5(0, &cfg.sendaddr[0]);
			}
			
			set_chx_rx_pw(i,32);//設置pipe:0-5有效數據寬度
		}
	}
	
    set_rf_power     (cfg.power);   //功率配置
    set_rf_channel   (cfg.channel); //頻率配置
    set_air_data_rate(cfg.adr);     //速率配置
    set_crc          (cfg.crc);     //CRC配置
    set_esb_param    (&cfg.esb);    //自動重發配置

    if (cfg.use_irq) //enable all irq
	{	
        enabled_irq(NRF24BITMASK_RX_DR | NRF24BITMASK_TX_DS | NRF24BITMASK_MAX_RT);
    }
    else  //disable all irq
	{
        disable_irq(NRF24BITMASK_RX_DR | NRF24BITMASK_TX_DS | NRF24BITMASK_MAX_RT);
    }

    flush_rx_fifo();//清空接收FIFO
    flush_tx_fifo();//清空發送FIFO

    reset_status(NRF24BITMASK_RX_DR | NRF24BITMASK_TX_DS | NRF24BITMASK_MAX_RT);//清空中斷標誌
    reset_observe_tx();//開啓發送監測功能,數據包丟失計數、重發計數

    if (cfg.role == ROLE_PTX)
    {
        _set_reg_bits(NRF24REG_CONFIG, NRF24BITMASK_PWR_UP);
        _reset_reg_bits(NRF24REG_CONFIG, NRF24BITMASK_PRIM_RX);
    }
    else if (cfg.role == ROLE_PRX)
    {
        _set_reg_bits(NRF24REG_CONFIG, NRF24BITMASK_PWR_UP);
        _set_reg_bits(NRF24REG_CONFIG, NRF24BITMASK_PRIM_RX);
		rt_pin_write(pin_ce, PIN_HIGH);
    }
    else
    {
        // never run to here
        ;
    }

	spi_wire_nrf24l01.nrf24l01.cfg	   = cfg;
	spi_wire_nrf24l01.nrf24l01.pin_ce  = pin_ce;
	spi_wire_nrf24l01.nrf24l01.pin_irq = pin_irq;
	
	return RT_EOK;
}

修改nrf24l01_prx_cycle

int nrf24l01_prx_cycle(uint8_t *pb_rx, const uint8_t *pb_tx, uint8_t tlen, uint8_t *rx_chnum)
{
    uint8_t chnum = 0, sta, rlen = 0;

    sta = _read_reg(NRF24REG_FIFO_STATUS);
    if (!(sta & NRF24BITMASK_RX_EMPTY))
    {
		sta = _read_reg(NRF24REG_STATUS);//讀狀態寄存器,必須在read_rxpayload前,否則狀態寄存器會被清空
		chnum = (sta >> 1) & 0x07;//獲取通道號
		*rx_chnum = chnum;//接收通道號
		
        rlen = get_top_rxfifo_width();
        read_rxpayload(pb_rx, rlen);
        // flush_rx_fifo();
        if ((tlen > 0) && (tlen <= 32))
        {
			write_ack_payload(chnum, pb_tx, tlen);		
        }
    }
	
    return rlen;
}

配置示例

接收端:

	nrf24l01_default_param(&nrf24l01_cfg);
	nrf24l01_cfg.role = ROLE_PRX;
	nrf24l01_cfg.selchx = 0X3F;//使能所以通道。pipe0:0x01, pipe1:0x02, pipe2:0x04, pipe3:0x08, pipe4:0x10, pipe5:0x20
	nrf24l01_cfg.use_irq = 1;
	nrf24l01_dev->nrf24l01.ops->nrf_init(nrf24l01_cfg, NRF24L01_CE_PIN, NRF24L01_IRQ_PIN);

發送端:

	nrf24l01_default_param(&nrf24l01_cfg);
	nrf24l01_cfg.role = ROLE_PTX;
	nrf24l01_cfg.selchx = 0X03;//使能pipe1。pipe0:0x01, pipe1:0x02, pipe2:0x04, pipe3:0x08, pipe4:0x10, pipe5:0x20
	nrf24l01_cfg.use_irq = 1;
	nrf24l01_dev->nrf24l01.ops->nrf_init(nrf24l01_cfg, NRF24L01_CE_PIN, NRF24L01_IRQ_PIN);

nrf24l01使用注意事項

  • nrf24l01組網方式
    如果使用的是第二種方式,每個發送端都使用pipe0與接收端通信,也就是教程工程中所使用的方法,那麼直接使用教程的工程就可以順風順水了。但如果使用的第一種,發送端使用與接收端相同的pipe進行通信,那你就準備好爬坑吧。
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-6PnJrVDt-1574685658042)(B03E8D86575C403681BBBB0D74191C48)]

  • 地址設置:pipe0與pipe1的RX_ADDR爲5Bytes可設,需要寫入5字節地址;pipe2-pipe5的RX_ADDR只有低位地址1Byte可設,只能寫入1字節地址,且剩餘4字節需與pipe1高4字節地址一致。不允許不同的數據通道設置完全相同的地址。TX_ADDR爲5Bytes可設,必須寫入5字節地址。
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Rw2FevS8-1574685658042)(F7834A3117DB431E93FCD9B16DDB9FF0)]

  • 發送端地址設置:如果使能了自動應答模式,nRF24L01接收端在確認收到數據後記錄發送端地址,並以此地址爲目標地址發送應答信號。在發送端,pipe0被用做接收應答信號,因此,pipe0的接收地址要與發送端地址相等以確保接收到正確的應答信號
    比如:在發送端使用pipe3與接收端通信,則發送端的TX_ADDR = RX_ADDR_P3 = RX_ADDR_P0

  • 通道選擇:在接收端一般是開啓所以通道,所以不會遇到這個問題。但如果是隻開啓其中的某個通道,則該通道前面的通道也必須開啓,具體原因我也不知道。比如:開啓pipe2,則pipe0和pipe1也必須開啓。

  • 接收端通道號獲取:如果想在接收端獲取當前通信的發送端通道號,可通過讀取STATUS寄存器的RX_P_NO位來獲取
    [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2FN0dDUf-1574685658042)(C57590414FF543B1A4985DE68342D9AA)]

但是必須還讀取RX FIFO前面獲取,否則獲取的RX_P_NO會是’111’,原因在於

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MG7o0jcs-1574685658043)(9953F54AD71747C7B5113297F4F8F99E)]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章