细说ARM MCU中的HAL_GPIO_Init()函数的实现过程

目录

一、实例背景:

二、HAL_GPIO_Init函数的格式如下:

1、HAL_GPIO_Init函数中while语句的条件表达式

2、HAL_GPIO_Init函数中的iocurrent变量赋值语句

3、HAL_GPIO_Init函数中的三条if语句

5、 GPIO作为输入时的电路

6、I/O作为输入时执行的语句

7、I/O作为输出的相关电路说明

8、I/O作为输入时执行的语句

9、读取GPIO状态HAL_GPIO_ReadPin()函数

三、重写读/写GPIO的代码


        继续上一篇文章,分析HAL_GPIO_Init函数是如何实现的,该函数的定义在stm32g4xx_hal _gpio.c文件中。

一、实例背景:

        本文中使用ST的开发板NUCLEO-G474RE,板上MCU型号为STM32G474RET6。配套的扩展板:

        实例中当开发板上的按键B1被按下时,PC13引脚被上拉至高电平VDD,不按下时,PC13下拉至低电平GND。用按键B1控制板上的LD2灯的亮灭,当PA5输出高电平时LD2亮,否则灯灭。

二、HAL_GPIO_Init函数的格式如下:

void HAL_GPIO_Init(GPIO_TypeDef *GPIOx,GPIO_InitTypeDef *GPIO_Init)

        HAL_GPIO_Init函数是void类型,不需要返回值。它有两个参数:一个是端口,为结构体类型,与HAL_GPIO_TogglePin()相同;另一个是端口的配置参数,也是结构体类型。stm32g4xx _hal_gpio.c文件中给出的HAL_GPIO_Init区(部分)如下:

void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
{uint32_t position = 0x00U;uint32_t iocurrent;uint32_t temp;/* Check the parameters */assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));assert_param(IS_GPIO_PIN(GPIO_Init->Pin));assert_param(IS_GPIO_MODE(GPIO_Init->Mode));/* Configure the port pins */while (((GPIO_Init->Pin) >> position) != 0U){/* Get current io position */iocurrent = (GPIO_Init->Pin) & (1UL << position);if (iocurrent != 0x00u){/*--------------------- GPIO Mode Configuration ------------------------*//* In case of Output or Alternate function mode selection */if(((GPIO_Init->Mode & GPIO_MODE) == MODE_OUTPUT) ||((GPIO_Init->Mode & GPIO_MODE) == MODE_AF)){/* Check the Speed parameter */assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));/* Configure the IO Speed */temp = GPIOx->OSPEEDR;temp &= ~(GPIO_OSPEEDR_OSPEED0 << (position * 2U));temp |= (GPIO_Init->Speed << (position * 2U));GPIOx->OSPEEDR = temp;/* Configure the IO Output Type */temp = GPIOx->OTYPER;temp &= ~(GPIO_OTYPER_OT0 << position) ;temp |= (((GPIO_Init->Mode & OUTPUT_TYPE) >> OUTPUT_TYPE_Pos) << position);GPIOx->OTYPER = temp;}if ((GPIO_Init->Mode & GPIO_MODE) != MODE_ANALOG){/* Check the Pull parameter */assert_param(IS_GPIO_PULL(GPIO_Init->Pull));/* Activate the Pull-up or Pull down resistor for the current IO */temp = GPIOx->PUPDR;temp &= ~(GPIO_PUPDR_PUPD0 << (position * 2U));temp |= ((GPIO_Init->Pull) << (position * 2U));GPIOx->PUPDR = temp;}/* In case of Alternate function mode selection */if ((GPIO_Init->Mode & GPIO_MODE) == MODE_AF){/* Check the Alternate function parameters */assert_param(IS_GPIO_AF_INSTANCE(GPIOx));assert_param(IS_GPIO_AF(GPIO_Init->Alternate));/* Configure Alternate function mapped with the current IO */temp = GPIOx->AFR[position >> 3U];temp &= ~(0xFU << ((position & 0x07U) * 4U));temp |= ((GPIO_Init->Alternate) << ((position & 0x07U) * 4U));GPIOx->AFR[position >> 3U] = temp;}/* Configure IO Direction mode (Input, Output, Alternate or Analog) */temp = GPIOx->MODER;temp &= ~(GPIO_MODER_MODE0 << (position * 2U));temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2U));GPIOx->MODER = temp;/*--------------------- EXTI Mode Configuration ------------------------*//* Configure the External Interrupt or event for the current IO */if ((GPIO_Init->Mode & EXTI_MODE) != 0x00u){/* Enable SYSCFG Clock */__HAL_RCC_SYSCFG_CLK_ENABLE();temp = SYSCFG->EXTICR[position >> 2U];temp &= ~(0x0FUL << (4U * (position & 0x03U)));temp |= (GPIO_GET_INDEX(GPIOx) << (4U * (position & 0x03U)));SYSCFG->EXTICR[position >> 2U] = temp;/* Clear Rising Falling edge configuration */temp = EXTI->RTSR1;temp &= ~(iocurrent);if ((GPIO_Init->Mode & TRIGGER_RISING) != 0x00U){temp |= iocurrent;}EXTI->RTSR1 = temp;temp = EXTI->FTSR1;temp &= ~(iocurrent);if ((GPIO_Init->Mode & TRIGGER_FALLING) != 0x00U){temp |= iocurrent;}EXTI->FTSR1 = temp;temp = EXTI->EMR1;temp &= ~(iocurrent);if ((GPIO_Init->Mode & EXTI_EVT) != 0x00U){temp |= iocurrent;}EXTI->EMR1 = temp;/* Clear EXTI line configuration */temp = EXTI->IMR1;temp &= ~(iocurrent);if ((GPIO_Init->Mode & EXTI_IT) != 0x00U){temp |= iocurrent;}EXTI->IMR1 = temp;}}position++;}
}

1、HAL_GPIO_Init函数中while语句的条件表达式

        HAL_GPIO_Init函数中主要就是一个while的条件表达式:

((GPIO_Init->Pin)>>position) != 0U

        其中,最后的“0U”,是无符号数0是无符(Unsigned int)。后面的1UL,“1”后面的“UL”表示数1为Unsigned long int。

        此处的GPIO_Init -> Pin中GPIO_Init是通过结构体变量传递过来的参数,实际就是引脚号。因此,对PC13来说,这个GPIO_Init->Pin就是GPIO_PIN_13对应的数(0010 0000 0000 0000),即0x2000,“>>”表示右移。右移的位数在position变量中。由于position初始为0,0x2000右移0位,值不会改变,还是0x2000,条件不等于0,所以,while的条件是满足的,程序继续执行。

2、HAL_GPIO_Init函数中的iocurrent变量赋值语句

        继续,给变量iocurrent赋值:

iocurrent = (GPIO_Init->Pin) & (1UL <<position);

        当前是在配置PC13,此时GPIO_Init->Pin为0x2000,按位逻辑“与”后面的1UL<<position,是将“1”左移position位,而position此时为0,所以还是1。用0x2000与1按位相“与”,结果为0。所以,接下来的if语句的条件(iocurrent!=0x00u)不满足的,此时程序就会跳到if之外,执行最后的position++,让position自加1;执行后,position为1。随后,会继续判断while条件是否成立。当然,虽然此时position为1,当0x2000右移1位后,依然不等于0,条件是满足的。接着执行iocurrent赋值语句,此时将0x2000与0x0002按位相与,结果iocurrent依然为0。所以,会继续执行position++语句,一直到position为13,此时在while的条件中0x2000右移13位,结果为1,还是不等于0,所以while条件还是满足的。接下来将会继续执行iocurrent赋值语句,此时1左移13位的结果刚好为0x2000,而GPIO_Init->Pin也为0x2000,这两个数按位逻辑“与”的结果就不再为0了;接下来的if语句,条件是满足的,所以会执行if中的语句。

3、HAL_GPIO_Init函数中的三条if语句

        在if(iocurrent!=0x00u){...}中还有三条if语句:

        第一条if语句用于复用功能(alternate function),本例中是用作GPIO,所以不会执行。

        第二条if语句输出或复用功能,由于当前是配置PC13作为输入,所以此时也不会执行。

        第三条if语句用于外部中断、触发等模式,本例中也不会执行。

      此外,在第一条if语句与第二条if语句之间有段配置I/O模式的语句(配置GPIO的GPIOx->MODER寄存器),在第二条if语句和第三条if语句之间有段配置I/O上拉/下拉功能的(配置GPIO的GPIOx_PUPDR寄存器),这两段代码在配置GPIO的输入与输出功能时都会执行。

4、I/O作为输入时执行的语句

        配置PC13作为输入引脚时会执行下面4条语句:

/* Activate the Pull-up or Pull down resistor for the current IO */
temp = GPIOx -> PUPDR;
temp &= ~(GPIO_PUPDR_PUPD0 << (position *2U));
temp |= ((GPIO_Init->Pull) << (position *2U));
GPIOx -> PUPDR = temp;

        第一条语句是将GPIOx -> PUPDR赋值给变量temp。PUPDR是GPIO的寄存器。查STM32G4系列MCU的参考手册,可以看到PUPDR的寄存结构:

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

PUPD15[1:0]

PUPD14[1:0]

PUPD13[1:0]

PUPD12[1:0]

PUPD11[1:0]

PUPD10[1:0]

PUPD9[1:0]

PUPD8[1:0]

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

PUPD7[1:0]

PUPD6[1:0]

PUPD5[1:0]

PUPD4[1:0]

PUPD3[1:0]

PUPD2[1:0]

PUPD1[1:0]

PUPD0[1:0]

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

 GPIOx_PUPDR寄存器(x为A、B、C、D、E、F、G)结构

        PUPDR有32位,每2位构成一组,共有16组,即PUPD0~PUPD15(PUPD是Pull-up,Pull-down的缩写)。实际上每一组PUPDx[1:0]对应一个GPIO端口引脚的上拉/下拉配置(二进制):

00:没有上拉,下拉;
01:上拉;
10:下拉;
11:保留。

        由于配置的是PC13,所以对应的就是PUPD13[1:0],它们在PUPD寄存器的第26和27位(最低位从0开始)。

        此外,还需要提一下PUPDR寄存器的默认值。在STM32G4系列MCU的参考手册中,提到了GPIOx_PUPDR寄存器的默认值(初始值,即复位后的值)。对于端口A(GPIOA),默认值是0x6400 0000。也就是说,PUPD15[1:0]=01(二进制),PA15默认为上拉;PUPD14[1:0]=10(二进制),PA14默认为下拉。

        对于端口B(GPIOB),默认值为0x0000 0100。也就是说,除了PUPD4[1:0]=01以外,其它均为00。意思是PB4默认为上拉,其他不开启上拉、下拉功能。

        除了GPIOA和GPIOB以外,对于其他GPIO,PUPDR寄存器的值均为0x0000 0000,即为不开启上拉、下拉功能。由于PC13属于GPIOC,所以默认情况下该端口的PUPDR的值为0。因此,执行temp = GPIOx->PUPDR语句后,temp的值为0。

5、 GPIO作为输入时的电路

        GPIO的引脚既可以用作输入,也可以用作输出,但是在同一时刻,只能配置为其中一种(即要么为输入,要么为输出)。用作输入时,输出通道是要关闭的。

6、I/O作为输入时执行的语句

        继续,分析配置PUPDR的代码。接下来的一行语句是:

temp &= ~(GPIO_PUPDR_PUPD0 << (position *2U));

        其中,“&=”是将变量temp与“=”后的表达式的值相“与”,并把结果赋给temp。不过由于执行完前面的赋值语句后,temp已经为0了,所以执行这一条语句后,temp会依然为0。

        在这条语句中,GPIO_PUPDR_PUPD0是个常量,实际就是在PUPDR寄存器中PUP0[1:0]所在的位的掩码,也就是表中的最低2位的掩码,用二进制表示掩码就是11,即十进制数值3。

        由于此时position为13(十进制数),与2相乘就是26,所以上边语句中等号右侧的表达式意思就是将二进制11左移26位,此时得到的值是一个第26和27位为1、其他位均为0的32位数:0x0C00 0000。然后取反,得到的数值为0xf3ff ffff。不过,与temp相“与”后,结果还是为0。所以,执行完这一条语句后,temp的值还是0。

        接下来的语句是:

temp |= ((GPIO_Init->Pull) << (position *2U));

        其中,GPIO_Init是HAL_GPIO_Init()函数的第二个参数,是由MX_GPIO_Init(void)函数传递过来的。在MX_GPIO_Init(void)函数中,就是结构体变量GPIO_InitStruct。在该函数中,该变量做过如下赋值:

GPIO_InitStruct.Pull =GPIO_PULLDOWN;

        所以,上述语句中的GPIO_Init->Pull就是GPIO_PULLDOWN,也就是下拉。在STM32g4xx _hal_gpio.h中,关于GPIO_PULLDOWN有一个宏定义:

# define GPIO_PULLDOWN (0x0000 0002U)

        此时positon为13,GPIO_PULLDOWN的值是2,用二进制表示就是10。重面己知,此时position为13,position*2就是26;二进制数10左移26位,结果是0x0800 0000;,

        “|=”是将“=”后的表达式的值与temp相“或”,然后再赋值给temp。所以,此句执行完的值为0x0800 0000。

        接下来的语句是:

GPIOx -> PUPDR = temp;

        该句表示将temp的值赋值给PUPDR寄存器,也就是说,把0x0800 0000赋值给PUPDR寄存器。对照表中PUPDR寄存器的结构,刚好是PUPD13[1:0]的值为二进制数10,也就是将PC13配置为下拉模式。

        至此,PUPDR就配置完毕。

7、I/O作为输出的相关电路说明

要配置PA5作为输出引脚,先来看一下将GPIO配置为输出I/O功能需要做哪些事情。

        在STM32 MCU中,输出有两种模式:一种是开漏(open drain),另一种是推挽(push-pull)。这是两种常见的电路输出方式:

        在push-pull模式时,会用到P-MOS和N-MOS两个MOS管。这两个管子是互补输出的,也就是说,上面的P-MOS导通,下面的N-MOS就会截止,此时输出高电平;P-MOS截止,N-MOS导通,则输出低电平。

        开漏(open drain)的“漏”,就是MOS管的漏极。开漏模式就是由MOS管的漏为输出。此时,只需要将下面那个N-MOS管接在输出和地之间。开漏模式比推挽模式少用一个P-MOS。此时,要输出高电平就需要上拉电阻配合。因此,如果设置了为开漏输出模式,通常要配置为上拉。

8、I/O作为输入时执行的语句

        接着分析HAL_GPIO_Init函数。在配置PA5时,程序会执行到中间这条if语句。再来分析一下配置GPIOx_OSPEED寄存器的过程。这个寄存器是配置I/O引脚速度参数的,关键的几句代码如下:

/*In case of Output or Alternate function mode selection */
if(…)
{……/*Configure the IO Speed */temp = GPIOx -> OSPEEDR;temp &= ~(GPIO_OSPEEDR_OSPEED0 << (position *2U));temp |= (GPIO_Init->Speed << (position *2U));GPIOx -> OSPEEDR = temp;……
}

        配置这个寄存器也是执行4条语句,与前面介绍的配置PUPDR寄存器的过程基本类似。在配置PA5时,当程序执行到这几句代码时,变量position的值应该是5。

        第一条语句是将GPIOx->OSPEEDR赋值给变量temp。OSPEED是GPIO的寄存器。查看STM32G4系列MCU的参考手册,可以看到OSPEED的寄存器结构。OSPEED有32位,每2位构成一组,共有16组,即OSPEED0~OSPEED15。实际上,每一组OSPEEDx[1:0]对应一个GPIO端口引脚的速度配置(二进制):

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

OSPEED15[1:0]

OSPEED14[1:0]

OSPEED13[1:0]

OSPEED12[1:0]

OSPEED11[1:0]

OSPEED10[1:0]

OSPEED9[1:0]

OSPEED8[1:0]

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

OSPEED7[1:0]

OSPEED6[1:0]

OSPEED5[1:0]

OSPEED4[1:0]

OSPEED3[1:0]

OSPEED2[1:0]

OSPEED1[1:0]

OSPEED0[1:0]

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

rw

 GPIOx_OSPEED寄存器(x为A、B、C、D、E、F、G)结构

00:低速;
01:中速;
10:高速;
11:很高速。

       GPIOx_OSPEED寄存器的默认值有两种情况:对于端口A(GPIOA),默认值为0x0C00 0000;对于其他端口,默认值一律为0x0000 0000。

        此时配置的是PA5,对应的就是OSPEED5[1:0],它们在OSPEED寄存器的第10和11位(最低位从0开始)。不过,由于GPIOA的OSPEED寄存器,默认值为0x0C00 0000,所以执行完这条赋值语句后,temp的值为0x0C00 0000。然后,

temp &= ~(GPIO_OSPEEDR_OSPEED0 << (position *2U));

        “&=”是将变量temp与“=”后的表达式的值相“与”,并把结果赋给temp。GPIO_OSPEEDR _OSPEED0 是个常量,实际就是在OSPEED寄存器中,OSPEEDO[1:0]在位的掩码,也就是表中的最低2位的掩码,用二进制表示掩码就是11,即数值3(十进制)。

        由于此时position为5,与2相乘就是10(十进制)。所以上边的语句中等号右侧的表达式意思就是将二进制11左移10位,结果为0x0000 0C00;然后,将该值取反,可以得到0xFFFF F3FF。

        将temp当前的值0x0C00 0000与0xFFFF F3FF相“与”,结果为0x0C00 0000,该值会赋给temp。所以该语句执行完毕后,temp的值为0x0C00 0000。这个结果与OSPEED寄存器的默认值相比较,在数值上没有什么变化。做这些操作有何意义呢?

        实际上,这两个temp赋值语句的目的是,将OSPEED寄存器中要配置的相应位(对PA5来说就是第10和11位)变为00,以便接下来做修改。这里与默认值相同的原因是,在此次读取OSPEED寄存器的时刻,这两位本来就为00。继续:

temp |= (GPIO_Init->Speed << (position *2U));

        该语句中,GPIO_Init -> Speed是取出在MX_GPIO_Init函数中配置的Speed值:

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_SPEED_FREQ_HIGH在stm32g4**_hal_gpio.h中被定义如下:
# define GPIO_SPEED_FREQ_HIGH (0x00000002U)

        也就是二进制数10,是高速时钟。将二进制数10左移10位后,结果为0x0000 0800,与temp的当前值0x0C00 0000相“或”后,得到0x0C00 0800。这个结果与OSPEED寄存器的默认值相比较,OSPEED5[1:0]的值被修改为二进制数10,即配置PA5的速度为高速。

9、读取GPIO状态HAL_GPIO_ReadPin()函数

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{GPIO_PinState bitstatus;/* Check the parameters */assert_param(IS_GPIO_PIN(GPIO_Pin));if ((GPIOx->IDR & GPIO_Pin) != 0x00U){bitstatus = GPIO_PIN_SET;}else{bitstatus = GPIO_PIN_RESET;}return bitstatus;
}

        HAL_GPIO_ReadPin函数的类型是GPIO_PinState,而GPIO_PinState是枚举类型。它有两个成员GPIO_PIN_RESET和GPIO_PIN_SET,取值为0和1。调用HAL_GPIO_ReadPin函数,需要返回引脚的状态,该状态要么为0(低电平),要么为1(高电平)。

        在HAL_GPIO_ReadPin函数中,首先声明了类型同样为GPIO_PinState的变量bitstatus,紧接着是一个assert_param()语句,用于判断传递过来的引脚号是否在有效范围内;随后,在if语句的条件表达式中,读取了GPIO的输入数据寄存器IDR。GPIOx ->IDR & GPIO_PIN的作用是取出IDR中与引脚号相对应的位,如果该位不为0,则将1(GPIO_PIN_SET)赋给变量bitstatus;如果该位为0,则将0赋给bitstatus。if语句之后,用return返回bitstatus。

        在STM32G4系列MCU的参考手册中,可以查到IDR寄存器的结构:

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

Res

Res

Res

Res

Res

Res

Res

Res

Res

Res

Res

Res

Res

Res

Res

Res

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

ID15

ID14

ID13

ID12

ID11

ID10

ID9

ID8

ID7

ID6

ID5

ID4

ID3

ID2

ID1

ID0

r

r

r

r

r

r

r

r

r

r

r

r

r

r

r

r

 GPIOx_IDR寄存器(x为A、B、C、D、E、F、G)结构

        IDR只是用了低16位,分别对应GPIO端口的16个引脚。就是相应引脚的输入状态数据,不过,ID[15:0]下面标有“r”,表示该位只可读。

三、重写读/写GPIO的代码

        用PC13作为按键状态的输入引脚,该引脚所属端口为GPIOC;用PB5作为控制发光二极管的输出引脚,所属端口为GPIOB。不过,在前面配置端口的模式时,给PC13起一个用户标识KEY,给PB5起的是LED,所以在main.h文件中,可以看到如下的宏定义:

# define KEY_Pin GPIO_PIN_13
# define KEY_GPIO_Port GPIOC
# define LED_Pin GPIO_PIN_5
# define LED_GPIO_Port GPIOA

        这样,就可以写出这两个函数的完整语句:

HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin);
HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);

        由于HAL_GPIO_ReadPin函数需要返回引脚的输入状态,类型是GPIO_PinState,所以,可以先在main.c中定义一个变量KEY,类型为GPIO_PinState。因为GPIO_PinState的成员是GPIO_ PIN_RESET和GPIO_PIN_SET,实际就是0和1,所以,也可以将变量KEY的类型定义为uint8_t。

/*USER CODE BEGIN 1 */
GPIO_PinState KEY;
/*USER CODE END 1 */
/*Infinite loop */
while(1)
{/*USER CODE BEGIN 3*/KEY = HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin);if(KEY == GPIO_PIN_SET){HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET);}else{HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_SET);}
}
/*USER CODE END 3*/

        代码编写完毕后,编译工程。如果没有出现错误,就可以下载到硬件中。运行后,开发板上的LD2默认状态下是点亮着的,按下B1键后LD2灯熄灭。如此便实现了通过按键控制LED灯亮灭的效果。

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

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

相关文章

HTML5 新表单元素详解

一、HTML5 新的 <input> 类型 HTML5 引入了多种新的 <input> 类型&#xff0c;使得表单的输入更加语义化和用户友好。 1. <input type"email"> <input type"email"> 用于接收电子邮件地址&#xff0c;浏览器会自动进行格式验证…

基于稀疏辅助小波和线性时不变滤波器的惯性传感器步态周期分割方法(MATLAB R2018A)

每个人在肌肉骨骼状况、生理状况、心理特征以及个人行走的“风格”等方面都有各自的特点&#xff0c;因此&#xff0c;每个人都有自己的步态指纹。这意味着可以根据步态特征来进行身份识别。基于步态的身份识别是生物特征识别的一个新兴领域。其机制有3个显著的优点&#xff1a…

STM32高级控制定时器应用之检测输入PWM周期和占空比

目录 概述 1 PWM 输入模式 1.1 原理介绍 1.2 应用实例 1.3 示例时序图 2 使用STM32Cube配置工程 2.1 软件环境 2.2 配置参数 2.3 生成项目文件 3 功能实现 3.1 PWM占空比函数 3.2 输入捕捉回调函数 4 功能测试 4.1 测试软件框架结构 4.2 实验实现 4.2.1 测试实…

整数之间的赋值问题

前言&#xff1a;我们在初学C语言的时候&#xff0c;总是避免不了一些数据类型的转换&#xff0c;例如int-->char&#xff0c;char-->int&#xff0c;如果我们仅仅只学习这些语法&#xff0c;而不去了解底层原理&#xff0c;对于这些输出的内容&#xff0c;我们可能会感觉…

2024还不会安装NodeJs

2024还不会安装NodeJs 1、官网下载 由于本地是windows&#xff0c;所以选择 Prebuilt Installer 64位 NodeJs官网下载 LTS长期支持版本 当然这里我用的 Snipastate 截屏软件&#xff0c;这里也配下载链接 Snipasate下载链接 2、配置环境变量 由于是自己的电脑&#xff0c…

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图(五)

SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09; 参考 目录 文章目录 SpringBoot启动流程分析之设置系统属性spring.beaninfo.ignore、自定义banner图&#xff08;五&#xff09;1、设置sping.beaninfo.ignore属性2、…

代码随想录leetcode200题之动态规划算法

目录 1 介绍2 训练3 参考 1 介绍 本博客用来记录代码随想录leetcode200题之动态规划算法相关题目。 2 训练 题目1&#xff1a;509. 斐波那契数 C代码如下&#xff0c; class Solution { public:int fib(int n) {if (n < 1) { //特判return n;}int a 0, b 1;for (int …

C语言进程编程:探索操作系统的核心机制

C语言进程编程&#xff1a;探索操作系统的核心机制 在C语言的广阔领域中&#xff0c;进程编程无疑是一块充满挑战与机遇的阵地。进程作为操作系统分配资源的基本单位&#xff0c;其编程涉及到系统调用、进程控制、通信与同步等多个复杂而关键的概念。本文将围绕四个方面、五个…

限流算法整理——滑动窗口限流算法

限流算法描述 滑动窗口限流需要将每个窗口空间划分为无限小的窗口区间&#xff0c;并且动态调整区间的起始点&#xff0c;并且在调整完毕之后需要判断各个区间&#xff0c;累加各个区间的请求&#xff0c;查看是否到达最大的阈值&#xff0c;以此返回允许请求还是拒绝请求 算…

计算机常用的英语单词

在计算机科学与技术领域&#xff0c;有一些常用的英语单词和术语是学习者需要掌握的。以下是一些常见的计算机必会英语单词&#xff0c;分为不同的类别&#xff1a; 1. 编程语言和技术&#xff1a; Algorithm - 算法Programming - 编程Code - 代码Variable - 变量Function - …

PyTorch学习(11):PyTorch的形状变换(view, reshape)与维度变换(transpose, permute)

PyTorch学习&#xff08;1&#xff09;&#xff1a;torch.meshgrid的使用-CSDN博客 PyTorch学习&#xff08;2&#xff09;&#xff1a;torch.device-CSDN博客 PyTorch学习&#xff08;9&#xff09;&#xff1a;torch.topk-CSDN博客 PyTorch学习&#xff08;10&#xff09;…

数据库与数据库管理系统 MySQL的安装 SQL语言学习:DDL、DML

day51 数据库 数据库&#xff08;database&#xff09;就是一个存储数据的仓库。为了方便数据的存储和管理&#xff0c;它将数据按照特定的规律存储在磁盘上。 通过数据库管理系统&#xff0c;可以有效地组织和管理存储在数据库中的数据&#xff0c;如数据库管理系统MySQL 数据…

Java学习Lambda表达式

Lambda表达式 有且只有一个未实现的方法叫做Lambda表达式&#xff0c;可以实现函数式编程 // 这个注解是用来检查你写的函数是否是函数式接口 FunctionalInterfaceinterface Myinterface {int sum(int a, int b);default String priteTitle(String name, int age, String sex)…

Kubernetes资源调度策略及实现机制

目录 一、资源调度策略 1.默认调度器&#xff08;Default Scheduler&#xff09; 2.自定义调度器&#xff08;Custom Scheduler&#xff09; 3.亲和性与反亲和性&#xff08;Affinity and Anti-Affinity&#xff09; 4.污点与容忍&#xff08;Taint and Tolerations&#…

时间序列差分顺序的讨论

生成出一组时间序列数据 服从标准正态分布的50个 随机数据 分别给出4步季节差分&#xff0c;再进行1步1阶差分的结果 和 1步1阶差分再进行 4步季节差分 的结果 讨论&#xff1a; 先进行4步季节差分再进行1步1阶差分与先进行1步1阶差分再进行4步季节差分的结果看起来是相同的

计算机网络复习(2)性能指标 带宽

计算机网络的性能指标是衡量网络效率、可靠性和服务质量的重要参数&#xff0c;它们帮助我们理解网络如何工作以及如何优化网络性能。以下是计算机网络中几个关键的性能指标的详细介绍&#xff1a; 1. 速率 (Rate) / 比特率 (Bit Rate) / 数据率 (Data Rate) 速率指的是数据在…

Nvidia Jetson/Orin +FPGA+AI大算力边缘计算盒子:潍柴雷沃智慧农业无人驾驶

潍柴雷沃智慧农业科技股份有限公司&#xff0c;是潍柴集团重要的战略业务单元&#xff0c;旗下收获机械、拖拉机等业务连续多年保持行业领先&#xff0c;是国内少数可以为现代农业提供全程机械化整体解决方案的品牌之一。潍柴集团完成对潍柴雷沃智慧农业战略重组后&#xff0c;…

kaggle:房价预测

比赛链接 结果展示 结果链接 8848是密码 文章目录 数据处理调包部分拒绝掉包岭回归理论代码实践结果 自助采样理论代码 集成学习前言Bagging理论Bagging-Ridge代码Bagging-Ridge实践Bagging-Ridge结果 Tricks 数据处理 #打开文件 import pandas as pd dataset1pd.read_csv(&q…

Arduino编程变量:深度探索与实际应用

Arduino编程变量&#xff1a;深度探索与实际应用 在Arduino编程中&#xff0c;变量扮演着至关重要的角色。它们用于存储程序运行过程中的临时数据&#xff0c;是实现各种功能和算法的关键。然而&#xff0c;对于初学者来说&#xff0c;变量的理解和使用往往充满了困惑和挑战。…

Java 基础面试300题 (111-140)

Java 基础面试300题 &#xff08;111-140&#xff09; 111.什么是Java包&#xff1f; 有什么优点&#xff1f; 包是相关Java类型的集合。包中可以包括相关的类、接口和枚举。使用包来组织软件代码有几方面的优点&#xff1a; 包有助于将相关代码保存在一起。包有助于避免命名…