CH592F 2.4G 低功耗

2.4G私有协议低功耗传输,tx按一下按键按键发送数据到rx,rx 1s内启动10ms接收窗口进行接收。

代码从github上拉取官方的代码:GitHub - openwch/ch592: The SDK and HDK for RISC-V Bluetooth LE BLE5.4 CH591/CH592 · GitHub

例程是ch592\EVT\EXAM\BLE\RF_PHY

配置开启 HAL_SLEEP

然后替换下面3个文件:

RF_PHY.h

复制代码
/********************************** (C) COPYRIGHT *******************************
 * File Name          : rf_phy.h
 * Author             : WCH
 * Version            : V1.0
 * Date               : 2018/11/12
 * Description        :
 *********************************************************************************
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * Attention: This software (modified or not) and binary are used for 
 * microcontroller manufactured by Nanjing Qinheng Microelectronics.
 *******************************************************************************/

#ifndef CENTRAL_H
#define CENTRAL_H

#ifdef __cplusplus
extern "C" {
#endif

#define SBP_RF_RX_OPEN_EVT         0x0001  // 打开RX并启动接收窗口
#define SBP_RF_RX_CLOSE_EVT        0x0002  // 关闭RX并进入低功耗等待
#define SBP_RF_RX_RESTART_EVT      0x0004  // 基本模式收包后重新启动RX
#define SBP_RF_TX_SEND_EVT         0x0008  // 发送一包TX数据
#define SBP_RF_TX_RX_DATA_EVT      0x0010  // 在TMOS任务中处理并打印应答数据
#define SBP_RF_KEY_IRQ_EVT         0x0020  // PA4下降沿中断投递事件
#define SBP_RF_KEY_CHECK_EVT       0x0040  // 延时10ms后检查按键电平
#define SBP_RF_TX_TIMEOUT_EVT      0x0080  // 连续发送3秒仍无应答则停止

#define LLE_MODE_ORIGINAL_RX       (0x80) //如果配置LLEMODE时加上此宏,则接收第一字节为原始数据(原来为RSSI)

extern void RF_Init(void);

#ifdef __cplusplus
}
#endif

#endif

RF_main.c

复制代码
/********************************** (C) COPYRIGHT *******************************
 * File Name          : main.c
 * Author             : WCH
 * Version            : V1.0
 * Date               : 2020/08/06
 * Description        :
 *********************************************************************************
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * Attention: This software (modified or not) and binary are used for 
 * microcontroller manufactured by Nanjing Qinheng Microelectronics.
 *******************************************************************************/

/******************************************************************************/
/* 头文件包含 */
#include "CONFIG.h"
#include "HAL.h"
#include "RF_PHY.h"

/*********************************************************************
 * GLOBAL TYPEDEFS
 */
__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];

#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)
const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};
#endif

/*********************************************************************
 * @fn      Main_Circulation
 *
 * @brief   主循环
 *
 * @return  none
 */
__HIGH_CODE
__attribute__((noinline))
void Main_Circulation()
{
    while(1)
    {
        TMOS_SystemProcess();
    }
}

/*********************************************************************
 * @fn      main
 *
 * @brief   主函数
 *
 * @return  none
 */
int main(void)
{
#if(defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE)
    PWR_DCDCCfg(ENABLE);
#endif
    SetSysClock(CLK_SOURCE_PLL_60MHz);
#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE)
    GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
    GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
#endif
#ifdef DEBUG
    GPIOA_SetBits(bTXD1);
    GPIOA_ModeCfg(bTXD1, GPIO_ModeOut_PP_5mA);
    UART1_DefInit();
#endif
    PRINT("start.\n");
    PRINT("%s\n", VER_LIB);
    CH59x_BLEInit();
    HAL_Init();
    RF_RoleInit();
    RF_Init();
    Main_Circulation();
}

/******************************** endfile @ main ******************************/

RF_PHY.c

复制代码
/********************************** (C) COPYRIGHT *******************************
 * File Name          : main.c
 * Author             : WCH
 * Version            : V1.0
 * Date               : 2020/08/06
 * Description        :
 *********************************************************************************
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * Attention: This software (modified or not) and binary are used for 
 * microcontroller manufactured by Nanjing Qinheng Microelectronics.
 *******************************************************************************/

/******************************************************************************/
/* 头文件包含 */
#include "CONFIG.h"
#include "RF_PHY.h"

#define RF_DEVICE_ROLE_RX       0
#define RF_DEVICE_ROLE_TX       1
#define RF_DEVICE_ROLE          RF_DEVICE_ROLE_TX

#if(RF_DEVICE_ROLE != RF_DEVICE_ROLE_RX) && \
   (RF_DEVICE_ROLE != RF_DEVICE_ROLE_TX)
#error "Invalid RF_DEVICE_ROLE"
#endif

/*********************************************************************
 * GLOBAL TYPEDEFS
 */

#define RF_AUTO_MODE_EXAM       1
#define RF_RX_PERIOD            MS1_TO_SYSTEM_TIME(1000)
#define RF_RX_WINDOW            MS1_TO_SYSTEM_TIME(10)
#define RF_KEY_DEBOUNCE_TIME     MS1_TO_SYSTEM_TIME(10)
#define RF_TX_TIMEOUT_TIME       MS1_TO_SYSTEM_TIME(3000)
#define RF_KEY_PIN               GPIO_Pin_4

typedef struct
{
    int8_t  rssi;
    uint8_t len;
    uint8_t data[251];
} rfRxPacket_t;

uint8_t taskID;
uint8_t ACK_DATA[2] = {'o', 'k'};
uint8_t TX_DATA[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};

volatile uint8_t tx_end_flag=0;
volatile uint8_t rx_end_flag=0;
static volatile uint8_t rx_window_open=FALSE;
static volatile uint8_t rx_first_packet=FALSE;
static volatile uint8_t rx_ack_status=0;
static rfRxPacket_t rx_packet;
static rfRxPacket_t tx_rx_packet;
static volatile uint8_t tx_running=FALSE;

#if(RF_DEVICE_ROLE == RF_DEVICE_ROLE_TX)
/*********************************************************************
 * @fn      HAL_KeyIrqInit
 *
 * @brief   配置PA4上拉输入、下降沿中断和睡眠唤醒
 */
void HAL_KeyIrqInit(void)
{
    GPIOA_ModeCfg(RF_KEY_PIN, GPIO_ModeIN_PU);
    GPIOA_ITModeCfg(RF_KEY_PIN, GPIO_ITMode_FallEdge);
    GPIOA_ClearITFlagBit(RF_KEY_PIN);
    PFIC_EnableIRQ(GPIO_A_IRQn);
    PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Long_Delay);
}

/*********************************************************************
 * @fn      HAL_KeyIrqGet
 *
 * @return  0-按下,非0-释放
 */
uint32_t HAL_KeyIrqGet(void)
{
    return GPIOA_ReadPortPin(RF_KEY_PIN);
}

/*********************************************************************
 * @fn      GPIOA_IRQHandler
 *
 * @brief   PA4下降沿中断,只投递事件,不在中断中消抖
 */
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void GPIOA_IRQHandler(void)
{
    uint16_t flag = R16_PA_INT_IF;

    if(flag & RF_KEY_PIN)
    {
        GPIOA_ClearITFlagBit(RF_KEY_PIN);
        tmos_set_event(taskID, SBP_RF_KEY_IRQ_EVT);
    }
}
#endif

/*********************************************************************
 * @fn      RF_Wait_Tx_End
 *
 * @brief   手动模式等待发送完成,自动模式等待发送-接收完成,必须在RAM中等待,等待时可以执行用户代码,但需要注意执行的代码必须运行在RAM中,否则影响发送
 *
 * @return  none
 */
__HIGH_CODE
__attribute__((noinline))
void RF_Wait_Tx_End()
{
    uint32_t i=0;
    while(!tx_end_flag)
    {
        i++;
        __nop();
        __nop();
        // 约5ms超时
        if(i>(FREQ_SYS/1000))
        {
            tx_end_flag = TRUE;
        }
    }
}

/*********************************************************************
 * @fn      RF_Wait_Rx_End
 *
 * @brief   自动模式等待应答发送完成,必须在RAM中等待,等待时可以执行用户代码,但需要注意执行的代码必须运行在RAM中,否则影响发送
 *
 * @return  none
 */
__HIGH_CODE
__attribute__((noinline))
void RF_Wait_Rx_End()
{
    uint32_t i=0;
    while(!rx_end_flag)
    {
        i++;
        __nop();
        __nop();
        // 约5ms超时
        if(i>(FREQ_SYS/1000))
        {
            rx_end_flag = TRUE;
        }
    }
}

/*********************************************************************
 * @fn      RF_2G4StatusCallBack
 *
 * @brief   RF 状态回调,此函数在中断中调用。注意:不可在此函数中直接调用RF接收或者发送API,需要使用事件的方式调用
 *          在此回调中直接使用或调用函数涉及到的变量需注意,此函数在中断中调用。
 *
 * @param   sta     - 状态类型
 * @param   crc     - crc校验结果
 * @param   rxBuf   - 数据buf指针
 *
 * @return  none
 */
void RF_2G4StatusCallBack(uint8_t sta, uint8_t crc, uint8_t *rxBuf)
{
    switch(sta)
    {
        case TX_MODE_TX_FINISH:
        {
#if(!RF_AUTO_MODE_EXAM)
            tx_end_flag = TRUE;
#endif
            break;
        }
        case TX_MODE_TX_FAIL:
        {
            tx_end_flag = TRUE;
#if(RF_DEVICE_ROLE == RF_DEVICE_ROLE_TX)
            if(tx_running)
            {
                tmos_set_event(taskID, SBP_RF_TX_SEND_EVT);
            }
#endif
            break;
        }
        case TX_MODE_RX_DATA:
        {
#if(RF_AUTO_MODE_EXAM)
            tx_end_flag = TRUE;
#if(RF_DEVICE_ROLE == RF_DEVICE_ROLE_TX)
            if((crc == 0) &&
               (rxBuf[1] == sizeof(ACK_DATA)) &&
               (rxBuf[2] == ACK_DATA[0]) &&
               (rxBuf[3] == ACK_DATA[1]))
            {
                uint8_t rx_len;

                tx_rx_packet.rssi = (int8_t)rxBuf[0];
                rx_len = rxBuf[1];
                if(rx_len > sizeof(tx_rx_packet.data))
                {
                    rx_len = sizeof(tx_rx_packet.data);
                }
                tmos_memcpy(tx_rx_packet.data, &rxBuf[2], rx_len);
                tx_rx_packet.len = rx_len;
                tmos_set_event(taskID, SBP_RF_TX_RX_DATA_EVT);
            }
            else
            {
                if(tx_running)
                {
                    tmos_set_event(taskID, SBP_RF_TX_SEND_EVT);
                }
            }
#endif
#endif
            break;
        }
        case TX_MODE_RX_TIMEOUT: // Timeout is about 200us
        {
#if(RF_AUTO_MODE_EXAM)
            tx_end_flag = TRUE;
#if(RF_DEVICE_ROLE == RF_DEVICE_ROLE_TX)
            if(tx_running)
            {
                tmos_set_event(taskID, SBP_RF_TX_SEND_EVT);
            }
#endif
#endif
            break;
        }
        case RX_MODE_RX_DATA:
        {
            if((crc == 0) && rx_window_open && !rx_first_packet)
            {
                uint8_t rx_len;

                rx_first_packet = TRUE;
                rx_packet.rssi = (int8_t)rxBuf[0];
                rx_len = rxBuf[1];
                if(rx_len > sizeof(rx_packet.data))
                {
                    rx_len = sizeof(rx_packet.data);
                }
                tmos_memcpy(rx_packet.data, &rxBuf[2], rx_len);
                rx_packet.len = rx_len;
#if(RF_AUTO_MODE_EXAM)
                RF_Wait_Rx_End();
#endif
            }
#if(!RF_AUTO_MODE_EXAM)
            if(rx_window_open)
            {
                tmos_set_event(taskID, SBP_RF_RX_RESTART_EVT);
            }
#endif
            break;
        }
        case RX_MODE_TX_FINISH:
        {
#if(RF_AUTO_MODE_EXAM)
            rx_end_flag = TRUE;
            if(rx_first_packet)
            {
                rx_ack_status = 1;
                tmos_set_event(taskID, SBP_RF_RX_CLOSE_EVT);
            }
#endif
            break;
        }
        case RX_MODE_TX_FAIL:
        {
#if(RF_AUTO_MODE_EXAM)
            rx_end_flag = TRUE;
            if(rx_first_packet)
            {
                rx_ack_status = 2;
                tmos_set_event(taskID, SBP_RF_RX_CLOSE_EVT);
            }
#endif
            break;
        }
    }
}

/*********************************************************************
 * @fn      RF_ProcessEvent
 *
 * @brief   RF 事件处理
 *
 * @param   task_id - 任务ID
 * @param   events  - 事件标志
 *
 * @return  未完成事件
 */
uint16_t RF_ProcessEvent(uint8_t task_id, uint16_t events)
{
    if(events & SYS_EVENT_MSG)
    {
        uint8_t *pMsg;

        if((pMsg = tmos_msg_receive(task_id)) != NULL)
        {
            // Release the TMOS message
            tmos_msg_deallocate(pMsg);
        }
        // return unprocessed events
        return (events ^ SYS_EVENT_MSG);
    }
#if(RF_DEVICE_ROLE == RF_DEVICE_ROLE_TX)
    if(events & SBP_RF_KEY_IRQ_EVT)
    {
        tmos_stop_task(taskID, SBP_RF_KEY_CHECK_EVT);
        tmos_start_task(taskID, SBP_RF_KEY_CHECK_EVT,
                        RF_KEY_DEBOUNCE_TIME);
        return events ^ SBP_RF_KEY_IRQ_EVT;
    }
    if(events & SBP_RF_KEY_CHECK_EVT)
    {
        if(HAL_KeyIrqGet() == 0)
        {
            PRINT("PA4 key pressed\n");
            if(!tx_running)
            {
                tx_running = TRUE;
                tmos_start_task(taskID, SBP_RF_TX_TIMEOUT_EVT,
                                RF_TX_TIMEOUT_TIME);
                tmos_set_event(taskID, SBP_RF_TX_SEND_EVT);
            }
        }
        return events ^ SBP_RF_KEY_CHECK_EVT;
    }
    if(events & SBP_RF_TX_TIMEOUT_EVT)
    {
        tx_running = FALSE;
        RF_Shut();
        tx_rx_packet.len = 0;
        tmos_clear_event(taskID, SBP_RF_TX_SEND_EVT |
                                SBP_RF_TX_RX_DATA_EVT);
        PRINT("TX timeout, no ACK in 3s\n");
        return events & ~(SBP_RF_TX_TIMEOUT_EVT |
                          SBP_RF_TX_SEND_EVT |
                          SBP_RF_TX_RX_DATA_EVT);
    }
    if(events & SBP_RF_TX_RX_DATA_EVT)
    {
        uint8_t i;

        if(tx_rx_packet.len)
        {
            PRINT("tx recv ACK, rssi: %d\n", tx_rx_packet.rssi);
            PRINT("len:%d-", tx_rx_packet.len);
            for(i = 0; i < tx_rx_packet.len; i++)
            {
                PRINT("%x ", tx_rx_packet.data[i]);
            }
            PRINT("\n");
            tx_rx_packet.len = 0;
        }
        tx_running = FALSE;
        tmos_stop_task(taskID, SBP_RF_TX_TIMEOUT_EVT);
        RF_Shut();
        PRINT("TX success, ACK received\n");
        return events ^ SBP_RF_TX_RX_DATA_EVT;
    }
    if(events & SBP_RF_TX_SEND_EVT)
    {
        uint8_t state;

        if(!tx_running)
        {
            return events ^ SBP_RF_TX_SEND_EVT;
        }
        RF_Shut();
        tx_end_flag = FALSE;
        state = RF_Tx(TX_DATA, sizeof(TX_DATA), 0xFF, 0xFF);
        if(state != SUCCESS)
        {
            PRINT("TX start failed.state = %x\n", state);
            tmos_start_task(taskID, SBP_RF_TX_SEND_EVT,
                            MS1_TO_SYSTEM_TIME(1));
        }
        return events ^ SBP_RF_TX_SEND_EVT;
    }
#else
    /* Close RX first if close and restart events arrive together. */
    if(events & SBP_RF_RX_CLOSE_EVT)
    {
        uint8_t i;

        rx_window_open = FALSE;
        tmos_stop_task(taskID, SBP_RF_RX_CLOSE_EVT);
        RF_Shut();
        if(rx_packet.len)
        {
            PRINT("rx recv, rssi: %d\n", rx_packet.rssi);
            PRINT("len:%d-", rx_packet.len);
            for(i = 0; i < rx_packet.len; i++)
            {
                PRINT("%x ", rx_packet.data[i]);
            }
            PRINT("\n");
            rx_packet.len = 0;
        }
        if(rx_ack_status == 1)
        {
            PRINT("ACK sent, RX closed early\n");
        }
        else if(rx_ack_status == 2)
        {
            PRINT("ACK failed, RX closed early\n");
        }
        return events ^ SBP_RF_RX_CLOSE_EVT;
    }
    if(events & SBP_RF_RX_OPEN_EVT)
    {
        uint8_t state;

        rx_window_open = TRUE;
        rx_first_packet = FALSE;
        rx_ack_status = 0;
        rx_packet.len = 0;
        rx_end_flag = FALSE;
        RF_Shut();
        state = RF_Rx(ACK_DATA, sizeof(ACK_DATA), 0xFF, 0xFF);
        PRINT("RX window open.state = %x\n", state);

        tmos_start_task(taskID, SBP_RF_RX_CLOSE_EVT, RF_RX_WINDOW);
        tmos_start_task(taskID, SBP_RF_RX_OPEN_EVT, RF_RX_PERIOD);
        return events ^ SBP_RF_RX_OPEN_EVT;
    }
#endif
    return 0;
}

/*********************************************************************
 * @fn      RF_Init
 *
 * @brief   RF 初始化
 *
 * @return  none
 */
void RF_Init(void)
{
    uint8_t    state;
    rfConfig_t rf_Config;

    tmos_memset(&rf_Config, 0, sizeof(rfConfig_t));
    taskID = TMOS_ProcessEventRegister(RF_ProcessEvent);
    rf_Config.accessAddress = 0x71764129; // 禁止使用0x55555555以及0xAAAAAAAA ( 建议不超过24次位反转,且不超过连续的6个0或1 )
    rf_Config.CRCInit = 0x555555;
    rf_Config.Channel = 39;
    rf_Config.Frequency = 2480000;
#if(RF_AUTO_MODE_EXAM)
    rf_Config.LLEMode = LLE_MODE_AUTO;
#else
    rf_Config.LLEMode = LLE_MODE_BASIC | LLE_MODE_EX_CHANNEL; // 使能 LLE_MODE_EX_CHANNEL 表示 选择 rf_Config.Frequency 作为通信频点
#endif
    rf_Config.rfStatusCB = RF_2G4StatusCallBack;
    rf_Config.RxMaxlen = 251;
    state = RF_Config(&rf_Config);
    PRINT("rf 2.4g init: %x\n", state);
#if(RF_DEVICE_ROLE == RF_DEVICE_ROLE_TX)
    tx_rx_packet.len = 0;
    tx_running = FALSE;
    HAL_KeyIrqInit();
#else
    rx_window_open = FALSE;
    tmos_set_event(taskID, SBP_RF_RX_OPEN_EVT);
#endif
}

/******************************** endfile @ main ******************************/
相关推荐
浩浩kids14 小时前
C•exercises
c语言
春生野草15 小时前
个人笔记——C语言字符串、树
c语言·开发语言·笔记
风中芦苇啊15 小时前
Java EasyExcel 导入通用工具类:自定义注解映射字段 + 反射机制
java·开发语言
PieroPc15 小时前
Python 写的 Windows凭据添加工具 第二版 解决Win11 23H2, 25H2,26H1,共享文件和打印 一部份问题,不是全部!
开发语言·windows·python
家有娇妻张兔兔15 小时前
Java 对接 PLC 主流型号最合适的方案:Apache PLC4X 实战指南
java·开发语言·plc·modbus·数据缓存·西门子s7·apache plc4x
The_Ticker16 小时前
大宗商品行情API接入教程
开发语言·python·websocket·程序人生·区块链
Infedium16 小时前
Qt嵌入式开发核心亮点:线程安全硬件交互技术
开发语言·qt
阿里嘎多学长16 小时前
2026-07-30 GitHub 热点项目精选
开发语言·程序员·github·代码托管
ysu_031416 小时前
用Vibe-Coding从零实现俄罗斯方块
c语言·游戏程序
gugucoding16 小时前
24. 【Java】枚举:更安全的常量
java·开发语言