E70_433半双工无线模组,伪全双工方案

article/2025/9/11 9:15:36

E70_433半双工无线模组,伪全双工方案

  • 前言
  • 架构设计
    • 外侧输入模块
    • 外侧输出模块
    • 内侧发帧模块
    • 内侧接受模块
  • 实现代码
    • 通用宏定义
      • 代码解析
    • 通用工具函数
      • 代码解析
    • 串口输入输出函数
      • 代码解析
    • 核心业务代码
      • 发送模块
        • 代码解析
      • 接收模块
        • 代码解析
        • 代码流程
  • 结语
    • 附带

前言

要搞一个远程数据传输,性价比高的模块是433模块类型,一开始选用的是E70_433模组但是后来发现需要能够全双工,E62模块大概要贵50块钱,因此就继续尝试用E70模组,看看能不能降一点成本,因此就有了以下这个方案_φ_(..) 写作业
如果是全双工模块外侧输入数据可以直接接入串口:
A-(串口)-E62_433——(空中信道)
但是因为是半双工因此我需要加入一个mcu(stm32)控制串口
A-(串口)-stm32-(串口)-E70_433——(空中信道)
本文的设计内容为stm32里的转发程序

架构设计

传输模型
全双工意味着输入的时候可以输出,半双工意味着只能选择输入或者输入,因此如果半双工切换状态的速度够快,在长的时间尺度上就可以实现全双工的效果。

外侧输入模块

首先,外侧流入数据的速度必须低于433模块数据吞吐的速度因为433模组切换状态和发送都需要时间。
其次,通讯可能会锻炼,比如突然有强信号干扰,因此必须有一个合适大小的数据缓存区域,为了方便存储和读取,必须采用队列存储方式
最后,注意中断

外侧输出模块

首先,由于433速度大于外侧数据吞吐速度,因此必须有一个合适大小的数据缓存区域(需要略大于输入缓存区)
其次,为了加快通讯速度,必须采用中断发送而不是阻塞发送,因此需要使用队列存贮方式。
最后,注意中断

内侧发帧模块

两组433间的通讯认为是内侧通讯,这里主要执行的功能是读取外侧输入模块封存的数据帧和内侧接受模块封存的数据帧,拼接完成后组包对外发送。

内侧接受模块

两组433间的通讯认为是内侧通讯,这里主要执行的功能是接受另一侧433模块传来的数据包。当数据包正常时,将数据解包封存进入外侧发送模块,并且将外侧数据封存一帧以实现连续传输;当数据包不正常时(缺头,缺尾,缺身子,长度错误…等等)丢弃这一帧数据,立即回传一个重发信号包,以确保数据的稳定性

实现代码

通用宏定义

#define BUFF_LEN_B 5000
#define BUFF_LEN_O 6000
#define BUFF_LEN 200#define FRAME_CLUB_MAX 49  //帧组最大数量#define M_TRUE   0x5a      //未启用  
#define M_FALSE  0xa5      //未启用  #define TRUE   1      	   
#define FALSE  0     			  #define PPP_FLAG  0x7e      //ppp协议的帧头和帧尾部
#define PPP_START 0xFF      //ppp协议的帧的开始#define E70_STATE_LISTEN 0x34     //433模块状态  接受数据包完成
#define E70_STATE_SEND   0x43     //433模块状态  发送数据包完成
#define E70_STATE_START  0x00     //433模块状态  准备建立通路#define E70_STATE_OVERTIME  0x0E  //433模块状态  接受数据超时请求重发   新增:数据错误请求重发
#define E70_STATE_LISTEN_E  0x3E  //433模块状态  接受丢包反馈完成
#define E70_STATE_RESEND    0xE3  //433模块状态  重新发送数据包完成#define PACK_MAX_DATA_LEN 100      //设定433模组间发送最大数据长度
#define PACK_HEAD_lEN      2      //设定包的头字节长度
#define PACK_LEN_lEN       2      //设定包的长度字节长度
#define PACK_NUMBER_lEN    2      //设定包的序号字节长度
#define PACK_FUNCTION_lEN  1      //设定包的类别字节长度
#define PACK_END_lEN       2      //设定包的结尾长度#define PACK_OUTDATA_LEN (PACK_HEAD_lEN +\PACK_LEN_lEN+\PACK_NUMBER_lEN+\PACK_FUNCTION_lEN+\PACK_END_lEN)     
//设定433模组间除数据外的长度#define PACK_MAX_LEN 		(PACK_OUTDATA_LEN + PACK_MAX_DATA_LEN)   
//设定433模组最大的数据长度#define PACK_HEAD_DATA      0x1234 	//设定433模组包头
#define PACK_END_DATA       0x4321 	//设定433模组包头
#define PACK_FUNCTION_WIFI    0x01  //设定433模组包功能:wifi方面启动发包 wifi start (未启用)
#define PACK_FUNCTION_DATA    0x02  //设定433模组包功能:数值 data
#define PACK_FUNCTION_NULL    0x03  //设定433模组包功能:空   null									 (未启用)
#define PACK_FUNCTION_4G      0x04  //设定433模组包功能:4g方面启动发包 4g start		 (未启用)
#define PACK_FUNCTION_RESEND  0x05  //设定433模组包功能:接受方重新发送上一包数据#define LOSE_HEAD_COUNT       0x02	//设定包头丢失最大计数
#define LOSE_HEAD_MODE_FINE   0x00	//设定包头丢失模式:无异常
#define LOSE_HEAD_MODE_WAIT   0x01	//设定包头丢失模式:等待判断
#define LOSE_HEAD_MODE_GET    0x02	//设定包头丢失模式:获取包尾
#define LOSE_HEAD_MODE_OUT    0x03	//设定包头丢失模式:获取超时#define LOSE_TAIL_MODE_FINE   0x00	//设定包尾丢失模式:无异常
#define LOSE_TAIL_MODE_WAIT   0x01	//设定包尾丢失模式:等待判断
#define LOSE_TAIL_MODE_GET    0x02	//设定包尾丢失模式:获取包尾
#define LOSE_TAIL_MODE_OUT    0x03	//设定包尾丢失模式:获取超时#define E70_TIME_OUT  500 			 	  // (单位是ms)
#define EC20_TIME_OUT 200 				  // (单位是ms)#define LOSE_HEAD_TIME_OUT 100 			// (单位是ms) 
#define LOSE_TAIL_TIME_OUT 100 			// (单位是ms) 
#define LOSE_PACK_TIME_OUT 200 			// (单位是ms) 19200 帧间隔应该近似62.5mstruct _LOSE_HEAD_
{__IO u32 Time;					//包头丢失超时时间__IO uint8_t Count;    	//帧头丢失计数__IO uint8_t EndCount;  //帧尾获取计数__IO uint8_t Mode;      //帧头丢失种类  //0.正常,1.等待判断,2.获取包尾,3.超时判别
};
struct _LOSE_TAIL_
{__IO u32 Time;					//帧尾丢失超时时间__IO uint8_t Count;    	//帧头丢失计数__IO uint8_t EndCount;  //帧尾获取计数__IO uint8_t Mode;      //帧尾丢失种类  //0.正常,1.等待判断,2.获取包尾,3.超时判别
};#define LOSE_HEAD _LOSE_HEAD_
#define LOSE_TAIL _LOSE_TAIL_#define OUTSIDE USART2
#define INSIDE  USART1#define OUTSIDE_TX_BUFF USART2_TX_BUFF
#define OUTSIDE_RX_BUFF USART2_RX_BUFF
#define INSIDE_TX_BUFF  USART1_TX_BUFF
#define INSIDE_RX_BUFF  USART1_RX_BUFF#define OUTSIDE_TX_LEN  USART2_TX_LEN
#define OUTSIDE_RX_LEN  USART2_RX_LEN
#define INSIDE_TX_LEN   USART1_TX_LEN
#define INSIDE_RX_LEN  	USART1_RX_LEN#define OUTSIDE_TX_QUEUE_LEN  USART2_TX_QUEUE_LEN
#define OUTSIDE_TX_END_LEN 	USART2_TX_END_LEN#define g_sysOutTime  g_sysMTime// 433 模块数据包接受完成后就是等待数据发送,数据发送完成后就是等待接受数据包,来回通讯
// 433 (send) ->- 433 (start)  to 433 (send)   --- 433 (listen)  start mode
// 433 (send) -<- 433 (send)   to 433 (listen) --- 433 (send)
// 433 (send) ->- 433 (send)   to 433 (send)   --- 433 (listen)
// or
// 433 (send) ->- 433 (send)   to 433 (send)   --- 433 (overtime)  
// 433 (send) -<- 433 (send)   to 433 (lis_e)  --- 433 (send)    
// 433 (re_s) ->- 433 (send)   to 433 (re_s)   --- 433 (listen)  resend lost pack
// or
// 433 (re_s) ->- 433 (send)   to 433 (re_s)   --- 433 (overtime)
// 433 (re_s) -<- 433 (send)   to 433 (listen) --- 433 (send)    jump lost pack

代码解析

以上建一个.h文件丢入,然后#include就可以了
其中OUTSIDE是对外侧连接的串口
其中INSIDE是对内侧连接的串口
其余有问题请留言_(´ཀ`」∠)_加班

通用工具函数


//在字符串1里找字符串2,返回字符串2结束在字符串1的位置,找不到时反馈0
uint16_t CompareString(uint8_t* Str1 ,uint8_t * Str2 ,uint16_t Str1_len,uint16_t Str2_len)
{uint16_t outLen   = 0;uint16_t startLen = 0;uint16_t i        = 0;if(Str1_len<Str2_len||Str2_len==0||Str1_len==0) //校验异常return 0;startLen=Str1_len-Str2_len;for(i=0;i<=startLen;i++){if(*(Str1+i)==*Str2) //找到起始字符{for(outLen=0;outLen<Str2_len;outLen++){if(*(Str1+i+outLen)!=*(Str2+outLen)){
//					printf("[test] i=%d, outLen=%d,*(Str1+i+outLen)=%x,*(Str2+outLen)=%x\r\n",
//					i,outLen,*(Str1+i+outLen),*(Str2+outLen));break;}}if(outLen==Str2_len)return outLen+i; //待验证}}return 0;
}
//在字符串1里找字符串2,返回字符串2结束在字符串1的位置,找不到时反馈0
uint16_t GetPackLen(uint8_t* Str1,uint16_t len)
{uint16_t outPackLen   = 0;uint16_t i            = 0;uint8_t  temp         = 0;if(len==0)return 0;                          //return failfor(i=0;i<len;i++){temp=(*(Str1+i))-'0';if(temp>9)                         // 超上限return 0;                        //return failoutPackLen*=10;                    //升一位outPackLen+=temp;}return outPackLen;
}uint32_t CompareTimeBase(uint32_t early,uint32_t late)
{if(early>late){if(early-late<10)									 //消除bug引起的浮动误差,不影响正常判别{return 0;	}return (0xFFFFFFFF - early + late);}else{return (late - early);}
}
uint32_t 	GetTickCount(void)
{return sysTime;
}//***********************************************************************
//将发送区数数据重新按着433私有协议个格式重新打包
//***********************************************************************
void pack433Data (u8 *pData,u16 len,u8 mode)
{u8 temporary[PACK_MAX_LEN] ={0};//-存入包头temporary[0]=PACK_HEAD_DATA>>8;          // 存入包头高字节temporary[1]=PACK_HEAD_DATA&0xff;        // 存入包头低字节//-存入帧长度temporary[2]=(PACK_OUTDATA_LEN+len)>>8;  // 存入帧长度高字节temporary[3]=(PACK_OUTDATA_LEN+len)&0xff;// 存入帧长度低字节//-存入帧序号(——)还未启用temporary[4]=0; 											   // 存入帧序号高字节temporary[5]=0;  												 // 存入帧序号低字节//-存入帧功能temporary[6]=mode; 											 // 存入帧功能memcpy(&temporary[7],pData,len);         //-存入帧数据//-存入尾头temporary[7+len]=PACK_END_DATA>>8;       // 存入包尾高字节temporary[8+len]=PACK_END_DATA&0xff;     // 存入包尾低字节memcpy(pData,temporary,PACK_OUTDATA_LEN+len);//打包完成
}	
//***********************************************************************
//将接收区数据重新按着帧格式封存
//***********************************************************************
//static u16 len=0;
void saveFrameToBUFF(u16 pointnNumber,u8 timeoutFlag)
{if(saveFrameFlag)                        //存帧标志位return;elsesaveFrameFlag=1;if(frame_club[frame_index_n][0]>pointnNumber)      //获取帧长度pointnNumber+=BUFF_LEN_B;		if(timeoutFlag==TRUE){																 //2是,帧组没有帧且要求立刻生成一帧if(frame_index_l>0) //清理非逻辑异常{saveFrameFlag=0;return;}frame_index_l=frame_index_l+2;                       //帧长度加2if(pointnNumber>=BUFF_LEN_B){pointnNumber-=BUFF_LEN_B;}frame_club[frame_index_n][1]=pointnNumber; //存入当前帧的结束位(后一位)frame_index_n=frame_index_n+1;if(frame_index_n>=FRAME_CLUB_MAX)frame_index_n=0;                      //帧组循环存储frame_club[frame_index_n][0]=pointnNumber; //存入当前帧(起始帧)	1if(frame_index_n==frame_index_s)        //帧组出现覆盖{#ifdef DEBUG_433printf("[E] i=%d,l=%d\n",frame_index_s,frame_index_l);#endifframe_index_n=frame_index_n==0?FRAME_CLUB_MAX-1:frame_index_n-1;//取消当前帧	frame_club[frame_index_n][0]=pointnNumber;//跳过帧saveFrameFlag=0;frame_index_l-=2;											//取消队列增长return;                               //阻止封帧}if(frame_index_l>2) //清理非逻辑异常{		#ifdef DEBUG_433printf("[E],2\n");#endifframe_index_n=frame_index_n==0?FRAME_CLUB_MAX-1:frame_index_n-1;frame_index_l-=2;											//取消队列增长saveFrameFlag=0;return;}			frame_club[frame_index_n][0]=pointnNumber; //存入当前帧(起始帧)2		saveFrameFlag=0;return;}if(pointnNumber-frame_club[frame_index_n][0]>=PACK_MAX_DATA_LEN-5) 														 //收到封帧请求时在2种情况下可以封帧//1是,当前帧长度满足要求{//len=pointnNumber-frame_club[frame_index_n][0];frame_index_l=frame_index_l+2;          //帧长度加2#ifdef DEBUG_433//printf("[T] add pack len:%d,%d,%d,%d,%d\n",len,pointnNumber,frame_club[frame_index_n][0],frame_club[frame_index_n-1][0],frame_index_n);#endifif(pointnNumber>=BUFF_LEN_B){pointnNumber-=BUFF_LEN_B;}frame_club[frame_index_n][1]=pointnNumber; //存入当前帧的结束位(后一位)frame_index_n=frame_index_n+1;if(frame_index_n>=FRAME_CLUB_MAX)frame_index_n=0;                      //帧组循环存储if(frame_index_n==frame_index_s)        //帧组出现覆盖{#ifdef DEBUG_433printf("[E] i=%d,l=%d\n",frame_index_s,frame_index_l);#endifframe_index_n=frame_index_n==0?FRAME_CLUB_MAX-1:frame_index_n-1;//取消当前帧			frame_index_l-=2;											//取消队列增长frame_club[frame_index_n][0]=pointnNumber;//跳过帧saveFrameFlag=0;return;                               //阻止封帧}frame_club[frame_index_n][0]=pointnNumber; //存入当前帧(起始帧)saveFrameFlag=0;return; 	}saveFrameFlag=0;
}

代码解析

以上主要关注2个函数:
pack433DatasaveFrameToBUFF
这是2个主要的功能函数
pack433Data这个函数用于把需要发送向433模块的数据按着帧包格式封存
saveFrameToBUFF这个函数用于将外测数据封存入帧队列(一共2个队列,一个帧队列,一个是输出队列)
第一个输入参数是缓存数据队列的指针号,第二个参数表示是否强制封帧
如果强制封帧当帧队列长度为0时可以封入,如果不强制封帧当缓存数据队列长度到达帧上限则封一帧。
另外在这个函数里有一个很重要的设计saveFrameFlag
这是这是用于防止中断侵入逻辑的防护手段。

串口输入输出函数

void USART1_IRQHandler(void)  //串口1中断    433
{u8 res;if(USART_GetITStatus(INSIDE,USART_IT_RXNE)) //收到一个字就立刻发送{res= USART_ReceiveData(INSIDE); //USART_SendData(USART2,res);  //1转2INSIDE_RX_BUFF[INSIDE_RX_LEN++]=res;if(INSIDE_RX_LEN>=BUFF_LEN){INSIDE_RX_LEN=0;}if(INSIDE_RX_LEN==1)                        //首字节判断{if(res!=(PACK_HEAD_DATA>>8))              //高位不正确{INSIDE_RX_LEN=0;                        //清除长度loseHead.Count++;												//帧头丢失}elseloseHead.Count=0;												//清除计数}if(INSIDE_RX_LEN==2)                        //次字节判断{if(res!=(PACK_HEAD_DATA&0xff))            //低位不正确{INSIDE_RX_LEN=0;                        //清除长度loseHead.Count+=2;											//帧头丢失(严重)}elseloseHead.Count=0;												//清除计数}if(INSIDE_RX_LEN>2&&loseHead.Count<LOSE_HEAD_COUNT)loseHead.Count=0;													//清除计数if(loseHead.Mode==LOSE_HEAD_MODE_WAIT)			//当前为帧头丢失判别{if(res==(PACK_END_DATA&0xff)&&loseHead.EndCount==1)//获取包尾低位{loseHead.EndCount=2;										//包尾长度记录}else if(res==(PACK_HEAD_DATA>>8)&&loseHead.EndCount==0)//获取包尾高位{loseHead.EndCount=1;										//包尾长度记录}else 				{loseHead.EndCount=0;										//无包尾字段}if(loseHead.EndCount>=2)									//获取包尾loseHead.Mode=LOSE_HEAD_MODE_GET;				//修改标志为包尾取得loseHead.Time=GetTickCount();    					//包头丢失超时计时}if(loseTail.Mode==LOSE_TAIL_MODE_WAIT)			//当前为帧尾丢失判别{if(res==(PACK_END_DATA&0xff)&&loseTail.EndCount==1)//获取包尾低位{loseTail.EndCount=2;										//包尾长度记录}else if(res==(PACK_HEAD_DATA>>8)&&loseTail.EndCount==0)//获取包尾高位{loseTail.EndCount=1;										//包尾长度记录}else 				{loseTail.EndCount=0;										//无包尾字段}if(loseTail.EndCount>=2)									//获取包尾loseTail.Mode=LOSE_TAIL_MODE_GET;				//修改标志为包尾取得loseTail.Time=GetTickCount();    					//包头丢失超时计时}if(loseHead.Count>=LOSE_HEAD_COUNT)					//帧头丢失超过容忍{loseHead.Count=LOSE_HEAD_COUNT;						//防止溢出loseHead.Time=GetTickCount();    					//包头丢失超时计时loseHead.Mode=LOSE_HEAD_MODE_WAIT;				//准备判别丢包种类}	g_sys433Time=GetTickCount();    //载入当前系统时间	}
}
void USART2_IRQHandler(void)  //串口2中断   外测
{u8 res;if(USART_GetITStatus(OUTSIDE,USART_IT_RXNE)) //收到一个字就立刻发送{res= USART_ReceiveData(OUTSIDE); //USART_SendData(USART1,res);  //2转1OUTSIDE_RX_BUFF[OUTSIDE_RX_LEN++]=res; 					 //存入收区if(OUTSIDE_RX_LEN>=BUFF_LEN_B)      OUTSIDE_RX_LEN=0;		saveFrameToBUFF(OUTSIDE_RX_LEN,FALSE);          //存入数据到帧组里g_sys4GTime=GetTickCount();    					       //载入当前系统时间		}if(USART_GetITStatus(OUTSIDE,USART_IT_TXE)!=RESET)//发送完成标志{if(setDataFlag)														//如果正在载入数据,先关闭中断{			USART_ClearITPendingBit(OUTSIDE,USART_IT_TXE);//先清除中断标志位	USART_ITConfig(OUTSIDE,USART_IT_TXE, DISABLE);//无数据则关闭中断outPutFlag=0;}else if(OUTSIDE_TX_QUEUE_LEN>0)                      //队列里有数据{OUTSIDE_TX_QUEUE_LEN--;               				 //队列长度减1USART_SendData(OUTSIDE, OUTSIDE_TX_BUFF[OUTSIDE_TX_LEN++]);//sendif(OUTSIDE_TX_LEN>=BUFF_LEN_O)      OUTSIDE_TX_LEN=0;		USART_ClearITPendingBit(OUTSIDE,USART_IT_TXE);//先清除中断标志位	outPutFlag=1;}else{USART_ClearITPendingBit(OUTSIDE,USART_IT_TXE);//先清除中断标志位	USART_ITConfig(OUTSIDE,USART_IT_TXE, DISABLE);//无数据则关闭中断outPutFlag=0;}}//*************************************************************//  if(USART_GetITStatus(USART2, USART_IT_TXE) == RESET)
//  {   
//		 USART_ClearFlag(USART2,USART_IT_TXE);
//     //USART_SendData(USART2, USART2_TX_BUFF[USART2_RX_LEN--]);//test
//  } //USART_ClearITPendingBit(USART2,USART_IT_TXE);	
}

说个题外化,我很努力的让keil里排版好看:
但是
但是复制过来就不整齐了,逼死了我这个强迫症!!!
(*▼ー(。-_-。)画风不对,如何相爱
咋办呢??

代码解析

以上一个是外测数据流通的串口中断,另一个是433数据流通时的串口中断。
433流向的串口中断主要执行3个功能
1,接受数据。
2,未进入包接受状态时抛弃非包头数据,并记录警报
3,在异常状态下抓取包尾数据
接受数据功能代表字段是这一段:
INSIDE_RX_BUFF[INSIDE_RX_LEN++]=res;
载入数据,并且移动坐标指针。
包头判别功能代表字段是这一段:

if(INSIDE_RX_LEN==1)                        //首字节判断
{if(res!=(PACK_HEAD_DATA>>8))              //高位不正确{INSIDE_RX_LEN=0;                        //清除长度loseHead.Count++;												//帧头丢失}elseloseHead.Count=0;												//清除计数
}
if(INSIDE_RX_LEN==2)                        //次字节判断
{if(res!=(PACK_HEAD_DATA&0xff))            //低位不正确{INSIDE_RX_LEN=0;                        //清除长度loseHead.Count+=2;											//帧头丢失(严重)}elseloseHead.Count=0;												//清除计数
}

通过检查存入的帧头是否正确来决定是否放弃这一帧数据
,包尾抓取的设计方法和这个类似就阐述了。
外侧数据流向的串口中断主要执行这2个功能:
1,获取数据封帧处理
2,读取发送队列发送数据
封帧功能主要通过调用这一个函数实现
saveFrameToBUFF(OUTSIDE_RX_LEN,FALSE); //存入数据到帧组里
发送数据功能主要通过这一段来实现
USART_SendData(OUTSIDE,OUTSIDE_TX_BUFF[OUTSIDE_TX_LEN++]);//send
这里也有一处不能忽视的设计:
setDataFlag
这同样是为了不让中断侵入逻辑而做的防御措施。(忘记对中断做防御,后果很严重)。
outPutFlag
这一处是我做着玩的,同样是为了防止中断侵入,但是后来发现没有必要,主要防御功能是用上一处实现的。

核心业务代码

发送模块

//*******************************************************************
//                     433私有协议帧包发送模式 resend
//*******************************************************************
//
//
void resendFrameTo433 (void)                 //向433模组发送一帧数据
{uint16_t 	frame_head  = 0;uint16_t	frame_end   = 0;uint16_t  frame_rhead = 0;                //考虑到循环存储,因此把发送数据做个分段提取uint16_t  frame_rend  = 0; uint16_t  i           = 0;  							//测试用序号frame_head=frame_club[FRAME_CLUB_MAX][0];	//取出帧头frame_end =frame_club[FRAME_CLUB_MAX][1];	//取出帧尾if(frame_head>frame_end)              	  //帧头序号大于帧尾序号{frame_rhead= BUFF_LEN_B ;           	  //头的结尾frame_rend =           0;            		//尾的开头}else{frame_rhead=frame_end;               		//头的结尾是尾frame_rend =frame_end ;              		//尾是尾}INSIDE_TX_LEN=(frame_rhead-frame_head)+(frame_end-frame_rend);									//获取发送长度if(INSIDE_TX_LEN>PACK_MAX_DATA_LEN){#ifdef DEBUG_433printf("[re][e] resend len over\n");#endifINSIDE_TX_LEN=999;                 			//临时处理长度错误问题memset(INSIDE_TX_BUFF,0,INSIDE_TX_LEN); //清除发送区数据}else{memcpy(&INSIDE_TX_BUFF[0],&OUTSIDE_RX_BUFF[frame_head],frame_rhead-frame_head);              //复制第一段数据memcpy(&INSIDE_TX_BUFF[frame_rhead-frame_head],&OUTSIDE_RX_BUFF[frame_rend],frame_end-frame_rend);						    //复制第二段数据}#ifdef DEBUG_433printf("[re]%2d,%3d\n",INSIDE_TX_LEN,frame_index_l);#endifpack433Data(INSIDE_TX_BUFF,INSIDE_TX_LEN,PACK_FUNCTION_DATA);//重新打包数据INSIDE_TX_LEN += PACK_OUTDATA_LEN;                     //打包数据的长度uart_sendData(INSIDE, INSIDE_TX_BUFF,INSIDE_TX_LEN);   //发送data的数据memset(INSIDE_TX_BUFF,0,INSIDE_TX_LEN); 	//清除发送区数据INSIDE_TX_LEN=0;			e70_433_state=E70_STATE_SEND;          		//发送完成置433状态为发送		i = i;                                  	//去除编译的warning,无意义
}
//*******************************************************************
//                     433私有协议帧包发送模式 send
//*******************************************************************
//
//
void sendFrameTo433 (void)                //向433模组重新发送一帧数据
{uint16_t 	frame_head  = 0;uint16_t	frame_end   = 0;uint16_t  frame_rhead = 0;                //考虑到循环存储,因此把发送数据做个分段提取uint16_t  frame_rend  = 0; uint16_t  i           = 0;  							//测试用序号if(frame_index_l>>1)											//也就是已经存储了若干帧{frame_index_l-=2;                       //取出1帧frame_head=frame_club[frame_index_s][0];//取出帧头frame_end =frame_club[frame_index_s][1];//取出帧尾frame_club[FRAME_CLUB_MAX][0]=frame_club[frame_index_s][0];//保存帧头frame_club[FRAME_CLUB_MAX][1]=frame_club[frame_index_s][1];//保存帧尾frame_club[frame_index_s][0]=0;         //清除旧数据frame_club[frame_index_s][1]=0;					//清除旧数据frame_index_s++;                        //发送帧组序号进1if(frame_index_s>=FRAME_CLUB_MAX)frame_index_s=0;                      //发送帧序号复位//暂时不做帧组管理和相关校验 2019.10.15if(frame_head>frame_end)                //帧头序号大于帧尾序号{frame_rhead= BUFF_LEN_B ;             //头的结尾frame_rend =           0;             //尾的开头}else{frame_rhead=frame_end;               	//头的结尾是尾frame_rend =frame_end ;               //尾是尾}INSIDE_TX_LEN=(frame_rhead-frame_head)+(frame_end-frame_rend);								//获取发送长度if(INSIDE_TX_LEN>PACK_MAX_DATA_LEN){#ifdef DEBUG_433printf("[e] frame_head=%d\n",frame_head);printf("[e] frame_end =%d\n",frame_end);printf("[e] frame_index_s =%d\n",frame_index_s);printf("[e] frame_index_n =%d\n",frame_index_n);printf("[e] frame_head_n =%d\n",frame_club[frame_index_s-2][0]);printf("[e] frame_end_n =%d\n",frame_club[frame_index_s-2][1]);printf("[e] frame_head_n =%d\n",frame_club[frame_index_s-3][0]);printf("[e] frame_end_n =%d\n",frame_club[frame_index_s-3][1]);#endif//INSIDE_TX_LEN=PACK_MAX_DATA_LEN;                 //临时处理长度错误问题INSIDE_TX_LEN=999;                 			//临时处理长度错误问题memset(INSIDE_TX_BUFF,0,INSIDE_TX_LEN); //清除发送区数据}else{memcpy(&INSIDE_TX_BUFF[0],&OUTSIDE_RX_BUFF[frame_head],frame_rhead-frame_head);              //复制第一段数据memcpy(&INSIDE_TX_BUFF[frame_rhead-frame_head],&OUTSIDE_RX_BUFF[frame_rend],frame_end-frame_rend);						    //复制第二段数据}#ifdef DEBUG_433//printf("%2d,%3d,%5d,%5d\n",USART1_TX_LEN,frame_index_l,frame_head,frame_end);//printf("%d,%3d,%3d\n",frame_index_l,frame_index_s,frame_index_n);printf("%2d,%3d\n",INSIDE_TX_LEN,frame_index_l);//printf("1\n");#endifpack433Data(INSIDE_TX_BUFF,INSIDE_TX_LEN,PACK_FUNCTION_DATA);//重新打包数据INSIDE_TX_LEN += PACK_OUTDATA_LEN;                     //打包数据的长度uart_sendData(INSIDE, INSIDE_TX_BUFF,INSIDE_TX_LEN);   //发送data的数据memset(INSIDE_TX_BUFF,0,INSIDE_TX_LEN); //清除发送区数据INSIDE_TX_LEN=0;			e70_433_state=E70_STATE_SEND;           //发送完成置433状态为发送		}i = i;                                    //去除编译的warning,无意义
}

代码解析

这里是2个函数,一个是正常的send函数另一个是重新发送数据的resend函数
两个函数业务逻辑是一样的,唯一不同的是数据来源。在send函数里,数据来源是帧组队列,在resend函数里数据来源是备份帧。
(隐患消除,如果没有备份帧呢?比如一侧死机了重启后,另一侧要求resend,不用担心,此时会发送空帧重建连接不会出现故障。至于丢失的数据,丢了就丢了呗)
( ̄▽ ̄)~*

接收模块

//*******************************************************************
//                     433私有协议帧包接受模式 receive
//*******************************************************************
//
//
void receiveFramefrom433 (void)             	//获取433模组的数据
{u16 len=0;u16 add_queue_len=0;u16 i;//u8  frame_ok =0;                          	//全解包标志while(INSIDE_RX_LEN||loseHead.Mode||loseTail.Mode)					{																							//缓存区有数据就必须完成一次解包switch(loseHead.Mode){case LOSE_HEAD_MODE_GET:case LOSE_HEAD_MODE_OUT:#ifdef DEBUG_433printf("[ERROR_433] loseHead.Mode :%d\n",loseHead.Mode);#endifmemset(INSIDE_TX_BUFF,0,BUFF_LEN); 		//清除发送区数据INSIDE_TX_LEN=0;		pack433Data(INSIDE_TX_BUFF,INSIDE_TX_LEN,PACK_FUNCTION_RESEND);//重新打包数据INSIDE_TX_LEN += PACK_OUTDATA_LEN;                     //打包数据的长度uart_sendData(INSIDE, INSIDE_TX_BUFF,INSIDE_TX_LEN);   //发送data的数据memset(INSIDE_TX_BUFF,0,INSIDE_TX_LEN);								 //清除发送区数据INSIDE_TX_LEN=0;	memset(INSIDE_RX_BUFF,0,BUFF_LEN); 		//清除接收区数据INSIDE_RX_LEN=0;	memset(&loseHead,0,sizeof(loseHead)); //清除故障标志return;case LOSE_HEAD_MODE_WAIT:								//已经判断为头数据丢失if(CompareTimeBase(loseHead.Time,GetTickCount())>LOSE_HEAD_TIME_OUT){#ifdef DEBUG_433printf("[ERROR_433] loseHead time out\n");#endifloseHead.Mode=LOSE_HEAD_MODE_OUT;}return;																//超时等待主要是为了消除残留数据default:;																//无异常}switch(loseTail.Mode){case LOSE_TAIL_MODE_GET:case LOSE_TAIL_MODE_OUT:#ifdef DEBUG_433printf("[ERROR_433] loseTail.Mode :%d\n",loseTail.Mode);#endifmemset(INSIDE_TX_BUFF,0,BUFF_LEN); 		//清除发送区数据INSIDE_TX_LEN=0;		pack433Data(INSIDE_TX_BUFF,INSIDE_TX_LEN,PACK_FUNCTION_RESEND);//重新打包数据INSIDE_TX_LEN += PACK_OUTDATA_LEN;                     //打包数据的长度uart_sendData(INSIDE, INSIDE_TX_BUFF,INSIDE_TX_LEN);   //发送data的数据memset(INSIDE_TX_BUFF,0,INSIDE_TX_LEN);								 //清除发送区数据INSIDE_TX_LEN=0;	memset(INSIDE_RX_BUFF,0,BUFF_LEN); 		//清除接收区数据INSIDE_RX_LEN=0;	memset(&loseTail,0,sizeof(loseTail)); //清除故障标志return;case LOSE_TAIL_MODE_WAIT:								//已经判断为头数据丢失if(CompareTimeBase(loseTail.Time,GetTickCount())>LOSE_TAIL_TIME_OUT){#ifdef DEBUG_433printf("[ERROR_433] loseTail time out\n");#endifloseTail.Mode=LOSE_TAIL_MODE_OUT;}return;																//超时等待主要是为了消除残留数据default:;																//无异常}if(INSIDE_RX_LEN>=4)                      //接受长度包括了长度字节{len=0;len+=(INSIDE_RX_BUFF[2]<<8);   len+=(INSIDE_RX_BUFF[3]);               //获取应该接受的包长度if(INSIDE_RX_LEN>=len)                  //理论上完全接受了{if(INSIDE_RX_BUFF[len-2]==(PACK_END_DATA>>8)&&INSIDE_RX_BUFF[len-1]==(PACK_END_DATA&0xff) )																	    //包尾获取成功{add_queue_len=len-PACK_OUTDATA_LEN;	//获取data长度setDataFlag=1;											//正在载入串口数据OUTSIDE_TX_QUEUE_LEN+=add_queue_len;if(OUTSIDE_TX_QUEUE_LEN>=BUFF_LEN_O) {						//OUTSIDE_TX_QUEUE_LEN=BUFF_LEN;	OUTSIDE_TX_QUEUE_LEN-=add_queue_len;#ifdef DEBUG_433printf("[ERROR_433] Too late to outgoing,give up\n");#endif}else{for(i=0;i<add_queue_len;i++)      //中断发送数据{OUTSIDE_TX_BUFF[OUTSIDE_TX_END_LEN++]=INSIDE_RX_BUFF[PACK_OUTDATA_LEN-PACK_END_lEN+i];if(OUTSIDE_TX_END_LEN>=BUFF_LEN_O)      OUTSIDE_TX_END_LEN=0;	}}setDataFlag=0;											//串口数据载入完成if(outPutFlag==0)																			//如果没在对外输出则开启中断USART_ITConfig(OUTSIDE,USART_IT_TXE, ENABLE);				//获取数据完毕,开启中断进行发送		//					// 测试模式封存数据入缓存区域,原地返回
//						
//					for(i=0;i<add_queue_len;i++)
//					{
//						OUTSIDE_RX_BUFF[OUTSIDE_RX_LEN++]=INSIDE_RX_BUFF[PACK_OUTDATA_LEN-PACK_END_lEN+i];
//						if(OUTSIDE_RX_LEN>=BUFF_LEN_B)      
//							OUTSIDE_RX_LEN=0;	
//					}				
//					//overif(INSIDE_RX_LEN==len)															//数据获取完全{if(INSIDE_RX_BUFF[6]==PACK_FUNCTION_RESEND)				//数据需要重新发送{#ifdef DEBUG_433printf("[DEBUG_433] pack fail :[");for(i=0;i<len;i++)printf("%x ",INSIDE_RX_BUFF[i]);printf("] [end] \n");printf("[DEBUG_433] len :%x\n",len);#endifmemset(INSIDE_RX_BUFF,0,BUFF_LEN); 							//清除接收区数据INSIDE_RX_LEN=0;	e70_433_state=E70_STATE_LISTEN_E;								//解包反馈数据重发g_sysOutTime=GetTickCount();         						//更新存储的时间戳return;}memset(INSIDE_RX_BUFF,0,BUFF_LEN); 								//清除接收区数据INSIDE_RX_LEN=0;				e70_433_state=E70_STATE_LISTEN;       						//解包有效更新状态g_sysOutTime=GetTickCount();         							//更新存储的时间戳do{saveFrameToBUFF(OUTSIDE_RX_LEN,TRUE);						//强制封一帧	}while(frame_index_l==0);													//防止中断引起封帧失败	return;}else                                                //还有第二帧数据{for(i=0;i<INSIDE_RX_LEN-len;i++)INSIDE_RX_BUFF[i]=INSIDE_RX_BUFF[i+len];        //搬运数据INSIDE_RX_LEN=USART1_RX_LEN-len;#ifdef DEBUG_433printf("[DEBUG_433] another frame\n");#endif}}else{#ifdef DEBUG_433printf("[DEBUG_433] pack fail :[");for(i=0;i<len;i++)printf("%x ",INSIDE_RX_BUFF[i]);printf("] [end] \n");printf("[DEBUG_433] len :%x\n",len);#endif//长度达标,但是包尾数据判断异常loseTail.Mode=LOSE_TAIL_MODE_WAIT;									//置入数据丢失标志位loseTail.Time=GetTickCount();   										//载入当前系统时间	for(i=PACK_OUTDATA_LEN;i<INSIDE_RX_LEN;i++)					//审核包尾异常情况{if(INSIDE_RX_BUFF[i-2]==(PACK_END_DATA>>8)&&INSIDE_RX_BUFF[i-1]==(PACK_END_DATA&0xff))			//发现包尾{loseTail.Mode=LOSE_TAIL_MODE_GET;								//置入包尾获取标志位memset(INSIDE_RX_BUFF,0,BUFF_LEN); 							//清除接收区数据INSIDE_RX_LEN=0;return ;            }}}}else if(INSIDE_RX_BUFF[len-2]==(PACK_END_DATA>>8)&&INSIDE_RX_BUFF[len-1]==(PACK_END_DATA&0xff)&&INSIDE_RX_LEN<len){#ifdef DEBUG_433printf("[DEBUG_433] pack lose :[");for(i=0;i<INSIDE_RX_LEN;i++)printf("%x ",INSIDE_RX_BUFF[i]);printf("] [end] \n");printf("[DEBUG_433] len :%x,%x\n",len,INSIDE_RX_LEN);#endif//提前获取包数据,包长字段错误或者包中字段丢失loseTail.Mode=LOSE_TAIL_MODE_GET;										//置入包尾获取标志位memset(INSIDE_RX_BUFF,0,BUFF_LEN); 									//清除接收区数据INSIDE_RX_LEN=0;return;}			}}i=i;                                      //去除warn
}

代码解析

这一段可难了我写了1天多,希望大家能看懂
这一段代码主要实现3个功能
1,将接受缓存区域的数据按着包格式解包,
2,验证解包后数据的正确行,正确存入发送队列,错误则生成警报
3,当存在警报时,如果满足条件就立即封重发请求

数据正确的时候的注意事项
当数据正确后必然能够将数据封入对外发送队列,但是一定不能被中断影响了逻辑。并且发送缓存区域必须比接受缓存区域稍大一点(我就多给了1k)因为这样才能确保数据阻塞时不会溢出。(从代码调试注释里,应该能看出我吃的苦)
数据不正确时候的注意事项
如果能够进入这里进行数据判断,必然已经通过了包头检验,因此基本只有以下3种包错误情况:
包中段错误,包尾部错误,包长错误。
其中包长因为是一个判断依据因此,最终只会生成包中段或者包尾部错误。
这两种错误最终会有2种表现形式:
缺少尾部或者尾部提前出现
缺少尾部的错误我用超时判断作为为处理方案,生成警报
尾部提前出现我认为这一包应该是发送完成了,立即发出重发警报。
另外由于头部缺少和尾部缺少都是在接受时段产生的错误,因此我都在上述这个函数里进行实现。这样上述这个函数就会有3种主要运行形态:
头缺少
尾缺少
正在接受(或者刚好接受完成)

其中
头缺少状态由接受中断逻辑判断产生;
尾缺少状态由接受完成逻辑判断产生。

在我的测试和研究之下我发现433模组的绝大部分的传输失效都是出现字段丢失,比如12345变成1345,因此我没有再进一步设计包序号和包校验,如果后续这个项目还能进行下去我会补上这一段程序设计。

代码流程

为了方便读者理解这一段代码,我专门用语言描述一下这个函数模块的运行流程:

首先进入函数,
当接受区域有数据(头正常)或者警报有状态时进入运行区间:
{当警报为丢头时,进入警报状态分拣,{如果是超时或者有尾{立即发送回包请求重发;清除警报缓存}如果是等待判别{看一下是否超时}return;}当警报是丢尾时{//流程相同略}如果收区字段长度达到4(也可以是9,因为9是空包长度){获取包长字段如果收区字段长度达到包长字段{检验包尾,如果包尾正常{取出数据封入对外发送队列{清除多余数据强制封一个发送帧用于保证通讯不断裂}{如果有帧重叠,重新再解一次(无用的设计)}}如果包尾错误{查看是否有包尾在前面的字段有则警报获取包尾无则警报超时}}{如果提前获取包尾认为包错误,警报获取包尾}}
}

结语

本次程序设计还有2处没有设计:
1是通讯完全断裂的完善解决方案
2队列异常守护
当前对于通讯异常只要收到了2个以上的字节就能够重新建立连接,但是如果完全断开通讯就只有一个还未设计完善的重发机制,这部分我没有写在博客里因为还不够完善。
另外队列存贮通常有3个要素:1队列长度,2当前位置,3使用位置。我用队列长度做队列控制,但是在某种异常下,队列长度和位置会不协调导致数据残留。(例如中断,因此我重新设计了中断防御机制)为了运行稳定,应定时处理一下帧队列状态用于保护帧组稳定。
综上,如果有什么意见和建议欢迎留言指正,如果觉得还OK点个赞再走吧

附带

以上代码我从11月2号到11月14号编写完成,基本用时7天,其中主要的问题是在解决bug,这个bug是帧组异常导致的数据残留。我用了4天去解决bug,1天解决设计失误,1天设计方案,1天编写代码。我希望,看了这一篇博文的程序员,不要犯我的错误,不要让中断能够修改逻辑运算使用的数据变量,( ´・ω・)ノ(._.`)摸摸头
最后祝大家:
ヾヾ( ˘ ³˘人)ヾ做的全会٩(*Ӧ)و写的全对


http://chatgpt.dhexx.cn/article/gMs2NGBd.shtml

相关文章

计算机双工模式,100M 全双工、100M 半双工、10M全双工几种模式分别测试

1. 首先核实是否有多台电脑同时上网&#xff0c;或是当前电脑有没有在进行P2P下载或在线视频之类比较占用网络带宽的操作&#xff0c;此操作可能导致宽带数据量过大影响稳定性。若存在此情况&#xff0c;请关闭些软件断开些联网设备&#xff0c;减少带宽使用测试。 2. 若有其他…

Linux 查看网卡全双工 还是半双工 以及设置网卡为半双工

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴! 请问各位兄弟,在Linux中怎么看网卡是全双工工作还是半双工工作?mii-tool Linux:~ # mii…

路由之静态路由配置

一、路由概念 二、路由表的形成 三、路由协议 静态路由 路由器之间的连接需要配置静态路由 首先创建一个局域网&#xff0c;给pc0和pc1分别配置ip地址。 创建三个不同网段的局域网分别给电脑配置ip地址&#xff0c;将三个连接到一个路由上。为路由器与局域网相连的端口&#…

路由器静态路由配置实验

简单配置: 1.连接设备 2.配置PC和服务器的IP地址和网关 3.在路由器配置接口的IP地址(作为网关) 4.实现PC之间的通信 5.分别命名交换机和路由器,并设置时间 6.实现PC1可以telnet和ssh管理SW2和R1 7.配置静态路由实现全网互通 8.开启web服务器,在4台PC上测试是否能访问 实验…

静态路由配置实验

题目&#xff1a; 目录 1、首先进行基础配置 2、创建环回接口并配置IP地址 3、配置静态路由 对r1&#xff0c;要配置除自身连接的3个网段以外的5个网段 对r2&#xff0c;要配置除自身连接的3个网段以外的5个网段,其中3.3.3.0/24网段已配过&#xff0c;则配剩余4个网段 对r…

华为简单静态路由配置

今天通过学习路由交换的知识&#xff0c;学会了配置简单的静态路由&#xff0c;所以我这里介绍一个简单的实 验&#xff0c;在开始之前&#xff0c;我们要先了解一下什么是路由&#xff1f; 路由 路由是指导报文转发的路径信息&#xff0c;通过路由可以确认转发IP报文的路径。…

vue 3.0 静态路由配置

今天研究了一下vue3.0的静态路由配置&#xff0c;分享一下。 首先我们现在项目中建立router文件夹&#xff0c;如下图所示&#xff1a; 404文件夹存放404页面&#xff0c;components文件夹存放首页界面&#xff0c;config为设置文件夹&#xff0c;diz存放具体的业务逻辑和界面…

计算机配置静态路由目标,静态路由的配置命令

用户需求: 某学校网络拓扑图如图所示,要求配置静态路由,实现计算机PC1、PC2和PC3互通。 直连路由直连路由出现在路由表的条件 (1)接口为“up/up”状态。 (2)接口已经完成了IP地址的配置。直连路由的检查 静态路由是指由网络管理员手工配置的路由信息,用于定义去往目的网络的…

路由基础(简单的静态路由配置)

目录 一.路由基础 1.路由信息获取方式 2.路由加表前的比较-优先级&#xff1b;度量值 3.路由转发的选择-最长掩码 4.静态路由应用场景及配置 1.路由信息获取方式 路由器依据路由表进行转发&#xff0c;要实现转发功能&#xff0c;路由器需要发现路由&#xff0c;三种常见…

四种静态路由配置方法

拓扑图如下&#xff1a; 接口IP地址如拓扑图所示&#xff0c;配置过程省略&#xff0c;ar1和ar3都开启了dhcp。过程省略。 ar1的路由表&#xff1a; 此时只有直连的1.0和2.0网段的IP。没有3.0网段的。 那怎么有3.0网段的呢&#xff1f;接下来介绍四种方法。 方法一&#xff1a…

Windows系统的静态路由配置

Windows电脑静态路由的配置&#xff0c;使电脑同时使用两个不同网段的IP 操作方法&#xff1a; 1.开始菜单&#xff0c;输入cmd&#xff0c;右击cmd.exe&#xff0c;选择以管理员身份运行 2.查看当前路由的配置 命令格式&#xff1a; ##查看静态路由 route print 输出结果…

华为静态路由配置

静态路由 静态路由(Static Router)是由管理员通过手动配置的方式创建的路由&#xff0c;可以让路由器便捷的获知到达目的网络的路由。在静态路由基础上也可使用负载均衡、路由备份等技术。 本文分别对静态路由、负载均衡、路由备份进行实验配置及配置完之后如何验证。 网络拓…

ENSP静态路由配置

拓扑图 实现结果&#xff1a; 1.pc1访问pc345走上面R1,R2&#xff0c;R2实现备份21.1.1.0/24&#xff0c;实现备份pc3456访问pc12走下面的R3,R4并实现等价路由&#xff0c;尽量减少路由条目&#xff0c;全网可达 2.R7代表运行商&#xff0c;所有pc均可访问 第一步&#xff1a…

静态路由配置全面详解,静态路由快速入门指南

操作步骤 配置各路由器接口的IP地址 以配置Router_1的GE0/0/0接口为例&#xff0c;其他接口配置与之类似&#xff0c;不再重复介绍。 a、如图2所示&#xff0c;依次选择“广域网互联 > 以太接口”&#xff0c;进入“以太接口”界面。 图2 以太接口界面 b、在“以太接口列…

12 路由器静态路由配置

借鉴网址&#xff1a;(28条消息) Packet Tracer 思科模拟器入门教程 之十一 路由器静态路由配置_柚子君.的博客-CSDN博客_思科模拟器新手详细教程 姓 名 彭彭头 实验日期 2022.04.26 学 号 实验序号 12 实验名称 路由器静态路由配置 一、实验目的及要求 掌握静态路由…

静态路由配置案例

静态路由配置案例 配置静态路由原理命令&#xff1a;案例&#xff1a;最后结果&#xff1a; 配置静态路由原理命令&#xff1a; [Huawei]ip route-static 来源ip 子网掩码 去向ip [Huawei]ip route-static 192.168.20.1 255.255.255.0 192.168.1.2 案例&#xff1a; pc1,pc2…

ipv6 静态路由配置

ipv6 静态路由配置 R1 配置 <Huawei>system-view Enter system view, return user view with CtrlZ. [Huawei]sysname R1 [R1]ipv6 # 全局使能 ipv6 [R1]interface GigabitEthernet 0/0/0 [R1-GigabitEthernet0/0/0]ipv6 enable [R1-GigabitEthernet0/0/0]ipv6 add…

路由器静态路由配置

实验名称 路由器静态路由配置 一、实验目标 1.掌握静态路由的配置方法和技巧&#xff1b; 2.掌握通过静态路由方式实现网络的连通性&#xff1b; 3.熟悉广域网线缆的链接方式&#xff1b; 二、实验背景 学校有新旧两个校区&#xff0c;每个校区是一个独立的局域网&…

linux配置ipv6静态路由,IPv6静态路由配置

IPv6静态路由 命令: R1(config)#ipv6 unicast-routing //启用IPv6路由 R1(config-if)#ipv6 address 2010:1111::1/64 //手工配置IPv6地址 R1(config-if)#ipv6 address 2010:1111::1/64 eui-64 //自动配置IPv6地址 R1(config)#ipv6 route 2009:2323::/64 s0/0 //配置IPv6静态路…

路由器和静态路由的配置

目录 一、路由概述 二、静态路由和默认路由 三、配置静态路由 一、路由概述 路由&#xff1a;从源主机到目标主机的转发过程 路由器工作原理&#xff1a;根据路由表转发数据 二、静态路由和默认路由 1.静态路由 &#xff1a; 网络管理员手动配置将不知道的网段手动配置进路由…