prettyprint

2023年8月6日 星期日

[Raspberry Pi Pico] nRF24L01+ Ep. 2 : Various types of network topologies

 本文章介紹nRF24L01(+)除了標準的Multiceiver的網路應用外,另外實作

  1. One PTX and multi PRX. 
  2. One PTX broadcast to multi PRX
  3. PTX & PRX role exchange: packet transmission of ring or ping-pong type。
nRF24L01簡介與驅動程式,請參閱前篇文章說明。 
  • 成果影片:



一、Multiceiver:

multiceiver.c
 #include <stdio.h>
#include "pico/stdlib.h"
#include "nRF24L01.h"
#include "string.h"

//#define RECV_NODE   // define for PRX

uint8_t transnode=1;  //PTX node 0 ~ 5

uint8_t role;
uint8_t can_send=false;
uint8_t send_buffer[33];

uint8_t addr[6][5] = {"0node", "1node", "2node","3node","4node","5node"};

uint8_t send_buffer[33];
uint32_t cnt=0;

void irq_callback(uint8_t event_type, uint8_t datapipe, uint8_t* data, uint8_t width) {
    static uint32_t ack_payload=0;
    uint8_t ack_buff[15];
      switch(event_type) {
        case EVENT_RX_DR:
                data[width]='\0';
                printf("RECV== pipe:%d, width:%d, %s\n", datapipe, width, data);
                gpio_put(datapipe*2, !gpio_get(datapipe*2));
        break;
        case EVENT_TX_DS:
            can_send=true;
            printf("event_data_sent:%d\n", datapipe);
        break;
        case EVENT_MAX_RT:
        //nRF24_flush_tx();
        //can_send=true;
        busy_wait_ms(2);
        printf("event_max_rt:%d, can_sent:%d\n", datapipe, can_send);
        break;
    }
}



void keydown() {
    if (gpio_get_irq_event_mask(15) == GPIO_IRQ_EDGE_RISE) {
        gpio_acknowledge_irq(15, GPIO_IRQ_EDGE_RISE);
        gpio_set_irq_enabled(15, GPIO_IRQ_EDGE_RISE, false);
        
        nRF24_write_payload(send_buffer,strlen(send_buffer));
        sprintf(send_buffer, "keydown");
        busy_wait_ms(100);
        can_send=true;
        
        //gpio_set_irq_enabled(gpio, event_mask, true);
        printf("keydown:%s\n",send_buffer);
        gpio_set_irq_enabled(15,GPIO_IRQ_EDGE_RISE, true);
    }
    //gpio_set_irq_enabled(gpio,GPIO_IRQ_EDGE_FALL, true);
    

}

int main()
{
    stdio_init_all();
    sleep_ms(2000);
    gpio_init(2);
    gpio_init(4);
    gpio_init(6);

    gpio_set_dir(2, true);
    gpio_set_dir(4, true);
    gpio_set_dir(6, true);

    uint8_t status;
    nRF24_spi_default_init(20, 21, irq_callback);
    //nRF24_set_RF_channel(0x1F);
    #ifdef RECV_NODE
        role=RECEIVER;
    #else   
        role = TRANSMITTER;
    #endif
    nRF24_config_mode(role);

    nRF24_enable_feature(FEATURE_EN_DPL, true);
    //nRF24_enable_feature(FEATURE_EN_ACK_PAY, true);
    //nRF24_enable_feature(FEATURE_EN_DYN_ACK, true);
#ifdef RECV_NODE
    nRF24_enable_RXADDR(0b00001111);
    nRF24_set_RX_addr(0, addr[0], 5);
    nRF24_set_RX_addr(1, addr[1], 5);
    nRF24_set_RX_addr(2, addr[2], 5);
    nRF24_set_RX_addr(3, addr[3], 5);

    nRF24_enable_data_pipe_dynamic_payload_length(0, true);
    nRF24_enable_data_pipe_dynamic_payload_length(1, true);
    nRF24_enable_data_pipe_dynamic_payload_length(2, true);
    nRF24_enable_data_pipe_dynamic_payload_length(3, true);
#else
    nRF24_set_TX_addr(addr[transnode], 5);
    nRF24_set_RX_addr(0, addr[transnode], 5);
    nRF24_enable_data_pipe_dynamic_payload_length(0, true);

    gpio_pull_down(15);
    gpio_add_raw_irq_handler(15, keydown);
    gpio_set_irq_enabled(15, GPIO_IRQ_EDGE_RISE, true);
    
#endif

    can_send=false;
     while(1) {
#ifndef RECV_NODE

if (can_send) {
    can_send=false;

    nRF24_write_payload(send_buffer, strlen(send_buffer));


}
#endif

      tight_loop_contents();
        
    }

    return 0;
}
CMakeLists.txt
 # Generated Cmake Pico project file

cmake_minimum_required(VERSION 3.13)

set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)

# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
set(PICO_SDK_PATH "/home/duser/pico/pico-sdk")

set(PICO_BOARD pico CACHE STRING "Board type")

# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)

if (PICO_SDK_VERSION_STRING VERSION_LESS "1.4.0")
  message(FATAL_ERROR "Raspberry Pi Pico SDK version 1.4.0 (or later) required. Your version is ${PICO_SDK_VERSION_STRING}")
endif()

project(nRF24L01 C CXX ASM)

# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()

# Add executable. Default name is the project name, version 0.1

add_executable(nRF24L01 multiceive.c )

pico_set_program_name(nRF24L01 "nRF24L01")
pico_set_program_version(nRF24L01 "0.1")

pico_enable_stdio_uart(nRF24L01 0)
pico_enable_stdio_usb(nRF24L01 1)

# Add the standard library to the build
target_link_libraries(nRF24L01
        pico_stdlib)

# Add the standard include files to the build
target_include_directories(nRF24L01 PRIVATE
  ${CMAKE_CURRENT_LIST_DIR}
  ${CMAKE_CURRENT_LIST_DIR}/.. # for our common lwipopts or any other standard includes, if required
)

# Add any user requested libraries
target_link_libraries(nRF24L01 
        hardware_spi
        )

add_subdirectory(nRF24L01)
target_link_libraries(nRF24L01
        nRF24L01_drv)
pico_add_extra_outputs(nRF24L01)
二、One PTX and multi PRX
1_T_n_R.c
 #include <stdio.h>
#include "pico/stdlib.h"
#include "nRF24L01.h"
#include "string.h"

#define SENDER  // define for one PTX

uint8_t node_id=2;  // define for PRX node 0~5

uint8_t role;
uint8_t can_send=false;
uint8_t send_buffer[33];

uint8_t addr[5][5] = {"0node", "1node", "2node","3node","4node", "5node"};


void irq_callback(uint8_t event_type, uint8_t datapipe, uint8_t* data, uint8_t width) {
    static uint32_t ack_payload=0;
    uint8_t ack_buff[15];
      switch(event_type) {
        case EVENT_RX_DR:
            data[width]='\0';
            printf("RECV== pipe:%d, width:%d, %s\n", datapipe, width, data);
            gpio_put(2, !gpio_get(2));
        break;
        case EVENT_TX_DS:
        //can_send=true;
            printf("event_data_sent:%d\n", datapipe);
        break;
        case EVENT_MAX_RT:
        //nRF24_flush_tx();
        //can_send=true;
        printf("event_max_rt:%d, can_sent:%d\n", datapipe, can_send);
        break;
    }
}



void keydown() {
    uint8_t irq_pin=0;
    
    if (gpio_get_irq_event_mask(13) == GPIO_IRQ_EDGE_RISE) {
        irq_pin=13;
        nRF24_set_TX_addr(addr[0],5);
        nRF24_set_RX_addr(0, addr[0],5);
    }
    if (gpio_get_irq_event_mask(14) == GPIO_IRQ_EDGE_RISE) {
        irq_pin=14;
        nRF24_set_TX_addr(addr[1],5);
        nRF24_set_RX_addr(0, addr[1],5);
    }
    if (gpio_get_irq_event_mask(15) == GPIO_IRQ_EDGE_RISE) {
        irq_pin=15;
        nRF24_set_TX_addr(addr[2],5);
        nRF24_set_RX_addr(0, addr[2],5);
    }
    if (irq_pin == 13 || irq_pin==14 || irq_pin==15) {
        gpio_acknowledge_irq(irq_pin, GPIO_IRQ_EDGE_RISE);
        gpio_set_irq_enabled(irq_pin,GPIO_IRQ_EDGE_RISE, false);
        nRF24_write_payload(send_buffer,strlen(send_buffer));
        sprintf(send_buffer, "keydown");
        busy_wait_ms(100);
        can_send=true;

        printf("keydown:%s\n",send_buffer);
        gpio_set_irq_enabled(irq_pin,GPIO_IRQ_EDGE_RISE, true);
    }
    

}

int main()
{
    stdio_init_all();
    sleep_ms(2000);
    gpio_init(2);
    gpio_init(4);
    gpio_init(6);

    gpio_set_dir(2, true);
    gpio_set_dir(4, true);
    gpio_set_dir(6, true);

    uint8_t status;
    nRF24_spi_default_init(20, 21, irq_callback);

    //nRF24_set_RF_channel(0x1F);

    #ifdef SENDER
        role = TRANSMITTER;
    #else   
        role=RECEIVER;
    #endif
    nRF24_config_mode(role);

    nRF24_enable_feature(FEATURE_EN_DPL, true);
    //nRF24_enable_feature(FEATURE_EN_ACK_PAY, true);
    //nRF24_enable_feature(FEATURE_EN_DYN_ACK, true);
#ifdef SENDER
    nRF24_enable_data_pipe_dynamic_payload_length(0, true);
    gpio_pull_down(13);
    gpio_add_raw_irq_handler(13, keydown);
    gpio_set_irq_enabled(13, GPIO_IRQ_EDGE_RISE, true);
    
    gpio_pull_down(14);
    gpio_set_irq_enabled(14, GPIO_IRQ_EDGE_RISE, true);
    gpio_pull_down(15); 
    gpio_set_irq_enabled(15, GPIO_IRQ_EDGE_RISE, true);


#else
    nRF24_set_RX_addr(0, addr[node_id], 5);
    nRF24_enable_data_pipe_dynamic_payload_length(0, true);
    
#endif
   
    can_send=true;
    while(1) {
#ifndef RECV_NODE

//if (can_send) {
//    can_send=false;
//    printf("send\n");
 // nRF24_write_payload("keydown",7);
  
////   sleep_ms(500);
//}
#endif
      tight_loop_contents();
        
    }

    return 0;
}

三、Broadcast:

broadcast.c
 #include <stdio.h>
#include "pico/stdlib.h"
#include "nRF24L01.h"
#include "string.h"

//#define BROADCASTER  // define if BROADCASTER (PTX)

#define LED_PIN 2

uint8_t addr[5][5] = {"0ode1", "1node", "2node", "3node", "4node"};

uint8_t send_buffer[33];

void irq_callback(uint8_t event_type, uint8_t datapipe, uint8_t* data, uint8_t width) 
      switch(event_type) {
        case EVENT_RX_DR:
            gpio_put(LED_PIN, !gpio_get(LED_PIN));
            data[width]='\0';
            printf("RECV== pipe:%d, width:%d, %s\n", datapipe, width, data);
        break;
        case EVENT_TX_DS:
            printf("event_data_sent:%d\n", datapipe);
        break;
        case EVENT_MAX_RT:
            //nRF24_flush_tx();
            //can_send=true;
            printf("event_max_rt:%d\n", datapipe);
        break;
    }
}

void keydown() {
    if (gpio_get_irq_event_mask(15) == GPIO_IRQ_EDGE_RISE) {
        gpio_acknowledge_irq(15, GPIO_IRQ_EDGE_RISE);
        gpio_set_irq_enabled(15, GPIO_IRQ_EDGE_RISE, false);
        
        nRF24_write_payload(send_buffer,strlen(send_buffer));
        sprintf(send_buffer, "keydown");
        busy_wait_ms(100);
        //can_send=true;

        printf("keydown:%s\n",send_buffer);
        gpio_set_irq_enabled(15,GPIO_IRQ_EDGE_RISE, true);
    }
  

}

int main()
{
    stdio_init_all();
    sleep_ms(2000);
    
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, true);
    nRF24_spi_default_init(20, 21, irq_callback);

    nRF24_enable_feature(FEATURE_EN_DPL, true);
    //nRF24_enable_feature(FEATURE_EN_ACK_PAY, true);
#ifdef BROADCASTER
    nRF24_config_mode(TRANSMITTER);
    nRF24_enable_feature(FEATURE_EN_DYN_ACK, true);
    nRF24_set_TX_addr(addr[0], 5);

    gpio_pull_down(15);
    gpio_add_raw_irq_handler(15, keydown);
    gpio_set_irq_enabled(15, GPIO_IRQ_EDGE_RISE, true);
    
#else   
    nRF24_config_mode(RECEIVER);
#endif
    nRF24_set_RX_addr(0, addr[0], 5);
    nRF24_enable_data_pipe_dynamic_payload_length(0, true);

    uint32_t dc=0;
    uint8_t send_buffer[32];
    uint32_t count=0;
    
    while(1) {
      
#ifdef BROADCASTER
        //sprintf(send_buffer, "broadcast:%d", count++);
        //count %=10000;
        //nRF24_write_payload_no_ack(send_buffer,strlen(send_buffer));     
#endif
       
        sleep_ms(500);

    }

    return 0;
}

四、PTX & PRX role swap: ping-pong mode


 #include <stdio.h>
#include "pico/stdlib.h"
#include "nRF24L01.h"
#include "string.h"

#define LED_PIN 2

#define NODE_A

uint8_t addr_a[2][5] = {"1a---", "2a---"};
uint8_t addr_b[2][5] = {"1b---", "2b---"};
bool can_send=true;
uint8_t role, new_role;

void irq_callback(uint8_t event_type, uint8_t datapipe, uint8_t* data, uint8_t width) {

      switch(event_type) {
        case EVENT_RX_DR:
            data[width]='\0';
            printf("RECV== pipe:%d, width:%d, %s\n", datapipe, width, data);
            gpio_put(LED_PIN, true);
            can_send=true;
            new_role = TRANSMITTER;
        break;
        case EVENT_TX_DS:
        puts("TX_DS");
            new_role=RECEIVER;
            gpio_put(LED_PIN, false);
            can_send=false;
        break;
        case EVENT_MAX_RT:
        //nRF24_flush_tx();
        //can_send=true;
        //printf("event_max_rt:%d, can_sent:%d\n", datapipe, can_send);
        break;
    }
}




int main()
{
    stdio_init_all();
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, true);

    uint8_t status;
    nRF24_spi_default_init(20, 21, irq_callback);
    #ifdef NODE_A
    role=TRANSMITTER;
    new_role=TRANSMITTER;
    nRF24_config_mode(TRANSMITTER);
    can_send=true;

    nRF24_set_TX_addr(addr_b[0], 5);
    nRF24_set_RX_addr(0, addr_b[0], 5);
    nRF24_set_RX_addr(1, addr_a[0], 5);
    #else
    role = RECEIVER;
    new_role = RECEIVER;
    nRF24_config_mode(RECEIVER);
    can_send=false;

    nRF24_set_TX_addr(addr_a[0], 5);
    nRF24_set_RX_addr(0, addr_a[0], 5);
    nRF24_set_RX_addr(1, addr_b[0], 5);
    #endif

    nRF24_enable_feature(FEATURE_EN_DPL, true);
 
    uint32_t count=0;
    uint8_t send_buff[32];
  
    nRF24_enable_data_pipe_dynamic_payload_length(0, true);
    nRF24_enable_data_pipe_dynamic_payload_length(1, true);
   
    uint32_t dc=0;
    while(1) {
        if (role != new_role) {
            role = new_role;
            nRF24_config_mode(role);
        }
        if (can_send && role==TRANSMITTER) {
            can_send=false;
            sprintf(send_buff, "0:abcdefgh%d", count++);
            count %=10000;
            nRF24_write_payload(send_buff,strlen(send_buff)); 
        }
    
        sleep_ms(500);
    }

    return 0;
}

五、PTX & PRX role swap: ring mode


 #include <stdio.h>
#include "pico/stdlib.h"
#include "nRF24L01.h"
#include "string.h"

#define LED_PIN 2
uint8_t node_id=3;  // node id: 0~5 for each node
uint8_t total_nodes=4; // total nodes in the ring 
uint8_t addr[6][5] = {"0node","1node", "2node", "3node", "4node", "5node"};
bool can_send=false;
uint8_t role, new_role;

void irq_callback(uint8_t event_type, uint8_t datapipe, uint8_t* data, uint8_t width) {
    static uint32_t ack_payload=0;
    uint8_t ack_buff[15];
      switch(event_type) {
        case EVENT_RX_DR:
            gpio_put(LED_PIN, true);
            data[width]='\0';
            printf("RECV== pipe:%d, width:%d, %s\n", datapipe, width, data);
            can_send=true;
            new_role = TRANSMITTER;
        break;
        case EVENT_TX_DS:
        puts("TX_DS");
            new_role=RECEIVER;
            gpio_put(LED_PIN, false);
            can_send=false;
        break;
        case EVENT_MAX_RT:
        //nRF24_flush_tx();
        //can_send=true;
        //printf("event_max_rt:%d, can_sent:%d\n", datapipe, can_send);
        break;
    }
}




int main()
{
    stdio_init_all();
    
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, true);

    uint8_t status;
    nRF24_spi_default_init(20, 21, irq_callback);
    if (node_id==0) { 
    role=TRANSMITTER;
    new_role=TRANSMITTER;
    nRF24_config_mode(TRANSMITTER);
    can_send=true;

    nRF24_set_TX_addr(addr[1], 5);
    nRF24_set_RX_addr(0, addr[1], 5);
    nRF24_set_RX_addr(1, addr[0], 5);
    } else {
        role = RECEIVER;
        new_role = RECEIVER;
        nRF24_config_mode(RECEIVER);
        can_send=false;
        nRF24_set_TX_addr(addr[(node_id+1)%total_nodes], 5);
        nRF24_set_RX_addr(0, addr[(node_id+1)%total_nodes], 5);
        nRF24_set_RX_addr(1, addr[node_id], 5);
    }

    nRF24_enable_feature(FEATURE_EN_DPL, true);
 
    uint32_t count=0;
    uint8_t send_buff[32];
  
    nRF24_enable_data_pipe_dynamic_payload_length(0, true);
    nRF24_enable_data_pipe_dynamic_payload_length(1, true);
   
    uint32_t dc=0;
    while(1) {
        if (role != new_role) {
            role = new_role;
            nRF24_config_mode(role);
        }
        if (can_send && role==TRANSMITTER) {
            can_send=false;
            sprintf(send_buff, "0:abcdefgh%d", count++);
            count %=10000;
            nRF24_write_payload(send_buff,strlen(send_buff)); 
        }
    
        sleep_ms(500);
    }

    return 0;
}

沒有留言:

張貼留言