STM32F4 | SYSTEM文件夹介绍 | delay文件夹 | sys文件夹 | usart文件夹

news2025/1/15 17:22:04

文章目录

    • 一、delay 文件夹代码介绍
      • 1.delay_init 函数
      • 2.delay_us 函数
      • 3.delay_ms函数
    • 二、sys 文件夹代码介绍
      • 1.IO 口的位操作实现
    • 三、usart 文件夹代码介绍
      • 1.printf 函数支持

  在 新建工程模板——库函数版本中,我们用到了一个 SYSTEM 文件夹里面的代码,此文件夹里面的代码由 ALIENTEK 提供,是 STM32F4xx 系列的底层核心驱动函数,可以用在 STM32F4xx 系列的各个型号上面,方便大家快速构建自己的工程。 SYSTEM 文件夹下包含了 delaysysusart 等三个文件夹。分别包含了 delay.csys.cusart.c及其头文件。

一、delay 文件夹代码介绍

  delay 文件夹内包含了 delay.cdelay.h 两个文件,这两个文件用来实现系统的延时功能,其中包含 7 个函数:

  • void delay_osschedlock(void);
  • void delay_osschedunlock(void);
  • void delay_ostimedly(u32 ticks);
  • void SysTick_Handler(void);
  • void delay_init(u8 SYSCLK);
  • void delay_ms(u16 nms);
  • void delay_us(u32 nus);

  在介绍这些函数之前,我们先了解一下编程思想:CM4 内核的处理和 CM3 一样,内部都包含了一个 SysTick 定时器,SysTick 是一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD寄存器中自动重装载定时初值。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。我们就是利用 STM32的内部 SysTick来实现延时的,这样既不占用中断,也不占用系统定时器。
  这里,我们以 UCOSII 为例,介绍如何实现操作系统和我们的 delay 函数共用 SysTick 定时器。首先,我们简单介绍下 UCOSII 的时钟:ucos 运行需要一个系统时钟节拍(类似 “心跳”),而这个节拍是固定的(由 OS_TICKS_PER_SEC 宏定义设置),比如要求 5ms 一次(即可设置:OS_TICKS_PER_SEC=200),在 STM32 上面,一般是由 SysTick 来提供这个节拍,也就是 SysTick要设置为 5ms 中断一次,为 ucos 提供时钟节拍,而且这个时钟一般是不能被打断的(否则就不准了)。
  因为在 ucossystick 不能再被随意更改,如果我们还想利用 systick 来做 delay_us 或者delay_ms 的延时,就必须想点办法了,这里我们利用的是时钟摘取法。以 delay_us 为例,比如:delay_us(50),在刚进入 delay_us 的时候先计算好这段延时需要等待的 systick 计数次数,这里为 50*180(假设系统时钟为 180Mhz,因为我们设置 systick 的频率为系统时钟频率,那么 systick每增加 1,就是 1/180us),然后我们就一直统计 systick 的计数变化,直到这个值变化了 50*180,一旦检测到变化达到或者超过这个值,就说明延时 50us 时间到了。这样,我们只是抓取 SysTick计数器的变化,并不需要修改 SysTick 的任何状态,完全不影响 SysTick 作为 UCOS 时钟节拍的功能,这就是实现 delay 和操作系统共用 SysTick 定时器的原理。

1.delay_init 函数

  该函数用来初始化 2 个重要参数:fac_us 以及 fac_ms;同时把 SysTick 的时钟源选择为外部时钟,如果需要支持操作系统(OS),只需要在 sys.h 里面,设置 SYSTEM_SUPPORT_OS 宏的值为 1 即可,然后,该函数会根据delay_ostickspersec 宏的设置,来配置 SysTick 的中断时间,并开启 SysTick中断。具体代码如下:

//初始化延迟函数
//当使用ucos的时候,此函数会初始化ucos的时钟节拍
//SYSTICK的时钟固定为AHB时钟
//SYSCLK:系统时钟频率
void delay_init(u8 SYSCLK)
{
#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
	u32 reload;
#endif
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLK
	fac_us=SYSCLK;						//不论是否使用OS,fac_us都需要使用
#if SYSTEM_SUPPORT_OS 						//如果需要支持OS.
	reload=SYSCLK;					    //每秒钟的计数次数 单位为K	   
	reload*=1000000/delay_ostickspersec;	//根据delay_ostickspersec设定溢出时间
											//reload为24位寄存器,最大值:16777216,在180M下,约合0.745s左右	
	fac_ms=1000/delay_ostickspersec;		//代表OS可以延时的最少单位	   
	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断
	SysTick->LOAD=reload; 					//每1/OS_TICKS_PER_SEC秒中断一次	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
#endif
}

可以看到,delay_init 函数使用了条件编译,来选择不同的初始化过程,如果不使用 OS 的时候,只是设置一下 SysTick 的时钟源以及确定 fac_us 值。而如果使用 OS 的时候,则会进行一些不同的配置,这里的条件编译是根据SYSTEM_SUPPORT_OS这个宏来确定的,该宏在sys.h里面定义。SysTickMDK 定义了的一个结构体,里面包含 CTRLLOADVALCALIB 等 4 个寄存器,

/**
  \brief  Structure type to access the System Timer (SysTick).
 */
typedef struct
{
  __IOM uint32_t CTRL;                   /*!< Offset: 0x000 (R/W)  SysTick Control and Status Register */
  __IOM uint32_t LOAD;                   /*!< Offset: 0x004 (R/W)  SysTick Reload Value Register */
  __IOM uint32_t VAL;                    /*!< Offset: 0x008 (R/W)  SysTick Current Value Register */
  __IM  uint32_t CALIB;                  /*!< Offset: 0x00C (R/ )  SysTick Calibration Register */
} SysTick_Type;

  CTRLSysTick控制和状态寄存器。SysTick->CTRL 的各位定义如图所示:
在这里插入图片描述
  LOADSysTick自动重装载除值寄存器。SysTick-> LOAD 的定义如图所示:
在这里插入图片描述
  VALSysTick当前值寄存器。SysTick-> VAL 的定义如图所示:
在这里插入图片描述
  CALIBSysTick校准值寄存器。SysTick-> CALIB 不常用,在这里我们也用不到,故不介绍了。
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);这句代码把 SysTick 的时钟选择为内核时钟,这里需要注意的是:SysTick 的时钟源自 HCLK,假设我们外部晶振为 25M,然后倍频到 180MHZ,那么 SysTick 的时钟即为 180Mhz,也就是 SysTick 的计数器 VAL 每减 1,就代表时间过了 1/180us。所以fac_us=SYSCLK;这句话就是计算在 SYSCLK 时钟频率下延时 1us需要多少个 SysTick 时钟周期。
  在不使用 OS 的时候:fac_usus 延时的基数,也就是延时 1usSystick 定时器需要走过的时钟周期数。 当使用 OS 的时候,fac_us,还是 us 延时的基数,不过这个值不会被写到SysTick->LOAD 寄存器来实现延时,而是通过时钟摘取的办法实现的。而fac_ms 则代表 ucos 自带的延时函数所能实现的最小延时时间(如 delay_ostickspersec=200,那么 fac_ms 就是 5ms)。

2.delay_us 函数

  该函数用来延时指定的 us,其参数 nus 为要延时的微秒数。该函数有使用 OS 和不使用 OS两个版本,这里我们首先介绍不使用 OS 的时候,实现函数如下:

//延时nus
//nus为要延时的us数.	
//nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)	 
void delay_us(u32 nus)
{		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;				//LOAD的值	    	 
	ticks=nus*fac_us; 						//需要的节拍数 
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	}
}

这里就正是利用了我们前面提到的时钟摘取法,ticks 是延时 nus 需要等待的 SysTick 计数次数(也就是延时时间),told 用于记录最近一次的 SysTick->VAL 值,然后 tnow 则是当前的SysTick->VAL 值,通过他们的对比累加,实现 SysTick 计数次数的统计,统计值存放在 tcnt 里面,然后通过对比 tcntticks,来判断延时是否到达,从而达到不修改 SysTick 实现 nus 的延时。
  对于使用 OS 的时候,delay_us 的实现函数和不使用 OS 的时候方法类似,都是使用的时钟摘取法,只不过使用 delay_osschedlockdelay_osschedunlock 两个函数,用于调度上锁和解锁,这是为了防止 OSdelay_us 的时候打断延时,可能导致的延时不准,所以我们利用这两个函数来实现免打断,从而保证延时精度。

//延时nus
//nus:要延时的us数.	
//nus:0~190887435(最大值即2^32/fac_us@fac_us=22.5)	    								   
void delay_us(u32 nus)
{		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;				//LOAD的值	    	 
	ticks=nus*fac_us; 						//需要的节拍数 
	delay_osschedlock();					//阻止OS调度,防止打断us延时
	told=SysTick->VAL;        				//刚进入时的计数器值
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;	//这里注意一下SYSTICK是一个递减的计数器就可以了.
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;			//时间超过/等于要延迟的时间,则退出.
		}  
	};
	delay_osschedunlock();					//恢复OS调度											    
}  

3.delay_ms函数

  该函数是用来延时指定的 ms 的,其参数 nms 为要延时的毫秒数。该函数有使用 OS 和不
使用 OS 两个版本,这里我们分别介绍,首先是不使用 OS 的时候,实现函数如下:

//延时nms
//nms:要延时的ms数
void delay_ms(u16 nms)
{
	u32 i;
	for(i=0;i<nms;i++) delay_us(1000);
}

该函数其实就是多次调用前面所讲的 delay_us 函数,来实现毫秒级延时的。
  再来看看使用 OS 的时候,delay_ms 的实现函数如下:

//延时nms
//nms:要延时的ms数
//nms:0~65535
void delay_ms(u16 nms)
{	
	if(delay_osrunning&&delay_osintnesting==0)//如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)	    
	{		 
		if(nms>=fac_ms)						//延时的时间大于OS的最少时间周期 
		{ 
   			delay_ostimedly(nms/fac_ms);	//OS延时
		}
		nms%=fac_ms;						//OS已经无法提供这么小的延时了,采用普通方式延时    
	}
	delay_us((u32)(nms*1000));				//普通方式延时
}

  该函数中,delay_osrunningOS 正在运行的标志,delay_osintnesting 则是 OS 中断嵌套次数,必须 delay_osrunning 为真,且 delay_osintnesting 为 0 的时候,才可以调用 OS 自带的延时函数进行延时(可以进行任务调度),delay_ostimedly 函数就是利用 OS 自带的延时函数,实现任务级延时的,其参数代表延时的时钟节拍数(假设 delay_ostickspersec=200 ,那么delay_ostimedly (1),就代表延时 5ms)。
  当 OS 还未运行的时候,我们的 delay_ms 就是直接由 delay_us 实现的,OS 下的 delay_us可以实现很长的延时(达到 204 秒)而不溢出!,所以放心的使用 delay_us 来实现 delay_ms,不过由于 delay_us 的时候,任务调度被上锁了,所以还是建议不要用 delay_us 来延时很长的时间,否则影响整个系统的性能。
  当 OS 运行的时候,我们的 delay_ms 函数将先判断延时时长是否大于等于 1 个 OS 时钟节拍fac_ms,当大于这个值的时候,我们就通过调用 OS 的延时函数来实现(此时任务可以调度),不足 1 个时钟节拍的时候,直接调用 delay_us 函数实现(此时任务无法调度)。

二、sys 文件夹代码介绍

  sys 文件夹内包含了 sys.csys.h 两个文件。在 sys.h 里面定义了 STM32F4IO 口位
操作输入读取宏定义和输出宏定义以及类型别名。sys.c 里面除了定义时钟系统配置函数Stm32_Clock_Init 外主要是一些汇编函数。本小节我们主要向大家介绍 sys.h 头文件里面的 IO 口位操作。

1.IO 口的位操作实现

  该部分代码在 sys.h 文件中,实现对STM32F4 各个 IO 口的位操作,包括读入和输出。
当然在这些函数调用之前,必须先进行 IO 口时钟的使能和 IO 口功能定义。此部分仅仅对IO 口进行输入输出读取和控制。
  位带操作简单的说,就是把每个比特膨胀为一个 32 位的字,当访问这些字的时候就达到了访问比特的目的,比如说 GPIOODR 寄存器有 32 个位,那么可以映射到 32 个地址上,我们去访问这 32 个地址就达到访问 32 个比特的目的。这样我们往某个地址写 1 就达到往对应比特位写 1 的目的,同样往某个地址写 0 就达到往对应的比特位写 0 的目的。
在这里插入图片描述
  对于上图,我们往 Address0 地址写入 1,那么就可以达到往寄存器的第 0 位 Bit0 赋值1 的目的。下面我们看看 sys.h 中位带操作的定义,代码如下:

//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).M4同M3类似,只是寄存器地址变了.
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014 
#define GPIOJ_ODR_ADDr    (GPIOJ_BASE+20) //0x40022414
#define GPIOK_ODR_ADDr    (GPIOK_BASE+20) //0x40022814

#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
#define GPIOJ_IDR_Addr    (GPIOJ_BASE+16) //0x40022410 
#define GPIOK_IDR_Addr    (GPIOK_BASE+16) //0x40022810 

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入 

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出 
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出 
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出 
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

#define PJout(n)   BIT_ADDR(GPIOJ_ODR_Addr,n)  //输出 
#define PJin(n)    BIT_ADDR(GPIOJ_IDR_Addr,n)  //输入

#define PKout(n)   BIT_ADDR(GPIOK_ODR_Addr,n)  //输出 
#define PKin(n)    BIT_ADDR(GPIOK_IDR_Addr,n)  //输入

以上代码的便是 GPIO 位带操作的具体实现。比如说,我们调用 PAout(1)=1是设置了 GPIOA 的第一个管脚 GPIOA.1 为 1,实际是设置了寄存器的某个位,但是我们的定义中可以跟踪过去看到却是通过计算访问了一个地址。上面一系列公式也就是计算GPIO 的某个 IO 口对应的位带区的地址了。
  有了上面的代码,我们就可以像51一样操作STM32IO口了。比如,我要PORTA的第七个 IO 口输出 1,则可以使用 PAout(6)=1;即可实现。我要判断 PORTA 的第 15个位是否等于 1,则可以使用 if(PAin(14)==1)…;就可以了。
  这里顺便说一下,在 sys.h 中的还有个全局宏定义:

//0,不支持os
//1,支持os
#define SYSTEM_SUPPORT_OS		0		//定义系统文件夹是否支持OS

SYSTEM_SUPPORT_OS,这个宏定义用来定义 SYSTEM 文件夹是否支持 ucos,如果在 ucos 下面使用 SYSTEM 文件夹,那么设置这个值为 1 即可,否则设置为 0(默认)。

三、usart 文件夹代码介绍

  该文件夹下面有 usart.cusarts.h 两个文件。串口相关知识将在串口实验中讲解。

1.printf 函数支持

  printf 函数支持的代码在 usart.c 文件的最上方,在我们初始化和使能串口 1 之后,然后把这段代码加入到工程,便可以通过 printf 函数向串口 1 发送我们需要的内容,方便开发过程中查看代码执行情况以及一些变量值。这段代码如果要修改一般也只是用来改变printf 函数针对的串口号,大多情况我们都不需要修改。代码如下:

//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
//#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)	
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{ 	
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
	USART1->DR = (u8) ch;      
	return ch;
}
#endif 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/85633.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于java+springboot+mybatis+vue+mysql的智慧养老平台

项目介绍 随着社会的发展我国的人口老龄化严重&#xff0c;为了让这些在年前是给社会做出过贡献的老人老有所依&#xff0c;老有所养&#xff0c;度过一个安详的晚年&#xff0c;很多地方都实现了智慧养老&#xff0c;为此我们通过springbootvueelementUI 开发了本次基于java的…

1.用Python写了一个进销存管理的软件~需求分析界面设计数据库设计技术路线选择~

一、需求分析 总体来说&#xff0c;就是一个在游泳馆使用的进销存管理软件&#xff0c;记录商品的入库、出库情况&#xff0c;以及统计销售的金额等~ 整个系统有三类用户&#xff0c;系统管理员、公司管理员和公司销售员&#xff0c;系统管理员负责录入公司信息以及分配用户&…

ActiveMQ、RabbitMQ、RocketMQ、Kafka区别

1、4种消息中间件比较 特性ActiveMQRabbitMQRocketMQKafka开发语⾔javaerlangjavascala单机吞吐量万级万级10万级10万级时效性ms级us级ms级ms级以内可⽤性⾼(主从架构)⾼(主从架构)⾮常⾼(分布式架构)⾮常⾼(分布式架构)功能特性 成熟的产品&#xff0c; 在很多公司得到应⽤&a…

FFmpeg - Windows下使用ShiftMediaProject方法编译FFmpeg

文章目录一、创建一个ShiftMediaProject文件夹二、下载ShiftMediaProject源码 &#xff08;以下操作最好都要翻墙&#xff09;三、下载其他头文件四、编译五、参考资料一、创建一个ShiftMediaProject文件夹 我创建在&#xff1a; C:\ShiftMediaProject 二、下载ShiftMediaPro…

【LeetCode题目详解】(一)27.原地移除元素、88.合并两个有序数组

目录 一、力扣第27题&#xff1a;原地移除元素 1.思路一&#xff1a; 2.思路二 3.思路三 二、力扣第88题&#xff1a;合并两个有序数组 1.思路一&#xff1a; 2.思路二&#xff1a; 3.思路三&#xff1a; 总结 一、力扣第27题&#xff1a;原地移除元素 题目链接&#xf…

基于YOLOv3的车辆号牌定位

01 OCR原理分析 本文中采用的车辆号牌识别部分的是采用CNNLSTMCTC组合而成&#xff0c;整个网络部分可以分为三个部分&#xff0c;首先是主干网络CNN用于提取字符的特征信息&#xff0c;其次采用深层双向LSTM网络在卷积特征的基础上提取文字或字符的序列特征&#xff0c;最终引…

基于java+springboot+mybatis+vue+mysql的校园台球厅人员与设备管理系统

项目介绍 校园台球厅人员与设备管理系统采用java技术&#xff0c;基于springboot框架&#xff0c;前端使用vue技术&#xff0c;mysql数据库进行开发&#xff0c;实现了以下功能&#xff1a; 本系统主要包括管理员和用户两个角色组成&#xff0c;主要包括以下功能&#xff1a;…

m基于LMMSE+turbo算法的信道估计均衡器误码率仿真,对比LS,DEF以及LMMSE三种均衡算法误码率

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 本文推导了符号间干扰&#xff08;ISI&#xff09;信道的矢量形状因子图表示。结果图具有树形结构&#xff0c;避免了现有图方法中的短周期问题。基于联合高斯近似&#xff0c;我们在LLR&#xf…

CUDA入门和网络加速学习(二)

0. 简介 最近作者希望系统性的去学习一下CUDA加速的相关知识&#xff0c;正好看到深蓝学院有这一门课程。所以这里作者以此课程来作为主线来进行记录分享&#xff0c;方便能给CUDA网络加速学习的萌新们去提供一定的帮助。 1. 基础矩阵乘法 下图是矩阵乘法的示意图&#xff0…

MySQL表的增删查改(上)

作者&#xff1a;~小明学编程 文章专栏&#xff1a;MySQL 格言&#xff1a;目之所及皆为回忆&#xff0c;心之所想皆为过往 前面给大家分享了关于数据库的一些基本的操作&#xff0c;今天分享的是数据库的核心内容&#xff0c;那就是我们常说的增删查改&#xff0c;也是我们数…

达梦数据库,备份目录冲突

问题描述 达梦数据库执行全库备份&#xff0c;BACKUP DATABASE FULL BACKUPSET ‘/data_share/data_back’; 提示备份目录冲突 解决办法 指定的目录必须为一个空目录。 下图&#xff0c;我指定的目录下有一个test文件夹&#xff0c;所以导致失败&#xff0c;把test文件删除m

[附源码]Python计算机毕业设计SSM基于WEB的网上零食销售系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Python OpenCV中的图像阈值处理

1 前言 上一篇介绍了用C如何对一幅图像进行阈值处理&#xff0c;本篇接着用python来做同样的事情。 图像阈值处理是很多高级算法的底层逻辑之一&#xff0c;比如在做图形检测&#xff0c;轮廓识别时&#xff0c;常常会先对图像进行阈值处理&#xff0c;然后再进行具体的检测或…

FreeRTOS使用 — 合理使用内存 “ 任务中创建任务 ”

前言 在我们学习 RTOS 的过程中&#xff0c;很多朋友都不会遇到内存不够的问题&#xff0c;因为大部分的开发板使用的芯片对学习来说&#xff0c;内存 “足够大” 。所以基本上很多人学会了基本功能&#xff0c;到了实际工作中使用&#xff0c;往往会遇到内存不够的问题&#…

pikachu靶场-10 XXE漏洞

XXE漏洞 概述 XXE -“xml external entity injection” 既"xml外部实体注入漏洞"。 概括一下就是"攻击者通过向服务器注入指定的xml实体内容,从而让服务器按照指定的配置进行执行,导致问题" 也就是说服务端接收和解析了来自用户端的xml数据,而又没有做严…

shell语法总结一(持续补充)

文章目录一、变量1、变量的命名规则2、查看变量3、删除命令4、变量的作用域4.1、局部变量4.2、全局变量4.3、环境变量5、自定义变量6、只读变量二、字符串1、单引号2、双引号&#xff08;用的多&#xff09;3、拼接字符串4、获取字符串的长度5、提取子字符串三、shell数组1、定…

必须掌握的数据库面试问题

一、为什么用自增列作为主键 1、如果我们定义了主键(PRIMARY KEY)&#xff0c;那么InnoDB会选择主键作为聚集索引。 如果没有显式定义主键&#xff0c;则InnoDB会选择第一个不包含有NULL值的唯一索引作为主键索引。 如果也没有这样的唯一索引&#xff0c;则InnoDB会选择内置…

1990-2021年全国各省产业高级化 数据

1990-2021年全国各省产业高级化数据 1、来源为&#xff1a;统计NJ、各省NJ 2、包括&#xff1a;全国31个省份 3、时间&#xff1a;1990-2021年 4、指标包括&#xff1a; 各地区经纬度、第三产业增加值、第二产业增加值、高级化水平 高级化水平第三产业增加值(亿元) / 第二…

HTTP协议【报文格式】

文章目录HTTP协议什么是HTTP协议HTTP协议格式抓包工具的使用HTTP请求URLURL的组成URL encodeHTTP请求的报文格式HTTP响应的报文格式HTTP方法GET方法POST方法POST方法与GET方法的区别请求报头HTTP响应状态码状态码的组成状态码的类别HTTP协议 什么是HTTP协议 HTTP协议即Hyper T…

m基于GA遗传优化的多因素加权竞价博弈频谱分配算法matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 假设有M个用户均为MIMO Full Duplex&#xff0c;N个频率&#xff0c;1<N<M&#xff0c;设计算法实现M个用户与N个频率的匹配。 由于在一个MIMO系统中&#xff0c;用户数量M大于可用的频谱个…