RF4463F30半双工模组,伪全双工透传方案(STM32平台)(第二章,业务逻辑)

2023-10-26

前言

环境已经搭建完毕,接下来逐步移植模块

核心代码编写

宏定义和变量声明

相关宏定义

//通用移植
#define OUTSIDE 	 USART3
#define O_2_I_BUFF   USART3_RX_BUFF	  		//外部数据导入缓存
#define O_2_I_LEN	 USART3_RX_LEN			//外部数据当前缓存指针

#define I_2_O_BUFF   USART3_TX_BUFF			//内部数据对外发出缓存
#define I_2_O_LEN	 USART3_TX_LEN			//内部数据当前缓存指针

#define I_2_O_QUEUE_LEN  USART3_TX_QUEUE_LEN
#define I_2_O_END_LEN 	 USART3_TX_END_LEN

上面这部分是用于对接stm32平台

#define MasterFlag 					//主从机标志位,有这个标志位表示是主机(如果是从机则需要注释)

#define FRAME_CLUB_MAX        20                            //最大帧组队列长度
#define BUFF_LEN              100
#define BUFF_LEN_I            2000													//输入缓存区域
#define BUFF_LEN_O            3000													//输出缓存区域
#define BUFF_LEN_B            BUFF_LEN_I

上面这部分是用于划分存储空间

#define PACK_MAX_DATA_LEN 35      //设定433模组间发送最大数据长度

#define PACK_LEN_lEN       1      //设定包的长度字节长度
#define PACK_NUMBER_lEN    2      //设定包的序号字节长度
#define PACK_FUNCTION_lEN  1      //设定包的类别字节长度
#define PACK_CHECK_lEN  	 1     	//设定包的校验字节长度

#define MAX_PACK_NUMBER   0xfe    //设定包序号的最大值为0xfe

#define PACK_OUTDATA_LEN (PACK_LEN_lEN+\
														PACK_NUMBER_lEN+\
														PACK_FUNCTION_lEN+\
														PACK_CHECK_lEN)     
//设定433模组间除数据外的长度

#define PACK_MAX_LEN 		(PACK_OUTDATA_LEN + PACK_MAX_DATA_LEN)   
//设定433模组最大的数据长度

上面这部分是用于分配协议的字段
这部分可以自定义,我暂时是设计了4个字段,核心字段是长度和序号,其他都可有可无
但是我建议也基本按我这一套的设计走,至少包含:
长度,序号,功能码,校验

#define payload_length  				PACK_MAX_LEN+4 //44

#define freq_channel						0 

struct FlagType{
	unsigned char reach_1s						;	
	unsigned char is_tx							;
	unsigned char rf_reach_timeout				;
	unsigned char run							;
	unsigned char is_rx							;
};

上面这部分是用于声明通用的标志位的

相关变量定义

#define tdata {'s','w','w','x',\
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 \
	,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 \
	,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }
	
static unsigned char tx__data[220] = tdata ;
extern U8 rx_buf[100];

上面这部分是用于分配发送和接受缓存区域
长度和内容不重要,但是至少要大于等于发送长度,内存够用的话就暂时不必要优化一般可以把 220 替换成 payload_length

extern uint16_t frame_club[FRAME_CLUB_MAX+1][2]; //最大帧组 (新增的最后一位表示上一帧发送的数据)
extern __IO uint16_t frame_index_n;              //当前的帧序号
extern __IO uint16_t frame_index_s;              //准备发送的帧序号
extern __IO uint16_t frame_index_l;              //奇数表示还在接受,偶数表示等待接受
	

extern uint8_t O_2_I_BUFF[BUFF_LEN_I];   	
extern uint8_t I_2_O_BUFF[BUFF_LEN_O];		

extern uint16_t O_2_I_LEN;
extern uint16_t I_2_O_LEN;
extern uint16_t I_2_O_QUEUE_LEN;
extern uint16_t I_2_O_END_LEN;

extern __IO u32 g_sysUsartTime;
extern __IO u32 g_sysUsartTime_start;
extern __IO u32 g_buff_len;

extern __IO uint8_t saveFrameFlag;	

extern uint8_t 	INSIDE_TX_BUFF[PACK_MAX_LEN];			 //对内发送所需的临时缓存区域
extern uint16_t INSIDE_TX_LEN;										 //对内发送所需数据长度

extern __IO uint8_t outPutFlag;							   	 //对外输出标志位 
extern __IO uint8_t setDataFlag;							   //编辑串口数据标志位 

extern struct FlagType	Flag;

上面这部分是用于分配数据队列缓存区域
主要有两个队列:
帧队列 frame_club
对外输出队列 I_2_O_BUFF
其中帧队列 存储的是指针 数据还是放在这里 O_2_I_BUFF

到此为止,主要的全局变量和宏定义已经声明了,接下来就是实现功能的代码了

工具函数

两个主要的工具函数

//***********************************************************************
//将发送区数数据重新按着433私有协议个格式重新打包
//***********************************************************************
void pack433Data (u8 *pData,u16 len,u8 mode)
{
	u8 temporary[PACK_MAX_LEN] ={0};
	
		                                       //-存入帧长度
	temporary[0]=len;												 // 存入帧长度低字节
	
			                                     //-存入帧序号(——)还未启用
	temporary[1]=0; 											   // 存入帧序号高字节
	temporary[2]=0;  												 // 存入帧序号低字节
	
				                                   //-存入帧功能
	temporary[3]=mode; 											 // 存入帧功能
	
																					 //-存入校验
	temporary[4]=0;													 //	存入校验(——)还未启用
	
	memcpy(&temporary[5],pData,len);         //-存入帧数据
//																					 //-存入校验
//	temporary[7+len]=0-packSumCheck(temporary,9+len);//存入校验
	memcpy(pData,temporary,PACK_OUTDATA_LEN+len);//打包完成
}
//***********************************************************************
//将接收区数据重新按着帧格式封存
//***********************************************************************
//static u16 len=0;
void saveFrameToBUFF(u16 pointnNumber,u8 timeoutFlag)
{
	if(saveFrameFlag)                        //存帧标志位
		return;
	else
		saveFrameFlag=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;                       //帧长度加2
		if(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; //存入当前帧(起始帧)	1
		if(frame_index_n==frame_index_s)        //帧组出现覆盖
		{
			#ifdef DEBUG_433
				printf("[E] i=%d,l=%d\n",frame_index_s,frame_index_l);
			#endif
			frame_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_433
				printf("[E],2\n");
			#endif
			frame_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);
		#endif
		if(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_l>>1)>=FRAME_CLUB_MAX-2||
		 (frame_index_n==frame_index_s))        //帧组出现覆盖
		{
			#ifdef DEBUG_433
			//	printf("[E] i=%d,l=%d\n",frame_index_s,frame_index_l);
			#endif
			frame_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;
}

第一个函数是帧队列里的数据或者其他特殊数据,按着协议格式进行封装
第二个函数是将 O_2_I_BUFF 的缓存队列指针根据情况封入帧队列中。在这个函数里有一个关键的标志位: saveFrameFlag 用于防止被中断干扰队列。

功能函数

发送数据函数

void test_tx_data2(u8 *pdata)					
{	
	//delay_ms(1);
	Flag.is_tx = 1;
	Flag.run=0;
	fifo_reset();  
	m_spi_write_fifo(pdata); 				
	enable_tx_interrupt();	
	clr_interrupt();
	tx_start();
	rf_timeout = 0;
	Flag.rf_reach_timeout = 0;
	while(Flag.run!=2)					//等待发送成功
	{
		if(Flag.rf_reach_timeout)
		{
			printf("send data timeout\n");
			sdn_all_reset();			//
		}
	}
	Flag.run=0;	
	//clr_interrupt();
	
	Flag.is_tx=0;				  //转换为接收模式
	rx_init();					 	//接收模式初始化	
	Flag.run=0;	
}

发送数据,并且发送完成后自动转为接受模式,如果发送动作超时,则完全复位模块。

时间管理函数

//**************************************************
//函数名	:时间戳管理函数
//功能	:判断超时,管理标志位
//输入	:null
//输出	:null
//作者	:Bao
//**************************************************
void TIME_Process(void)
{
	u32 nowSysTime=0;
	nowSysTime= GetTickCount();					//获取当前时间戳
	if(CompareTimeBase(m_time.recevie_Time,nowSysTime)>RECEVICE_TIME_OUT)//接收间隔超时
	{
		Flag.is_tx=1;											//(简单操作)转换为发送模式
		m_test.Count++;										//记录错误次数		
		m_time.recevie_Time =nowSysTime;
		printf("time out,%d,%d,%d\n",m_time.recevie_Time,m_test.Count,m_test.Count2);
	}
}

主机用于判断是否出现接收超时,如果有则则转换为接受模式并且准备进行重连接

模块工作状态函数

//**************************************************
//函数名	:数据管理函数
//功能	:进行状态位切换
//输入	:null
//输出	:null
//作者	:Bao
//**************************************************
void SI4463_Process(void)						
{
	//--------------------数据收发--------------------
	if(Flag.is_tx)
	{
		test_tx_data2(tx__data);		//发送
	}
	else
	{
		//test_Receive2();						//接受
		receiveFramefrom433();			//数据接收	
	}
}

根据标志位选择数据的收发情况

将数据帧提取放入发送区的函数

//**************************************************
//函数名	:对内发送数据打包函数
//功能	:将缓存区域数据转移一部分进行封包,存入数据发送缓存区域中
//输入	:null
//输出	:null
//作者	:Bao
//**************************************************
void pack_O_2_I_Frame(void)
{
	uint16_t 	frame_head  = 0;
	uint16_t	frame_end   = 0;
	uint16_t  frame_rhead = 0;                //考虑到循环存储,因此把发送数据做个分段提取
	uint16_t  frame_rend  = 0; 
	uint16_t  i           = 0;  							//测试用序号

	do{
		saveFrameToBUFF(O_2_I_LEN,TRUE);				//强制封一帧	
	}
	while(frame_index_l==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++;                        //发送帧组序号进1
		if(frame_index_s>=FRAME_CLUB_MAX)
			frame_index_s=0;                      //发送帧序号复位
		
		//暂时不做帧组管理和相关校验 2019.10.15
		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_433
				printf("[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);
			#endif
			INSIDE_TX_LEN=PACK_MAX_DATA_LEN+20;        //临时处理长度错误问题
			memset(INSIDE_TX_BUFF,0,INSIDE_TX_LEN); //清除发送区数据
		}
		else
		{
			memcpy(&INSIDE_TX_BUFF[0],
				&O_2_I_BUFF[frame_head],
				frame_rhead-frame_head);              //复制第一段数据
			memcpy(&INSIDE_TX_BUFF[frame_rhead-frame_head],
				&O_2_I_BUFF[frame_rend],
				frame_end-frame_rend);						    //复制第二段数据
		}
		
		#ifdef DEBUG_433
			printf("%2d,%3d\n",INSIDE_TX_LEN,frame_index_l);
		#endif
		
		pack433Data(INSIDE_TX_BUFF,INSIDE_TX_LEN,PACK_FUNCTION_DATA);//重新打包数据
		INSIDE_TX_LEN += PACK_OUTDATA_LEN;                //打包数据的长度
		
		//test
		memcpy(&tx__data[4],INSIDE_TX_BUFF,PACK_MAX_LEN);	//转移数据	
		
		memset(INSIDE_TX_BUFF,0,PACK_MAX_LEN); 						//清除发送缓存区数据
		INSIDE_TX_LEN=0;			
	}
	i = i;                                    //去除编译的warning,无意义
}

这部分移植了E70 半双工方案里的读取帧的部分。
主业务流程为:
确保帧队列里有帧,然后把最老的帧提取出来,根据头和尾的指针位置,复制这一段数据到发送缓存区域

接收数据函数

//**************************************************
//函数名	:获取来自于433模块的帧数据
//功能	:将获取的帧数据进行解包转发操作
//输入	:null
//输出	:null
//作者	:Bao
//**************************************************
void receiveFramefrom433 (void)             	//获取433模组的数据
{
	if(Flag.run==2)
	{ 
		Flag.run=0;
		clr_interrupt();   															// clear interrupt	
		if((spi_read_buf[4] &0x08) == 0)  							// crc error check
		{
			spi_read_fifo();
			fifo_reset();
			m_test.Count2++;
			Flag.is_rx=1;																	//接收动作喂狗
			
			unpackFrame();																//解包函数
			
			m_time.recevie_Time=GetTickCount();
			//printf(",%d,%d,%d\n",m_time.recevie_Time,m_test.Count,m_test.Count2);
			
			Flag.is_tx=1;																	//转换为发送模式
		}
		else
		{
			printf("---------------crc error-------------\n");
			
			packSpecialFrame(PACK_FUNCTION_RESEND);				//封包:请求重发
			
			Flag.is_tx=1;																	//转换为发送模式
		}		
	}
	i=i;	
}

接受数据,如果正确接受则对数据包进行解包,如果不正确接受,则一帧特殊数据包到发送区域。

解包函数

//**************************************************
//函数名	:对于帧进行解包
//功能	:对于帧数据进行解包处理
//输入	:null
//输出	:null
//作者	:Bao
//**************************************************
void unpackFrame (void)	  										 	//解包函数
{
	u16 len						=0;
	u16 number				=0;
	u16 function 			=0;
	u16 check					=0;
	u8 dataBuff[PACK_MAX_LEN]={0};								//划分缓存区域
	
	u16 add_queue_len=0;													//数据队列新增
	
	memcpy(dataBuff,&rx_buf[4],PACK_MAX_LEN); 		//读取数据
	len 			= 	dataBuff[0];										//获取帧长度
	number 		= 	(dataBuff[1]<<8)+dataBuff[2]; 	//获取帧序号	//暂时未启用
	function	= 	dataBuff[3];										//获取帧功能
	check 		= 	dataBuff[4];										//获取帧校验
	
	number = number;
	check  = check;
	switch(function)															//根据帧功能进行分拣
	{
		case PACK_FUNCTION_RESEND:									//数据需要重新发送
			//空操作
			//发送组里的数据不会因为发送而改变
			//因此重新只需要重新进入发送姿态即可
			break;	
		case PACK_FUNCTION_DATA:
			add_queue_len=len ;
			setDataFlag=1;														//正在载入串口数据
			I_2_O_QUEUE_LEN+=add_queue_len;						//对外输出队列加长 (公共数据,线程锁包含)
			setDataFlag=0;														//串口数据载入完成

			if(I_2_O_QUEUE_LEN>=BUFF_LEN_O) 
			{						
				I_2_O_QUEUE_LEN=add_queue_len;
				#ifdef DEBUG_433
					printf("[ERROR_433] Too late to outgoing,give up\n");
				#endif
			}
			else
			{
				for(i=0;i<add_queue_len;i++)      					//中断发送数据
				{
					I_2_O_BUFF[I_2_O_END_LEN++]=dataBuff[i+PACK_OUTDATA_LEN];
					if(I_2_O_END_LEN>=BUFF_LEN_O)      
						I_2_O_END_LEN=0;	
				}
			}
			#ifdef DEBUG_433
				printf("T,%d,%d,%d\n",I_2_O_LEN,I_2_O_QUEUE_LEN,I_2_O_END_LEN);
			#endif
			if(outPutFlag==0)																			//如果没在对外输出则开启中断
				USART_ITConfig(OUTSIDE,USART_IT_TXE, ENABLE);				//获取数据完毕,开启中断进行发送		
			pack_O_2_I_Frame();														//向4463模块发送区封入数据帧
			break;
		case PACK_FUNCTION_START:												//如果功能码字段为空表示此包是启动包(临时处理)
			#ifdef DEBUG_433
					printf("[ERROR_433] pack function == 0\n");
			#endif
			packSpecialFrame (PACK_FUNCTION_DATA);				//临时处理
			break;
		default:;		
	}
}	

业务逻辑如下
获取数据包的功能字节段,
根据长度字节段搬运数据。
根据功能字节段选择合适的执行动作

其中如果是重新回包请求,则无视,如果是正常数据包,则把数据转移到对外发送队列里,修改相关参数,这里有一个关键点:setDataFlag 同样是为了不让中断影响队列。

特殊功能封包函数

//**************************************************
//函数名	:打包特殊功能的数据帧
//功能	:打包特殊功能的空数据帧
//输入	:null
//输出	:null
//作者	:Bao
//**************************************************
void packSpecialFrame (u8 function)
{
	memset(INSIDE_TX_BUFF,0,PACK_MAX_LEN); 								 //清除缓存区域数据
	INSIDE_TX_LEN=0;		
	pack433Data(INSIDE_TX_BUFF,INSIDE_TX_LEN,function);		 //重新打包数据
	INSIDE_TX_LEN += PACK_OUTDATA_LEN;                     //打包数据的长度
	//test 
	memcpy(&tx__data[4],INSIDE_TX_BUFF,INSIDE_TX_LEN);		 //转移数据	
}

用于特殊情况下不进行数据通讯时,封印专用的功能包,并放入发送缓存区域。

外侧数据处理函数(串口中断)

void USART3_IRQHandler(void)  //串口3中断  
{
	u8 res;
	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(I_2_O_QUEUE_LEN>0)                      	//队列里有数据
		{
			I_2_O_QUEUE_LEN--;               					//队列长度减1
			USART_SendData(OUTSIDE, I_2_O_BUFF[I_2_O_LEN++]);//send
			if(I_2_O_LEN>=BUFF_LEN_O)      
				I_2_O_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(OUTSIDE,USART_IT_RXNE)) //收到一个字就立刻发送
	{
		res= USART_ReceiveData(OUTSIDE); 
		
		//USART_SendData(USART1,res);  //2转1
//		USART_SendData(USART3,res);  //转3
		
		O_2_I_BUFF[O_2_I_LEN++]=res; 					  		//存入收区
		if(O_2_I_LEN>=BUFF_LEN_I)      
			O_2_I_LEN=0;			
		saveFrameToBUFF(O_2_I_LEN,FALSE);						//封帧
	}
}

主函数基础操作

		//read_Version();  	//读版本号测试
		TIME_Process();			//超时判别
		SI4463_Process();		//业务逻辑

代码写的好就是主页面就是这么简洁┗( ▔, ▔ )┛

结语

这个方案,我经过测试,发现稳定性很好,但是速度不是很满意。我调出单向最快空速9KB的时候,双向空速近似是2KB 所以后续代码和结构以及一些优化我就放弃制作了。如果有这方面的开发的问题可以问我。我目前研究了E70伪全双工,E62全双工,双E70全双工,4463伪全双工,下一步是双4463 全双工。
也欢迎大佬来讨论远距离双向传输方案。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RF4463F30半双工模组,伪全双工透传方案(STM32平台)(第二章,业务逻辑) 的相关文章

  • 统计学——卡方检验和卡方分布

    什么是卡方检验 卡方检验是一种用途很广的计数资料的假设检验方法 它属于非参数检验的范畴 主要是比较两个及两个以上样本率 构成比 以及两个分类变量的关联性分析 其根本思想就是在于比较理论频数和实际频数的吻合程度或拟合优度问题 它在分类资料统计
  • 目标检测标注原则

    算力和数据是影响深度学习应用效果的两个关键因素 在算力满足条件的情况下 为了到达更好的效果 我们需要将海量 高质量的素材数据喂给神经网络 训练出高精度的网络模型 吴恩达在深度学习公开课中提到 在算力满足要求的前提下 模型效果会随着素材数量的
  • vue事件绑定、事件参数、事件修饰符、表单双向绑定、监听器、计算属性

    目录 事件绑定 事件参数 事件修饰符 表单 watch 监听器 监听属性 computed 计算属性 面试题 事件机制 概述 在dom阶段 我们已经讲述了事件机制的特点 事件三要素 事件绑定 事件流 事件对象 事件代理 事件类型 这些概念在
  • ISAKMP - 安全关联协商

    前面说过 ISAKMP主要有三个过程 SA协商 密钥交换和认证 本篇主要讨论SA协商 首先要明白一个问题 为什么需要协商 为什么协议不规定使用某种特定的算法 这样实现上可以变得简单很多 要回答这个问题 我们必须全面的审视网络通信的环境 所有

随机推荐

  • Redis中常用命令:基本+五种基本类型(string、list、hash、set、zset)+三种特殊类型(geospatial、hyperloglog、bitmap)

    redis的命令有很多 命令不区分大小写 如下是一些常用的命令 可以通过官网 命令来学习使用更多的命令 例如 1 基本命令 选择数据库select 编号 redis默认的数据库有16个 编号从0 15 默认使用0号数据库 在配置文件中可查看
  • Elasticsearch(三)使用 Kibana 操作 ES

    文章目录 下载 Kibana 镜像 启动 Kibana 容器 索引 分片和副本 索引 索引分片 索引副本 创建索引 映射 数据结构 字段的数据类型 创建映射 查看映射 添加文档 删除文档 删除索引 下载 Kibana 镜像 docker p
  • Deep Java Library(DJL)上手指南

    Deep Java Library DJL https djl ai 是一个Java语言编写的深度学习库 平台 支持各种已有的模型直接导入 受益于Java的跨平台和高性能 相对Python DJL可以很容易部署和高效率运行 尤其是推理 首先
  • uc3842改可调电源教程_《学习笔记》--DC/DC电源电路设计实例

    1 设计概述 利用LTC3704实现3 3V 1 5V的转换 最大输出电流1A LTC3704是一款支持正向电源电压转换为负向电源电压的DC DC电源芯片 支持的输入端电源电压范围是2 5V 36V 输出端电源电压可调 2 引脚介绍 VIN
  • 若依前端后端框架 分离切换用户问题解决!学不会得找我!!!

    笔者最近遇到一个问题 就是有主账号一个字段 有多个从账号 基于这个目的用户表登录名是从账号得登录名 而有一个字段为主账号 识别是这个人 若依前后端 看了官网 都是用userName去鉴权 然后生成token和JWT数据 所有userName
  • todolist 案例 JavaScript

    css样式 body margin 0 padding 0 font size 16px background CDCDCD header height 50px background 333 background rgba 47 47 4
  • VUE 巧用$attrs和inheritAttrs提高组件的可扩展性

    VUE 巧用 attrs和inheritAttrs提高组件的可扩展性 前言 在平时创建组件时 一般使用的是利用props传值 然后通过传入的值再赋给标签的方式 来控制组件里的 这种方法在使用时的可扩展性不大 很难通过外部来动态的往组件内部添
  • java学习笔记(第7天:形参和返回值)

    目录 一 形参和返回值都是基本类型 二 类名作为形参和返回值 三 抽象类作为形参和返回值 四 接口作为形参和返回值 一 形参和返回值都是基本类型 这里比较简单 放一个不确定参数数量的例子玩玩 package Demo public clas
  • 关于Unity游戏开发场景切换:Time.timeScale的捣乱

    在制作场景切换功能的时候 我用的是SceneManager LoadScene函数 从主界面场景切换到关卡1场景 从关卡1场景切换到关卡2场景都是没有问题的 但是 当我在点击Pause按钮来到暂停界面 点击Back Menu按钮准备回到主界
  • LR和线性回归的区别与联系

    区别 区别 线性回归 liner regression LR logistics regression 构建方法 最小二乘法 似然函数 解决问题 主要解决回归问题 也可以用来分类 但是鲁棒性差 解决分类问题 输出 输出实数域上连续值 输出值
  • 在#define中使用参数

    在 define中使用参数 在 define中使用参数可以创建外形和作用与函数类似的类函数宏 例如 define SQUARE X X X 在程序中可以这样用 z SQUARE 2 这看上去像函数调用 但它的行为与函数调用完全不同 预处理器
  • 网关Gateway-快速上手

    gateway网关官方文档 https docs spring io spring cloud gateway docs current reference html 网关的概念 网关作为流量的入口 常用的功能包括路由转发 权限校验 限流等
  • 单片机:按键(使用中断)控制数码管的数字加减(c语言实现)

    本实验的目的 使用中断实现通过编号为8和C的按键控制数码管数字的加减 加至15之后再循环到0 减到0之后保持0不变 include
  • Python Django项目URL中包含另外一个urls模块

    在我们的项目中 不可能只有一个app 如果把所有的app的views中的视图都放在urls py中进行映射 肯定会让代码显得非常乱 因此django给我们提供了一个方法 可以在app内部包含自己的url匹配规则 而在项目的urls py中再
  • win11 设置系统环境变量

    由于win11的设置面板大变样 一时之间找不到高级设置进入系统环境变量的设置 面对这个问题可以这样 1 按win键 在搜索中输入 编辑系统环境变量 如图
  • 线程同步与线程安全

    1线程同步 同步 多线程访问临界资源时 必须进行同步控制 多进程或者多线程的执行并不完全是绝对的并行运行 又可能主线程需要等待函数线程的某些条件的发生 多线程的临界资源有全局数据 堆区数据 文件描述符 同步控制方式 1 1信号量 需要用到头
  • git repo工具介绍引入

    一 repo是什么 是什么 Repo是基于git的仓库管理工具 是一个python脚本 干什么 Repo用于同时管理多个git仓库 可以做统一的上传下载等操作 二 repo使用相关语法介绍 2 1 要使用repo首先需要有 manifest
  • iOS 捷径大全

    iOS 捷径大全 一 实用工具 支付助手3 0 新 微博热搜榜 新浪微博 网购历史价格查询3 0 小火箭 新 支付宝红包 新 任天堂红白机小游戏 你不会自己百度么 上朝网易云 早上好 晚安 天气预报 系统自带 捷径2 1 0 报时语音天气
  • JS数组去重之利用set数据结构去重

    在常用的JS去重方法中 都是通过循环遍历来去重 难免麻烦了不少 这边发现ES6中有更加方便的去重方式 记录一下 1 set数据结构 ES6提供了新的数据结构Set 类似于数组 只不过其成员值都是唯一的 没有重复的值 这边就是利用set没有重
  • RF4463F30半双工模组,伪全双工透传方案(STM32平台)(第二章,业务逻辑)

    RF4463F30半双工模组 伪全双工透传方案 STM32平台 第二章 业务逻辑 前言 核心代码编写 宏定义和变量声明 工具函数 功能函数 发送数据函数 时间管理函数 模块工作状态函数 将数据帧提取放入发送区的函数 接收数据函数 解包函数