16_pair 对码通信例程

一、简介

本例程演示 PAN211 芯片的对码通信功能,包含发送端和接收端两个部分。发送端可以通过按键切换对码模式和控制模式,接收端在接收到对码数据后会将发送端的ID作为新的接收地址,实现一对一的通信。

二、条件说明

芯片工作模式:PAN211_CHIPMODE_XN297
CRC:2字节
数据速率:1Mbps
SPI类型:3线SPI
数据长度:8字节(1字节命令 + 7字节数据)
工作模式:普通型
发送功率:9dBm
公共地址:{0xCC, 0xCC, 0xCC, 0xCC, 0xCC}
命令定义:
    - 对码指令:0xA0
    - 控制指令:0xA1

三、接口(移植)实现

  1. 根据硬件实现以下配置:

  • SPI_CS引脚配置为推挽输出

  • SPI_SCK引脚配置为推挽输出

  • SPI_DATA引脚配置为推挽输出或输入模式,低功耗模式下需配置为输入模式并启用上拉电阻

#define SPI_CS_HIGH      CS_PIN = 1      /* 将SPI_CS引脚设置为高电平 */
#define SPI_CS_LOW       CS_PIN = 0      /* 将SPI_CS引脚设置为低电平 */
#define SPI_SCK_HIGH     SCK_PIN = 1     /* 将SPI_SCK引脚设置为高电平 */
#define SPI_SCK_LOW      SCK_PIN = 0     /* 将SPI_SCK引脚设置为低电平 */
#define SPI_DATA_HIGH    DATA_PIN = 1    /* 将SPI_DATA引脚设置为高电平 */
#define SPI_DATA_LOW     DATA_PIN = 0    /* 将SPI_DATA引脚设置为低电平 */
#define SPI_DATA_STATUS  DATA_PIN        /* 读取SPI_DATA引脚状态 */
#define SPI_DATA_OUTPUT  GPIO_SetModeByPin(P4_3, GPIO_MODE_OUTPUT)  /* 配置SPI_DATA引脚为输出模式 */
#define SPI_DATA_INPUT   GPIO_SetModeByPin(P4_3, GPIO_MODE_INPUT)   /* 配置SPI_DATA引脚为输入模式 */
  1. 根据实际使用的MCU修改SPI接口初始化代码:

/**
 * @brief 初始化PAN211 3线SPI接口
 * @param 无
 * @return 无
 * @note 该函数配置SPI_SCK、SPI_CS和SPI_DATA引脚为GPIO模式,并设置为输出模式
 * @note PAN211没有独立中断引脚,可开启SPI_DATA引脚中断复用功能
 * @note PAN216具有独立中断引脚,可通过P4_5来检测PAN216的中断事件
 */
void BSP_3LineSPIInit(void)
{
    CLK_AHBPeriphClockCmd(CLK_AHBPeriph_GPIO, ENABLE);

    // 将引脚配置为GPIO模式,以软件SPI实现
    SYS_ConfigMFP(P4_0, SYS_MFP_GPIO); // SPI_SCK
    SYS_ConfigMFP(P4_1, SYS_MFP_GPIO); // SPI_CS
    SYS_ConfigMFP(P4_3, SYS_MFP_GPIO); // SPI_DATA
    SYS_ConfigMFP(P4_5, SYS_MFP_GPIO); // IRQ引脚,PAN211未使用

    GPIO_SetModeByPin(P4_1, GPIO_MODE_OUTPUT); // 配置SPI_CS为输出模式
    GPIO_SetModeByPin(P4_0, GPIO_MODE_OUTPUT); // 配置SPI_SCK为输出模式
    GPIO_SetModeByPin(P4_3, GPIO_MODE_OUTPUT); // 配置SPI_DATA为输出模式,后续根据时序需要设置为输入模式
    GPIO_SetModeByPin(P4_5, GPIO_MODE_INPUT);  // PAN211没有中断引脚,PAN216有中断引脚,配置为输入模式

    P41 = 1; // SPI_CS置高,表示未选中
    P40 = 0; // SPI_SCK置低,SPI时钟极性为低电平有效
    P43 = 0; // SPI_DATA置低

    GPIO_EnablePullupPath(P4, BIT3); // 将SPI_DATA引脚设置为输入模式,并启用上拉电阻
}

四、应用范例

1、发送端配置

设置为发射模式, 首先读取滚码作为自己ID,初始化为对码模式。在主循环中可以通过按键切换发射“对码包”和对码完成之后的“控制包” ,demo演示的是以间隔10ms的频率持续发射数据,实际应用中请按照实际要求实现。比如上电后先不发射数据,按“对码键”后开始发射对码包。

int main(void)
{
    /* MCU 初始化 */

    if (PAN211_Init() != 1) /* 初始化&校准 PAN211 芯片 */
    {
        printf("PAN211 init failed.\r\n");
        while (1);
    }
    
    printf("Pair tx test start.\r\n");
    
    getRolling();    /* 获取滚码值 */
    setPairMode();   /* 上电初始为对码模式 */

    while (1)
    {
        scanKey();                                /* 切换对码模式或者控制模式 */
        PAN211_WriteFIFO(TxBuf, PAYLOAD_WIDTH);   /* 将待发送的数据写入PAN211 TX FIFO */
        PAN211_TxStart();                         /* PAN211进入发送状态并开始送数据 */
        BSP_DelayMs(10);                          /* 等待发送完成 */
        PAN211_ClearIRQFlags(RF_IT_ALL_IRQ);      /* 清除中断标志 */
    }
}

2、接收端配置

上电设置为接收模式,并且先进入配对模式,接收到数据后判断是“对码包”还是“控制包”,并进行相应处理。


int main(void)
{
    /* MCU 初始化 */

    if (PAN211_Init() != 1) /* 初始化&校准 PAN211 芯片 */
    {
        printf("PAN211 init failed.\r\n");
        while (1);
    }

    printf("Pair rx test start.\r\n");
    
    PAN211_RxStart();   /* 进入接收模式 */
    setPairMode();      /* 设置对码模式 */

    while (1)
    {
        while (!IRQDetected()); /* 等待SPI_DATA/IIC_SDA引脚变低,指示发送完成 */
        
        IRQFlag = PAN211_GetIRQFlags(); /* 获取中断标志 */
        if (IRQFlag & RF_IT_RX_IRQ)     /* 接收中断 */
        { 
            PAN211_ReadFIFO(RxBuf, sizeof(RxBuf));  /* 读取FIFO数据到RxBuf缓冲区,注意:FIFO数据长度不能超过RxBuf大小 */
            PAN211_ClearIRQFlags(RF_IT_RX_IRQ);  /* 清除接收中断标志 */
            
            switch(RxBuf[0])  /* RxBuf[0]为接收数据的第一个字节,表示命令类型 */
            {
                case CMD_PAIR_CODE:
                   parseRfPairCmd(RxBuf); /* 对码处理函数 */
                   break;
                case CMD_CONTROL_CODE:
                   parseRfCtrlCmd();      /* 接收数据解析,只有对码过后才会进入 */
                   break;
            }

            BSP_Led3Toggle();  /* 切换LED3状态 */
        }

        PAN211_ClearIRQFlags(RF_IT_ALL_IRQ);   /* 清除所有中断标志 */
    }
}

在收到“对码包”之后,将接收数据中的“ID”设置新的接收地址,从而达到只能被拥有唯一“ID”的发射端控制。

void parseRfPairCmd(unsigned char *buf)
{
    WorkMode = CONTROL_MODE;         /* 设置工作模式为控制模式 */
    PAN211_SetRxAddr(0, &buf[1], 5); /* 对码指令,将数据中的ID作为新的接收地址, 默认使用0通道 */
    printf("Pair code done! ID:%02X %02X %02X %02X %02X\r\n", buf[1], buf[2], buf[3], buf[4], buf[5]);
}

在本例程中,由于我们每次配对的状态不保存,所以我们接收只需要用到通道0(RX_PIPE0)就可以了,对码未完成之前通道0设置公共地址,对码完成后更新为专用地址。如果我们需要做配对状态保存,更方便的做法是接收使用两个通道,即RX_PIPE0和RX_PIPE1。RX_PIPE0设置为公共地址,RX_PIPE1设置为上次对码的专用地址。在接收到数据后我们可以通过函数PAN211_GetRxPipeNum()来判断是哪个通道收到数据,进而判断出是对码通道收到数据还是控制通道收到数据,当然也可以在数据包中加入相应标志位来判断。

五、参考文档

03_DOC/PAN211x 单向对码.pdf