NRF24L01是一款比较常见的无线通讯芯片,不过有个缺点就是只能半双工通讯,当涉及到双向通讯时就比较麻烦一些·,特别是想要做无线IAP数据需要一直来回发送,这点无疑然人恶心到想吐,不过还好有数据中断可以用来做切换。
前些时间做的无线IAP用到双向通讯,现在分享如下
省去初始化SPI,等一些初始化
1、初始化接口,以及中断引脚IRQ
void EXTIInitialize(void) //外部中断初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //通道设置为串口1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中断抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中断响应优先级2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打开中断
NVIC_Init(&NVIC_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0; //外部中断0
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; //上拉输入
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
EXTI_ClearITPendingBit(EXTI_Line0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)!=RESET)
{
DataProces();
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
2、NRF24L01模式初始化选择数据中断
void NRF_Mode(char mode)
{
NRF24L01_CE=0;
NRF24L01_Write_Reg(WRITE_REG_NRF+SETUP_AW,0x03);//地址宽度
NRF24L01_Write_Buf(WRITE_REG_NRF+TX_ADDR,(u8*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址
NRF24L01_Write_Buf(WRITE_REG_NRF+RX_ADDR_P0,(u8*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
NRF24L01_Write_Reg(WRITE_REG_NRF+EN_AA,0x00); //使能通道0的自动应答
NRF24L01_Write_Reg(WRITE_REG_NRF+EN_RXADDR,0x01);//使能通道0的接收地址
NRF24L01_Write_Reg(WRITE_REG_NRF+SETUP_RETR,0x1a);
NRF24L01_Write_Reg(WRITE_REG_NRF+RF_CH,124); //设置RF通信频率
NRF24L01_Write_Reg(WRITE_REG_NRF+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度
NRF24L01_Write_Reg(WRITE_REG_NRF+RF_SETUP,0x0f);//设置TX发射参数,0db增益,2Mbps,低噪声增益开启
//tx
if(mode==1)
NRF24L01_Write_Reg(WRITE_REG_NRF+CONFIG,0x5e);//0101
//rx
else
NRF24L01_Write_Reg(WRITE_REG_NRF+CONFIG, 0x3f);
NRF24L01_CE = 1; //CE为高,启动配置
}
3、接受到数据后产生中断以及发送完成产生中断,中断相对于主机而言,对于NRF24L01只是产生一个高电平,用中断去处理相关数据
void DataProces(void)
{
u8 sta,i;
sta=NRF24L01_Read_Reg(STATUS); //读取状态寄存器的值
NRF24L01_Write_Reg(WRITE_REG_NRF+STATUS,0x70); //清除中断标志
if(sta&TX_OK)//发送完成
{
NRF24L01_Write_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器
ChangeMode(2);
my_delay_us(10); //粗略等待15us,不调用滴答定时器影响整体时序
}
if(sta&RX_OK)//接收到数据
{
NRF24L01_Read_Buf(RD_RX_PLOAD,RxNrfBuf,RX_PLOAD_WIDTH);//读取数据
NRF24L01_Write_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器
ChangeMode(1);
IAP(RxNrfBuf);
//不调用滴答定时器影响整体时序
//延时30等待对方切换模式s
my_delay_us(50);
//TxNrfBuf[0] = test++;
NrfSend(TxNrfBuf);
}
}
4、接受或者发送完成之后便可以做响应的处理,其中为了提高数据准确性我将中断数据处理定义成两个模式分为主接受,和主发送。’主接受模式接收到数据后就切换发送模式根据需要去返回数据,发送完成后就立马切换为接收模式,以接收模式作为常态,为下一次的接收做准备;主发送模式发送完数据后就切换为接收模式,等待有数据返回,返回后就立马切换为发送模式,以发送模式作为常态。其中有一个小小的技巧,在主发送模式下等待接收数据时可开启定时器,用来做超时处理,超时后重新发送,当然,NRF25L01上面自带重发功能,但我不太喜欢上面的自动重发,那个是不可控的,我比较喜欢可控的数据收发,这样更为灵活,可以根据自己单片机的速度以及环境因素设定 符合自己的所需要的重发时间
void ChangeMode(char mode)
{
NRF24L01_CE=0;
//TX
if(mode == 1)
NRF24L01_Write_Reg(WRITE_REG_NRF+CONFIG,0x5e);
else
NRF24L01_Write_Reg(WRITE_REG_NRF+CONFIG,0x3f);
NRF24L01_CE=1;//启动
}