2.4g无线跳频(三)
2.4g无线跳频(三)
一、跳频过程分析
1.主从建立连接,开启定时器。
2.对于主机,每个定时周期内,前部分处于发送模式,后部分处于接收模式;
对于从机,每个定时周期内,前部分处于接收模式,后部分处于发送模式;发送时间应安排小于接收时间;
3.主机发送数据后,在规定的时间后转换为接收模式;从机接收到数据后马上调整自身时间,以达到同步的目的;
主机发送数据的时间要求准时,因为从机接收到信息后会马上调整定时器的计数,同步从机与主机的时间;
4.定时时间一到便开始跳频,注意设法让接收方先于发送方跳。
跳频示意图:
带序列的跳频示意图:
二、代码
#define TIMXCNT TIM3->CNT
#define NRF_CH_SIZE 32 //频道数目
typedef struct
{
u8 rsq[NRF_CH_SIZE]; //序列
u32 seed ; //随机种子
u32 rsqval; //当前序列值
} _rsq_st ; //与随机序列有关的变量
_rsq_st rsq_st;
u8 semflag=0; //全局标志变量,用于同步线程
u8 print_flag=0; //用于串口打印输出的标志变量
/*字节对齐,方便读写*/
#pragma pack(push)
#pragma pack(4)
u8 tmp_Tbuf[NRF_CH_SIZE];
u8 tmp_Rbuf[NRF_CH_SIZE];
#pragma pack(pop)
u8 pdatas[255]={0}; //用于打印测试
TIM3_Int_Init(50000-1 ,72-1 ); // 定时arr=50000
#ifdef NRF24LXX_MASTER //主机代码
void TIM3_IRQHandler(void) //TIM3中断
{
static u8 i=0 ;
if ( TIM_GetITStatus( TIM3, TIM_IT_Update) != RESET) //检查中断源
{
TIM_ClearITPendingBit( TIM3, TIM_IT_Update ); //清除TIMx的中断待处理位
if( NRF_CH_SIZE == i) //序列周期到了
{
i=0;
revflag=1;
rsq_st.seed = *(u32*)(tmp_Rbuf+4) ; //接收种子
BuildRandomSequence( rsq_st.rsq, NRF_CH_SIZE, rsq_st.seed);//利用种子生成特定序列
}
rsq_st.rsqval = rsq_st.rsq[i];
tmp_Tbuf[0] = i+'@';
tmp_Tbuf[1] = i+'@';
semflag = 0;//
i++;
}
}
#else //从机代码
void TIM3_IRQHandler(void)
{
static u8 i=0 ;
if (TIM_GetITStatus( TIM3, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit( TIM3, TIM_IT_Update );
if( NRF_CH_SIZE == i )
{
i=0;
revflag=1;
BuildRandomSequence( rsq_st.rsq, NRF_CH_SIZE, rsq_st.seed);//利用种子生成特定序列
}
NRF24L01_SET_rfch( rsq_st.rsq[i] ) ; //根据序列跳频
NRF24L01_TX_Mode(1);
tmp_Tbuf[0] = i+'@'; //改变其中一个发射值
tmp_Tbuf[1] = i+'@'; //改变其中一个发射值
NRF24L01_TxPacket( tmp_Tbuf);
semflag = 0;
i++;
}
}
#endif
/*生成随机种子并装载至发生内存*/
u32 mySequence()
{
rsq_st.seed = get_random();//随机种子
*(u32*)(tmp_Tbuf+4) = rsq_st.seed;
return rsq_st.seed;
}
# ifdef NRF24LXX_MASTER //主机代码
static u8 i=0;
NRF24L01_RX_Mode(1);//接收模式,开启自动应答
BuildRandomSequence( rsq_st.rsq, NRF_CH_SIZE, rsq_st.seed);//利用种子生成特定序列
while(1)
{
switch( semflag)
{
case 0:
NRF24L01_SET_rfch( rsq_st.rsqval ) ; //根据序列跳频
NRF24L01_RX_Mode(1);
semflag++;
break ;
case 1:
if( print_flag )//打印数据
{
print_flag=0;
fz+= i;fm+=NRF_CH_SIZE;
printf (" %d:%d:%.4f:", temp, i, fz/ fm);
pdatas[ i]='\r',pdatas[ i+1]='\n';
myUSART_Sendarr( USART1, pdatas , i+2) ;
i=0;
}
semflag++;
break ;
case 2:
if( TIMXCNT <30000)
{
if(NRF24L01_RxPacket( tmp_Rbuf)==0)//接收到信息
{
temp= TIM3->CNT ;
TIM3->CNT=1800 ;
pdatas[ i]= tmp_Rbuf[0];
i++;
}
}
else
semflag++;
break ;
case 3:
NRF24L01_TX_Mode(1); //发送模式,开启自动应答自动从发
semflag++;
break ;
case 4:
NRF24L01_TxPacket( tmp_Tbuf);
if( semflag==4) semflag++;
mySequence();//生成随机种子并装载发送内存,为下一周期准备
break ;
case 5:
break ;
}
}
}
#else //从机代码
{
static u16 temp ;
static u8 i=0;
NRF24L01_TX_Mode(1);//发送模式,开启自动应答自动从发
mySequence(); //生成随机数并装载发送内存,为下周期准备
while(1)
{
if( TIMXCNT >20000) //时间到了开始接收模式
{
if( semflag == 0)
{
NRF24L01_RX_Mode(1); //接收模式,开启自动应答
semflag++;
}
else if(TIMXCNT <49500)
{
if(NRF24L01_RxPacket( tmp_Rbuf)==0) //接收到信息
{
temp=TIM3->CNT ; //用于观察计数器
pdatas[i]= tmp_Rbuf[0];//取第一个数装载至pdatas ,用来测试
i++;
}
}
}
if( print_flag ) //打印数据
{
print_flag=0;
fz+= i;fm+= NRF_CH_SIZE;
printf ("%d:%d:%.4f:", temp, i, fz/ fm);//串口打印
pdatas[i]='\r',pdatas[i+1]='\n';
myUSART_Sendarr( USART1, pdatas, i+2); //串口打印数组
i=0;
}
};
}
#endif
以上代码,注意主函数进程与定时器中断服务进程之间的同步,绝不要让两个进程同时访问相同的硬件(这里是无线IC)。
三、验证
两个模块,串口接收如下;
注意第一个数据是各自接收到数据时的定时器读数,而后面1.0000代表丢失率为0,数据接收质量还不错。
————————————————
版权声明:本文为****博主「林子xxx」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.****.net/wangzibigan/article/details/77510187