当前位置: 首页 > news >正文

STM32基础--位带操作

位带简介

位操作就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见。51 单片机中通过关键字 sbit 来实现位定义,STM32 没有这样的关键字,而是通过访问位带别名区来实现。
在 STM32 中,有两个地方实现了位带,一个是 SRAM 区的最低 1MB 空间,另一个是外设区最低 1MB 空间。这两个 1MB 的空间除了可以像正常的 RAM 一样操作外,他们还有自己的位带别名区,位带别名区把这 1MB 的空间的每一个位膨胀成一个 32 位的字,当访问位带别名区的这些字时,就可以达到访问位带区某个比特位的目的。
在这里插入图片描述

外设位带区

外 设 外 带 区 的 地 址 为:0X40000000~0X40100000, 大 小 为1MB, 这1MB的 大 小 在103系 列 大/中/小 容 量 型 号 的 单 片 机 中 包 含 了 片 上 外 设 的 全 部 寄 存 器, 这 些 寄 存 器的 地 址 为:0X40000000~0X40029FFF。 外 设 位 带 区 经 过 膨 胀 后 的 位 带 别 名 区 地 址 为:0X42000000~0X43FFFFFF,这个地址仍然在 CM3 片上外设的地址空间中。在 103 系列大/中小容量型号的单片机里面,0X40030000~0X4FFFFFFF 属于保留地址,膨胀后的 32MB 位带别名区刚好就落到这个地址范围内,不会跟片上外设的其他寄存器地址重合。

STM32 的全部寄存器都可以通过访问位带别名区的方式来达到访问原始寄存器比特位的效果,这比 51 单片机强大很多。因为 51 单片机里面并不是所有的寄存器都是可以比特位操作,有些寄存器还是得字节操作,比如 SBUF。

虽然说全部寄存器都可以实现比特操作,但我们在实际项目中并不会这么做,甚至不会这么做。有时候为了特定的项目需要,比如需要频繁的操作很多 IO 口,这个时候我们可以考虑把 IO 相关的寄存器实现比特操作。

SRAM 位带区

SRAM 的位带区的地址为:0X2000 0000~X2010 0000,大小为 1MB,经过膨胀后的位带别名区地址为:0X2200 0000~0X23FF FFFF,大小为 32MB。操作 SRAM 的比特位这个用得很少。

位带区和位带别名区地址转换

位带区的一个比特位经过膨胀之后,虽然变大到 4 个字节,但是还是 LSB 才有效。有人会问这不是浪费空间吗,要知道 STM32 的系统总线是 32 位的,按照 4 个字节访问的时候是最快的,所以膨胀成 4 个字节来访问是最高效的。

我们可以通过指针的形式访问位带别名区地址从而达到操作位带区比特位的效果。那这两个地址直接如何转换,我们简单介绍一下。

外设位带别名区地址

对于片上外设位带区的某个比特,记它所在字节的地址为 A, 位序号为 n(0<=n<=31)(n 的范围根据具体寄存器能控制的位决定),则该比特在别名区的地址为:

AliasAddr = 0x42000000+ (A-0x40000000)*8*4 +n*4

0X42000000 是外设位带别名区的起始地址,0x40000000 是外设位带区的起始地址, (A-0x40000000)表示该比特前面有多少个字节,一个字节有 8 位,所以 *8,一个位膨胀后是 4 个字节,所以 *4,n 表示该比特在 A 地址的序号,因为一个位经过膨胀后是四个字节,所以也 *4。

SRAM 位带别名区地址

对于 SRAM 位带区的某个比特,记它所在字节的地址为 A, 位序号为 n(0<=n<=31)(n 的范围根据具体寄存器能控制的位决定),则该比特在别名区的地址为:

AliasAddr = 0x22000000+ (A-0x20000000)*8*4 +n*4

公式原理则与上面一样。

统一公式

为了方便操作,我们可以把这两个公式合并成一个公式,把“位带地址 + 位序号”转换成别名区地址统一成一个宏。

// 把“位带地址 + 位序号”转换成别名地址的宏
#define 	BITBAND(addr, bitnum)			 ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))

addr & 0xF0000000 是为了区别 SRAM 还是外设,实际效果就是取出 4 或者 2,如果是外设,则取出的是 4,+0X02000000 之后就等于 0X42000000,0X42000000 是外设别名区的起始地址。如果是 SRAM,则取出的是 2,+0X02000000 之后就等于 0X22000000,0X22000000 是 SRAM 别名区的起始地址。

addr & 0x00FFFFFF 屏蔽了高三位,相当于减去 0X20000000 或者 0X40000000,但是为什么是屏蔽高三位?因为外设的最高地址是:0X20100000,跟起始地址 0X20000000 相减的时候,总是低5 位才有效,所以干脆就把高三位屏蔽掉来达到减去起始地址的效果,具体屏蔽掉多少位跟最高地址有关。SRAM 同理分析即可。«5 相当于 84,«2 相当于 *4,这两个我们在上面分析过。最后我们就可以通过指针的形式操作这些位带别名区地址,最终实现位带区的比特位操作。

// 把一个地址转换成一个指针
#define 		MEM_ADDR(addr)		*((volatile unsigned long*)(addr))
// 把位带别名区地址转换成指针
#define 		BIT_ADDR(addr, bitnum)		MEM_ADDR(BITBAND(addr, bitnum))

GPIO 位带操作

外设的位带区,覆盖了全部的片上外设的寄存器,我们可以通过宏为每个寄存器的位都定义一个位带别名地址,从而实现位操作。但这个在实际项目中不是很现实,也很少人会这么做,我们在这里仅仅演示下 GPIO 中 ODR 和 IDR 这两个寄存器的位操作。
从手册中我们可以知道 ODR 和 IDR 这两个寄存器对应 GPIO 基址的偏移是 12 和 8,我们先实现这两个寄存器的地址映射,其中 GPIOx_BASE 在库函数里面有定义。

别忘了的事

添加bsp_led_bitbang.c文件和bsp_led_bitbang.h文件
别忘了添加文件的时候,在魔术棒的地方加路径。(加上bsp_led_bitbang.h存放的路径)

GPIO 寄存器映射(bsp_led_bitbang.h中)

// 这里只定义了 GPIO ODR和IDR这两个寄存器的位带别名区地址,其他寄存器的没有定义//SRAM 位带区:    0X2000 0000~0X2010 0000
//SRAM 位带别名区:0X2200 0000~0X23FF FFFF//外设 位带区:    0X4000 0000~0X4010 0000
//外设 位带别名区:0X4200 0000~0X43FF FFFF// 把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2)) 
/**addr & 0xF0000000,取地址的高4位,看看是2还是4,用于区分SRAM和外设地址,*如果是2,+0x02000000则=0X2200 0000,即是SRAM,如果是4,+0x02000000则=0X4200 0000,即是外设**addr & 0x000FFFFFF,屏蔽掉高两位,相当于-0X2000 0000或者-0X4000 0000,结果表示偏移位带区多少个字节*<<5  等于*8*4,因为位带区一个地址表示一个字节,一个字节有8个bit,一个bit可以膨胀成一个字,即4个字节*<<2 等于*4,因为一个位可以膨胀成一个字,即4个字节**分解成两条公式应该就是这样:*SRAM位带别名地址*AliasAddr= 0x22000000+((A-0x20000000)*8+n)*4 =0x22000000+ (A-0x20000000)*8*4 +n*4*外设位带别名地址*AliasAddr= 0x22000000+((A-0x20000000)*8+n)*4 =0x22000000+ (A-0x20000000)*8*4 +n*4*/// 把一个地址转换成一个指针
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) // 把位带别名区地址转换成指针
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))   // GPIO ODR 和 IDR 寄存器地址映射 
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C   
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C   
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C   
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C   
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C   
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C      
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C      #define GPIOA_IDR_Addr    (GPIOA_BASE+8)  //0x40010808   
#define GPIOB_IDR_Addr    (GPIOB_BASE+8)  //0x40010C08   
#define GPIOC_IDR_Addr    (GPIOC_BASE+8)  //0x40011008   
#define GPIOD_IDR_Addr    (GPIOD_BASE+8)  //0x40011408   
#define GPIOE_IDR_Addr    (GPIOE_BASE+8)  //0x40011808   
#define GPIOF_IDR_Addr    (GPIOF_BASE+8)  //0x40011A08   
#define GPIOG_IDR_Addr    (GPIOG_BASE+8)  //0x40011E08

现在我们就可以用位操作的方法来控制 GPIO 的输入和输出了,其中宏参数 n 表示具体是哪一个IO 口,n(0,1,2⋯15)。这里面包含了端口 A~G ,并不是每个单片机型号都有这么多端口,使用这部分代码时,要查看你的单片机型号,如果是 64pin 的则最多只能使用到 C 端口。

GPIO 位操作(bsp_led_bitbang.h中)

// 单独操作 GPIO的某一个IO口,n(0,1,2...15),n表示具体是哪一个IO口
#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)  //输入

就是分别使用别名操作每个I/O口的ODR寄存器和IDR寄存器实现输入和输出。

GPIO测试(bsp_led_bitbang.c中)

有关 LED GPIO 初始化和软件延时等函数我们直接用(以前写过的bsp_led.c和bsp_key.c文件里面的函数),修改的是控制 GPIO 输出的部分改成了位操作。该实验我们让 按键控制IO 口输出高低电平来控制LED 的亮灭,负逻辑点亮。具体使用哪一个 IO 和点亮方式由硬件平台决定。

void Led_Bitbang_GPIO_Test(void)
{//LED灯初始化LED_GPIO_Config();//按键初始化Key_GPIO_Config();//红灯亮PBout(5) = 0;/* 轮询按键状态,若按键按下则反转 LED(还没学到DMA或者中断呢) */while(1){if(Key_Scan_Bitbang('A',0) == KEY_ON){/*LED1 开启 */PBout(5) = 0;}if(Key_Scan_Bitbang('C',13) == KEY_ON){/*LED1 关闭 */PBout(5) = 1;}	}	}

代码

bsp_led_bitbang.c

/*** ****************************************************************************** @file        bsp_led_bitbang.c* @brief      	使用位带操作点亮或者熄灭LED灯* @author       (六千里)* @date        2024-03-09* @copyright   无* ******************************************************************************/#include "bsp_led_bitbang.h"/*** @brief检测是否有按键按下* @paramGPIOX: 具体的端口, GPIOX 可以是(A...G)* @paramGPIO_PIN: 具体的端口位, 可以是 x(x 可以是 0...15)* @retval	按键的状态*	@arg KEY_ON: 按键按下*	@arg KEY_OFF: 按键没按下
**/
static uint8_t Key_Scan_Bitbang(uint8_t GPIOX,uint8_t GPIO_Pin)
{switch (GPIOX) {case 'A':	{/* 检测是否有按键按下 */if((PAin(GPIO_Pin)) == KEY_ON){//因为有硬件消抖,故不写软件消抖/* 等待按键释放 */while(PAin(GPIO_Pin) == KEY_ON);												return KEY_ON;}else{return KEY_OFF;}												}case 'B':{/* 检测是否有按键按下 */if((PBin(GPIO_Pin)) == KEY_ON){//因为有硬件消抖,故不写软件消抖/* 等待按键释放 */while(PBin(GPIO_Pin) == KEY_ON);												return KEY_ON;}else{return KEY_OFF;}												}		case 'C':{/* 检测是否有按键按下 */if((PCin(GPIO_Pin)) == KEY_ON){//因为有硬件消抖,故不写软件消抖/* 等待按键释放 */while(PCin(GPIO_Pin) == KEY_ON);												return KEY_ON;}else{return KEY_OFF;}												}		case 'D':{/* 检测是否有按键按下 */if((PDin(GPIO_Pin)) == KEY_ON){//因为有硬件消抖,故不写软件消抖/* 等待按键释放 */while(PDin(GPIO_Pin) == KEY_ON);												return KEY_ON;}else{return KEY_OFF;}												}		case 'E':{/* 检测是否有按键按下 */if((PEin(GPIO_Pin)) == KEY_ON){//因为有硬件消抖,故不写软件消抖/* 等待按键释放 */while(PEin(GPIO_Pin) == KEY_ON);												return KEY_ON;}else{return KEY_OFF;}												}	case 'F':{/* 检测是否有按键按下 */if((PFin(GPIO_Pin)) == KEY_ON){//因为有硬件消抖,故不写软件消抖/* 等待按键释放 */while(PFin(GPIO_Pin) == KEY_ON);												return KEY_ON;}else{return KEY_OFF;}												}	case 'G':{/* 检测是否有按键按下 */if((PGin(GPIO_Pin)) == KEY_ON){//因为有硬件消抖,故不写软件消抖/* 等待按键释放 */while(PGin(GPIO_Pin) == KEY_ON);												return KEY_ON;}else{return KEY_OFF;}												}														default: return KEY_OFF;}}void Led_Bitbang_GPIO_Test(void)
{//LED灯初始化LED_GPIO_Config();//按键初始化Key_GPIO_Config();//红灯亮PBout(5) = 0;/* 轮询按键状态,若按键按下则反转 LED(还没学到DMA或者中断呢) */while(1){if(Key_Scan_Bitbang('A',0) == KEY_ON){/*LED1 开启 */PBout(5) = 0;}if(Key_Scan_Bitbang('C',13) == KEY_ON){/*LED1 关闭 */PBout(5) = 1;}	}	}

bsp_led_bitbang.h

#ifndef __BSP_LED_BITBANG_H
#define __BSP_LED_BITBANG_H/*** ****************************************************************************** 包含的头文件* ******************************************************************************/
#include "bsp_led.h"
#include "bsp_key.h"/*** ****************************************************************************** 宏定义* ******************************************************************************/// 这里只定义了 GPIO ODR和IDR这两个寄存器的位带别名区地址,其他寄存器的没有定义//SRAM 位带区:    0X2000 0000~0X2010 0000
//SRAM 位带别名区:0X2200 0000~0X23FF FFFF//外设 位带区:    0X4000 0000~0X4010 0000
//外设 位带别名区:0X4200 0000~0X43FF FFFF// 把“位带地址+位序号”转换成别名地址的宏
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2)) 
/**addr & 0xF0000000,取地址的高4位,看看是2还是4,用于区分SRAM和外设地址,*如果是2,+0x02000000则=0X2200 0000,即是SRAM,如果是4,+0x02000000则=0X4200 0000,即是外设**addr & 0x000FFFFFF,屏蔽掉高两位,相当于-0X2000 0000或者-0X4000 0000,结果表示偏移位带区多少个字节*<<5  等于*8*4,因为位带区一个地址表示一个字节,一个字节有8个bit,一个bit可以膨胀成一个字,即4个字节*<<2 等于*4,因为一个位可以膨胀成一个字,即4个字节**分解成两条公式应该就是这样:*SRAM位带别名地址*AliasAddr= 0x22000000+((A-0x20000000)*8+n)*4 =0x22000000+ (A-0x20000000)*8*4 +n*4*外设位带别名地址*AliasAddr= 0x22000000+((A-0x20000000)*8+n)*4 =0x22000000+ (A-0x20000000)*8*4 +n*4*/// 把一个地址转换成一个指针
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) // 把位带别名区地址转换成指针
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))   // GPIO ODR 和 IDR 寄存器地址映射 
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C   
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C   
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C   
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C   
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C   
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C      
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C      #define GPIOA_IDR_Addr    (GPIOA_BASE+8)  //0x40010808   
#define GPIOB_IDR_Addr    (GPIOB_BASE+8)  //0x40010C08   
#define GPIOC_IDR_Addr    (GPIOC_BASE+8)  //0x40011008   
#define GPIOD_IDR_Addr    (GPIOD_BASE+8)  //0x40011408   
#define GPIOE_IDR_Addr    (GPIOE_BASE+8)  //0x40011808   
#define GPIOF_IDR_Addr    (GPIOF_BASE+8)  //0x40011A08   
#define GPIOG_IDR_Addr    (GPIOG_BASE+8)  //0x40011E08 // 单独操作 GPIO的某一个IO口,n(0,1,2...15),n表示具体是哪一个IO口
#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)  //输入  /*** ****************************************************************************** .c文件中包含的函数* ******************************************************************************/static uint8_t Key_Scan_Bitbang(uint8_t GPIOX,uint8_t GPIO_Pin);
void Led_Bitbang_GPIO_Test(void);
#endif /*__BSP_LED_BITBANG_H*/

stm32f10x_conf.h

/********************************************************************************* @file    Project/STM32F10x_StdPeriph_Template/stm32f10x_conf.h * @author  MCD Application Team* @version V3.5.0* @date    08-April-2011* @brief   Library configuration file.******************************************************************************* @attention** THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.** <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>*******************************************************************************//* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F10x_CONF_H
#define __STM32F10x_CONF_H/* Includes ------------------------------------------------------------------*/
/* Uncomment/Comment the line below to enable/disable peripheral header file inclusion */
#include "stm32f10x_adc.h"
#include "stm32f10x_bkp.h"
#include "stm32f10x_can.h"
#include "stm32f10x_cec.h"
#include "stm32f10x_crc.h"
#include "stm32f10x_dac.h"
#include "stm32f10x_dbgmcu.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_flash.h"
#include "stm32f10x_fsmc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_iwdg.h"
#include "stm32f10x_pwr.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_rtc.h"
#include "stm32f10x_sdio.h"
#include "stm32f10x_spi.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_wwdg.h"
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
/***自己书写文件的头文件**/
#include "bsp_led.h"
#include "bsp_key.h"
#include "bsp_led_bitbang.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Uncomment the line below to expanse the "assert_param" macro in the Standard Peripheral Library drivers code */
/* #define USE_FULL_ASSERT    1 *//* Exported macro ------------------------------------------------------------*/
#ifdef  USE_FULL_ASSERT/*** @brief  The assert_param macro is used for function's parameters check.* @param  expr: If expr is false, it calls assert_failed function which reports *         the name of the source file and the source line number of the call *         that failed. If expr is true, it returns no value.* @retval None*/#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */void assert_failed(uint8_t* file, uint32_t line);
#else#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */#endif /* __STM32F10x_CONF_H *//******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

main.c

/*** ****************************************************************************** @file        main.c* @brief       主函数* @author       (六千里)* @date        2024-03-09* @copyright   无* ******************************************************************************/
#include "stm32f10x.h"  int main(void)	
{// 来到这里的时候,系统的时钟已经被配置成72M。Led_Bitbang_GPIO_Test();}

相关文章:

STM32基础--位带操作

位带简介 位操作就是可以单独的对一个比特位读和写&#xff0c;这个在 51 单片机中非常常见。51 单片机中通过关键字 sbit 来实现位定义&#xff0c;STM32 没有这样的关键字&#xff0c;而是通过访问位带别名区来实现。 在 STM32 中&#xff0c;有两个地方实现了位带&#xff…...

C# winform 重启电脑

一、重启电脑指令 windows7系统的启动文件夹为“开始菜单”——“所有程序”里面就有“启动”文件夹&#xff0c;其位置是 “C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup” 如果没有&#xff0c;则需要将其中的"administrator…...

波奇学Linux: 信号捕捉

sigaction:修改信号对应的handler方法 act输入型参数&#xff0c;oldact输出型参数 void (*sa_handler) (int) //修改的自定义函数 sigset_t sa_mask // void handler(int signo) {cout<<"catch a signal, signal number: "<<signo<<endl; } int …...

Flink hello world

下载并且解压Flink Downloads | Apache Flink 启动Flink. $ ./bin/start-cluster.sh Starting cluster. Starting standalonesession daemon on host harrydeMacBook-Pro.local. Starting taskexecutor daemon on host harrydeMacBook-Pro.local. 访问localhost:8081 Flin…...

STL之map容器代码详解

基础概念 简介&#xff1a; map中所有元素都是pair。pair中第一个元素为key&#xff08;键值&#xff09;&#xff0c;起到索引作用&#xff0c;第二个元素为value&#xff08;实值&#xff09;。所有元素都会根据元素的键值自动排序。 本质&#xff1a; map/multimap属于关…...

使用GRU进行天气变化的时间序列预测

本文基于最适合入门的100个深度学习项目的学习记录&#xff0c;同时在Google clolab上面是实现&#xff0c;文末有资源连接 天气变化的时间序列的难点 天气变化的时间序列预测涉及到了一系列复杂的挑战&#xff0c;主要是因为天气系统的高度动态性和非线性特征。以下是几个主…...

uniapp 小程序AP配网

一、TCPSocket.js 封装TCP协议 class socket {constructor() {this.connection {};}// 创建一个TCP实例establish(monitor) {this.connection wx.createTCPSocket();this.connection.connect({ address: "000.000.0.0", port: 6800 });}// 发送消息connect(messag…...

Stable Diffusion ———LDM、SD 1.0, 1.5, 2.0、SDXL、SDXL-Turbo等版本之间关系现原理详解

一、简介 2021年5月&#xff0c;OpenAI发表了《扩散模型超越GANs》的文章&#xff0c;标志着扩散模型&#xff08;Diffusion Models&#xff0c;DM&#xff09;在图像生成领域开始超越传统的GAN模型&#xff0c;进一步推动了DM的应用。 然而&#xff0c;早期的DM直接作用于像…...

GESP5级T1真题 [202309] 因数分解——O(sqrt(n))的时间复杂度,值得一看

描述 每个正整数都可以分解成素数的乘积&#xff0c;例如&#xff1a;62*3、2022 *5 现在&#xff0c;给定一个正整数N&#xff0c;请按要求输出它的因数分解式。 输入描述 输入第一行&#xff0c;包含一个正整数N。约定2<N<10^12 输出描述 输出一行&#xff0c;为N…...

Stable Diffusion 3报告

报告链接&#xff1a;https://stability.ai/news/stable-diffusion-3-research-paper 文章目录 要点表现架构细节通过重新加权改善整流流量Scaling Rectified Flow Transformer Models灵活的文本编码器RF相关论文 要点 发布研究论文&#xff0c;深入探讨Stable Diffuison 3的…...

一个足球粉丝该怎么建个个人博客?

做一个个人博客第一步该怎么做&#xff1f; 好多零基础的同学们不知道怎么迈出第一步。 那么&#xff0c;就找一个现成的模板学一学呗&#xff0c;毕竟我们是高贵的Ctrl c v 工程师。 但是这样也有个问题&#xff0c;那就是&#xff0c;那些模板都&#xff0c;太&#xff01;…...

缩放算法优化步骤详解

添加链接描述 背景 假设数据存放在在unsigned char* m_pData 里面&#xff0c;宽和高分别是&#xff1a;m_nDataWidth m_nDataHeight 给定缩放比例&#xff1a;fXZoom fYZoom&#xff0c;返回缩放后的unsigned char* dataZoom 这里采用最简单的缩放算法即&#xff1a; 根据比…...

[axios]使用指南

axios使用指南 Axios 是一个基于 promise 的 HTTP 库&#xff0c;可以用在浏览器和 node.js 中。 axios 安装 npm安装 $ npm install axios 使用cdn <script src"https://unpkg.com/axios/dist/axios.min.js"></script> axios API axios(config)…...

HTML5基础2

drag 可以把拖放事件拆分成4个步骤 设置元素为可拖放。为了使元素可拖动&#xff0c;把 draggable 属性设置为 true 。 <img draggable"true"> 拖动什么。ondragstart 和 setData() const dragestart (ev)>{ev.dataTransfer.setData(play,ev.target.id)} …...

数据结构与算法-希尔排序

引言 在计算机科学中&#xff0c;数据结构和算法是构建高效软件系统的基石。而排序算法作为算法领域的重要组成部分&#xff0c;一直在各种应用场景中发挥着关键作用。今天我们将聚焦于一种基于插入排序的改进版本——希尔排序&#xff08;Shell Sort&#xff09;&#xff0c;深…...

蓝桥杯算法错题记录

这里写目录标题 本文还在跟新&#xff0c;最新更新时间24/3/91. nextInt () next() nextLine() 的注意事项2 . 转换数据类型int ,string,charint -> string , charstring -> int ,charchar -> int , string 进制转换十六进制转化为10 进制 最大公约数 本文还在跟新&am…...

【Python 图像处理 PIL 系列 13 -- PIL 及 Image.convert 函数介绍】

文章目录 Python PIL 介绍PIL 使用介绍PIL convert 介绍PIL convert 使用示例 Python PIL 介绍 PIL 是 Python Image Library 的简称。PIL 库中提供了诸多用来处理图片的模块&#xff0c;可以对图片做类似于 PS&#xff08;Photoshop&#xff09; 的编辑。比如&#xff1a;改变…...

使用docker datascience-notebook进行数据分析

Jupyter/datascience-notebook 简介 jupyter/datascience-notebook 是 Docker Hub 上可用的 Docker 镜像&#xff1a;https://hub.docker.com/。该镜像提供了一个开箱即用的环境&#xff0c;用于数据科学任务&#xff0c;包括&#xff1a; Jupyter Notebook: 一个基于 Web 的…...

VR全景技术在VR看房中有哪些应用,能带来哪些好处

引言&#xff1a; 随着科技的不断发展&#xff0c;虚拟现实&#xff08;VR&#xff09;技术在房地产行业中的应用也越来越广泛。其中&#xff0c;VR全景技术在VR看房中的运用尤为突出。今天&#xff0c;让我们一起深入探讨VR全景技术在VR看房中的应用及其带来的种种好处。 一、…...

Winform窗体随着屏幕的DPI缩放,会引起窗体变形及字体变形,superTabControl标签字体大小不匹配

一、前言 superTabControl做的浏览器标签(cefsharp)在缩放比例(125%,150%时字体不协调) 物联网浏览器,定制浏览器,多媒体浏览器(支持H264)参考栏目文章即可 二、配置参数 app.manifest参数 dpiAware =true <application xmlns="urn:schemas-microsoft-c…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

MinIO Docker 部署:仅开放一个端口

MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的&#xff1a;a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...

sshd代码修改banner

sshd服务连接之后会收到字符串&#xff1a; SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢&#xff1f; 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头&#xff0c…...