16_pair 对码通信例程¶
一、简介¶
本例程演示 PAN211 芯片的对码通信功能,包含发送端和接收端两个部分。发送端可以通过按键切换对码模式和控制模式,接收端在接收到对码数据后会将发送端的ID作为新的接收地址,实现一对一的通信。
二、条件说明¶
芯片工作模式:PAN211_CHIPMODE_XN297
CRC:2字节
数据速率:1Mbps
SPI类型:3线SPI
数据长度:8字节(1字节命令 + 7字节数据)
工作模式:普通型
发送功率:9dBm
公共地址:{0xCC, 0xCC, 0xCC, 0xCC, 0xCC}
命令定义:
- 对码指令:0xA0
- 控制指令:0xA1
三、接口(移植)实现¶
根据硬件实现以下配置:
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引脚为输入模式 */
根据实际使用的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