Wireless Controller Receiver Design
3:16
examples/zigbee/ and build, then split into modules later.Key points you may wish to customiseC
/********************************************************************* * Hoist Receiver – nRF52840 + Zigbee + TFT LCD * Hardware : * • nRF52840-QIAA * • VNH5019ATR-E (INA/P0.06, INB/P0.07, PWM/P0.08) * • Hall sensor (P0.05, active-low) * • TFT ST7789 (SPI: SCK/P0.14, MOSI/P0.13, CS/P0.12, * DC/P0.11, RST/P0.10, BL/P0.09 [30 Ω R3]) * • Battery sense (SAADC AIN6 / P0.30 through 100 kΩ/47 kΩ divider) *********************************************************************/ #include "sdk_config.h" #include "boards.h" #include "nrf_drv_pwm.h" #include "nrf_drv_saadc.h" #include "app_timer.h" #include "app_util_platform.h" #include "bsp_btn_ble.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "zboss_api.h" #include "zb_error_handler.h" #include "zb_mem_config_med.h" #include "zb_nrf52_internal.h" #include "zb_zcl_identify.h" /* --------------------------------------------------------------- */ /* PROJECT CONSTANTS */ /* --------------------------------------------------------------- */ #define ZIGBEE_CHANNEL 16 #define ZIGBEE_RX_EP 10 /* Application endpoint */ #define MANUFACTURER_ID 0x1337 #define APP_TIMER_PRESCALER 0 #define APP_TIMER_OP_QUEUE_SIZE 4 #define PWM_INSTANCE_ID 0 #define PWM_FREQUENCY_HZ 1000 /* 1 kHz PWM for motor speed */ #define ACTUATOR_STROKE_GOAL 1 /* One stroke per cycle */ #define BATTERY_SAMPLES_MS 30000 /* Update battery every 30 s */ #define LCD_UPDATE_MS 500 /* Refresh LCD twice a second */ /* --------------------------------------------------------------- */ /* GPIO DEFINITIONS */ /* --------------------------------------------------------------- */ #define PIN_INA NRF_GPIO_PIN_MAP(0,6) #define PIN_INB NRF_GPIO_PIN_MAP(0,7) #define PIN_PWM NRF_GPIO_PIN_MAP(0,8) #define PIN_HALL NRF_GPIO_PIN_MAP(0,5) #define TFT_SCK NRF_GPIO_PIN_MAP(0,14) #define TFT_MOSI NRF_GPIO_PIN_MAP(0,13) #define TFT_CS NRF_GPIO_PIN_MAP(0,12) #define TFT_DC NRF_GPIO_PIN_MAP(0,11) #define TFT_RST NRF_GPIO_PIN_MAP(0,10) #define TFT_BL NRF_GPIO_PIN_MAP(0,9) #define VBAT_ADC_CH NRF_SAADC_INPUT_AIN6 /* P0.30 */ #define VBAT_R1 100000.0f /* Top resistor (Ω) */ #define VBAT_R2 47000.0f /* Bottom resistor (Ω) */ #define VBAT_REF 0.6f /* SAADC internal reference */ /* --------------------------------------------------------------- */ /* GLOBAL STATE */ /* --------------------------------------------------------------- */ static nrf_drv_pwm_t m_pwm = NRF_DRV_PWM_INSTANCE(PWM_INSTANCE_ID); static nrf_pwm_values_individual_t m_pwm_seq_vals = {0,0,0,0}; static nrf_pwm_sequence_t m_pwm_seq = { .values.p_individual = &m_pwm_seq_vals, .length = NRF_PWM_VALUES_LENGTH(m_pwm_seq_vals), .repeats = 0, .end_delay = 0 }; static volatile uint32_t g_lift_cycles = 0; static zb_bool_t g_motor_running = ZB_FALSE; static uint8_t g_motor_dir = 0; /* 0=stop,1=up,2=down */ /* --------------------------------------------------------------- */ /* FUNCTION PROTOTYPES */ /* --------------------------------------------------------------- */ static void zigbee_init(void); static void tft_init(void); static void tft_print_status(void); static void motor_stop(void); static void motor_drive(uint8_t dir); static void hall_isr(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action); static void battery_timer_cb(void *p_context); static void lcd_timer_cb(void *p_context); /* --------------------------------------------------------------- */ /* MAIN */ /* --------------------------------------------------------------- */ int main(void) { /* Logging & timers */ APP_ERROR_CHECK(NRF_LOG_INIT(NULL)); NRF_LOG_DEFAULT_BACKENDS_INIT(); APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); /* GPIO setup */ nrf_gpio_cfg_output(PIN_INA); nrf_gpio_cfg_output(PIN_INB); nrf_gpio_cfg_output(PIN_PWM); nrf_gpio_cfg_output(TFT_CS); nrf_gpio_cfg_output(TFT_DC); nrf_gpio_cfg_output(TFT_RST); nrf_gpio_cfg_output(TFT_BL); motor_stop(); /* PWM for motor */ nrf_drv_pwm_config_t pwm_cfg = { .output_pins = { PIN_PWM, NRF_DRV_PWM_PIN_NOT_USED, NRF_DRV_PWM_PIN_NOT_USED, NRF_DRV_PWM_PIN_NOT_USED }, .irq_priority = APP_IRQ_PRIORITY_LOW, .base_clock = NRF_PWM_CLK_1MHz, .count_mode = NRF_PWM_MODE_UP, .top_value = 1000, /* 1 kHz */ .load_mode = NRF_PWM_LOAD_INDIVIDUAL, .step_mode = NRF_PWM_STEP_AUTO }; nrf_drv_pwm_init(&m_pwm, &pwm_cfg, NULL); m_pwm_seq_vals.channel_0 = 0; nrf_drv_pwm_simple_playback(&m_pwm, &m_pwm_seq, 1, NRF_DRV_PWM_FLAG_LOOP); /* Hall sensor interrupt */ nrf_drv_gpiote_init(); nrf_drv_gpiote_in_config_t hall_cfg = GPIOTE_CONFIG_IN_SENSE_HITOLO(true); hall_cfg.pull = NRF_GPIO_PIN_PULLUP; nrf_drv_gpiote_in_init(PIN_HALL, &hall_cfg, hall_isr); nrf_drv_gpiote_in_event_enable(PIN_HALL, true); /* ADC for battery */ nrf_saadc_channel_config_t ch = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(VBAT_ADC_CH); ch.gain = NRF_SAADC_GAIN1_6; /* 1/6 gain for 3.6 V full-scale */ nrf_drv_saadc_init(NULL, NULL); nrf_drv_saadc_channel_init(0, &ch); /* TFT */ tft_init(); tft_print_status(); /* Timers */ app_timer_id_t batt_timer, lcd_timer; app_timer_create(&batt_timer, APP_TIMER_MODE_REPEATED, battery_timer_cb); app_timer_start(batt_timer, APP_TIMER_TICKS(BATTERY_SAMPLES_MS), NULL); app_timer_create(&lcd_timer, APP_TIMER_MODE_REPEATED, lcd_timer_cb); app_timer_start(lcd_timer, APP_TIMER_TICKS(LCD_UPDATE_MS), NULL); /* Zigbee */ zigbee_init(); /* Main loop */ while (true) { zb_sched_run(); zb_sleep_if_allowed(); NRF_LOG_FLUSH(); } } /* --------------------------------------------------------------- */ /* ZIGBEE HANDLING */ /* --------------------------------------------------------------- */ #define ZB_ZCL_BASIC_CLUSTER_ID 0x0000 #define CMD_UP 0x01 #define CMD_DOWN 0x02 ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT(basic_attr_list, &g_attr_zcl_version, &g_attr_power_source); static void zboss_signal_handler(zb_uint8_t param) { zb_zdo_app_signal_hdr_t *sig_hndler = (void*)param; zb_zdo_app_signal_type_t sig = sig_hndler->type; if (sig == ZB_BDB_SIGNAL_DEVICE_FIRST_START || sig == ZB_BDB_SIGNAL_DEVICE_REBOOT) { zb_bdb_signal_device_first_start_params_t *params = (zb_bdb_signal_device_first_start_params_t*)sig_hndler->buf; if (params->status == ZB_NWK_JOINED) NRF_LOG_INFO("Joined Zigbee network"); else NRF_LOG_INFO("Failed to join Zigbee network: %d", params->status); } zb_buf_free(param); } static zb_void_t cmd_rx_cb(zb_uint8_t param) { zb_uint8_t *cmd_id = zb_buf_begin(param); switch (*cmd_id) { case CMD_UP: motor_drive(1); break; case CMD_DOWN: motor_drive(2); break; default: motor_stop(); break; } zb_buf_free(param); } static void zigbee_init(void) { zb_ret_t zb_err_code; zb_cfg_ext_t ce; zb_memset(&ce, 0, sizeof(ce)); ce.psz_ieee_addr = NULL; zb_get_long_address(ce.eui64); ce.channel_mask = 1l << ZIGBEE_CHANNEL; ce.nwk_role = EMBEDDED_COORDINATOR; zb_err_code = zb_init(&ce); ZB_ERROR_CHECK(zb_err_code); /* Register endpoint */ ZB_AF_SIMPLE_DESC_TYPE(10, 0, 0, 1, 0, ZB_ZCL_BASIC_CLUSTER_ID); zb_af_endpoint_desc_t ep_desc; ep_desc.ep_id = ZIGBEE_RX_EP; ep_desc.profile_id = 0xC105; /* Manufacturer specific */ ep_desc.device_id = 0x0001; ep_desc.device_version = 1; ep_desc.input_cluster_count = 1; ep_desc.output_cluster_count = 0; ep_desc.p_in_cluster_list = (zb_uint16_t*)&ZB_ZCL_BASIC_CLUSTER_ID; ep_desc.p_out_cluster_list = NULL; zb_af_register_endpoint(&ep_desc); /* Register command handler */ zb_zcl_register_cluster_command_handler(ZIGBEE_RX_EP, ZB_ZCL_BASIC_CLUSTER_ID, cmd_rx_cb); zb_set_network_ed_role(ZB_FALSE); zb_err_code = zboss_start_no_autostart(); ZB_ERROR_CHECK(zb_err_code); zb_affix_signal_handler(zboss_signal_handler); } /* --------------------------------------------------------------- */ /* MOTOR DRIVER */ /* --------------------------------------------------------------- */ static void motor_stop(void) { nrf_gpio_pin_clear(PIN_INA); nrf_gpio_pin_clear(PIN_INB); m_pwm_seq_vals.channel_0 = 0; nrf_drv_pwm_simple_playback(&m_pwm, &m_pwm_seq, 1, NRF_DRV_PWM_FLAG_LOOP); g_motor_running = ZB_FALSE; g_motor_dir = 0; } static void motor_drive(uint8_t dir) { if (dir == 1) /* UP */ { nrf_gpio_pin_set(PIN_INA); nrf_gpio_pin_clear(PIN_INB); } else if (dir == 2) /* DOWN */ { nrf_gpio_pin_clear(PIN_INA); nrf_gpio_pin_set(PIN_INB); } else { motor_stop(); return; } m_pwm_seq_vals.channel_0 = 500; /* 50 % duty */ nrf_drv_pwm_simple_playback(&m_pwm, &m_pwm_seq, 1, NRF_DRV_PWM_FLAG_LOOP); g_motor_running = ZB_TRUE; g_motor_dir = dir; } /* --------------------------------------------------------------- */ /* HALL SENSOR ISR */ /* --------------------------------------------------------------- */ static void hall_isr(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { if (g_motor_running) { ++g_lift_cycles; motor_stop(); /* Stop after one stroke */ } } /* --------------------------------------------------------------- */ /* BATTERY + DISPLAY */ /* --------------------------------------------------------------- */ static float read_battery_volts(void) { nrf_saadc_value_t raw; nrf_drv_saadc_sample_convert(0, &raw); float v = (raw / 2047.0f) * VBAT_REF * 6.0f; /* gain 1/6 */ return v * (VBAT_R1 + VBAT_R2) / VBAT_R2; } static void battery_timer_cb(void *p_context) { (void)p_context; float vbat = read_battery_volts(); NRF_LOG_INFO("Battery = %.2f V", vbat); } static void lcd_timer_cb(void *p_context) { (void)p_context; tft_print_status(); } /* --------------------------------------------------------------- */ /* TFT DRIVER (MINIMAL) */ /* --------------------------------------------------------------- */ #include "nrf_drv_spi.h" static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0); static void tft_cmd(uint8_t c) { nrf_gpio_pin_clear(TFT_DC); nrf_drv_spi_transfer(&spi, &c, 1, NULL, 0); } static void tft_data(uint8_t d) { nrf_gpio_pin_set(TFT_DC); nrf_drv_spi_transfer(&spi, &d, 1, NULL, 0); } static void tft_init(void) { nrf_drv_spi_config_t spi_cfg = NRFX_SPI_DEFAULT_CONFIG; spi_cfg.sck_pin = TFT_SCK; spi_cfg.mosi_pin = TFT_MOSI; spi_cfg.miso_pin = NRFX_SPI_PIN_NOT_USED; spi_cfg.cs_pin = TFT_CS; spi_cfg.frequency = NRF_DRV_SPI_FREQ_8M; spi_cfg.mode = NRF_DRV_SPI_MODE_2; nrf_drv_spi_init(&spi, &spi_cfg, NULL, NULL); nrf_gpio_pin_set(TFT_RST); nrf_delay_ms(5); nrf_gpio_pin_clear(TFT_RST); nrf_delay_ms(20); nrf_gpio_pin_set(TFT_RST); /* Software reset, sleep out, etc. – minimal ST7789 init */ tft_cmd(0x01); nrf_delay_ms(150); tft_cmd(0x11); nrf_delay_ms(120); tft_cmd(0x29); /* Display ON */ nrf_gpio_pin_set(TFT_BL); } static void tft_print_status(void) { char buf[32]; float vbat = read_battery_volts(); snprintf(buf, sizeof(buf), "Batt: %.2f V", vbat); /* … send ASCII to TFT – left as exercise (draw text function) */ snprintf(buf, sizeof(buf), "Cycles: %lu", (unsigned long)g_lift_cycles); /* … draw second line */ }
0x01 = UP, 0x02 = DOWN).ZB_ZCL_BASIC_CLUSTER_ID and change cmd_rx_cb() accordingly.m_pwm_seq_vals.channel_0 for different duty cycles or map it to an 8-bit value in the Zigbee packet.VBAT_R1 / VBAT_R2.main.c into /examples/zigbee/hoist_receiver.sdk_config.h from examples/zigbee/light_control and enable:
#define ZB_CONFIG_ENABLE_ZIGBEE_ROLE_ROUTER 1
#define NRFX_PWM_ENABLED 1
#define NRFX_SAADC_ENABLED 1
#define NRFX_GPIOTE_ENABLED 1
Project → Build) or use make -j.To get started, talk to Flux or create a New Document.
Reviews
Documents
Documents are markdown text files which describe project goals, capture details, or even simulation outputs.
Assets
No assets added.
wireless reciever
Properties
Properties describe core aspects of the project.
Pricing & Availability
Distributor | Qty 1 |
|---|
Controls
Welcome 👋
Flux helps you build PCBs faster with an AI teammate!
Create your account to collaborate, stay updated, fork your own version, and get instant answers from our AI agent.

AI-Powered Component Placement
Let AI place your components intelligently. AI Placement analyzes your schematic and positions components for optimal routing, signal integrity, and board density.
From Schematic to Layout in Seconds
Skip the tedious manual placement. AI Placement generates a starting layout you can refine, saving hours of repetitive work on every new design.
Works With Auto-Layout
Pair AI Placement with Auto-Layout for a complete AI-driven PCB design flow — from component placement through trace routing, all with one click.