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

# 2-STM32F103-复位和时钟控制RCC

STM32-复位和时钟控制RCC

  • 2-STM32-复位和时钟控制RCC
  • 摘要
  • 说明
    • 本文参考资料如下:
  • 一、STM32最小系统回顾
    • STM32F103C8T6核心板原理图
  • 二、复位
  • 三、时钟
    • 3.1 时钟树
    • 3.2 STM32启动过程
    • 3.2 SystemInit()函数
      • 3.2.1 SystemInit()第1句:
      • 3.2.2 SystemInit()第2句:
      • 3.2.3 SystemInit()第3句:
    • 3.3 SetSysClock()函数:
    • 3.4 SetSysClockTo72()函数:
      • 3.4.1 SetSysClockTo72()第1句:
      • 3.4.2 SetSysClockTo72()第2句:
      • 3.4.3 SetSysClockTo72()第3句:
      • 3.4.4 SetSysClockTo72()第4句:
      • 3.4.5 SetSysClockTo72()第5句:
      • 3.4.6 SetSysClockTo72()第6句:
      • 3.4.7 SetSysClockTo72()第7句:
  • 四、标准库与HAL库区别
    • 4.1 HAL库SystemInit()函数
    • 4.1 HAL库配置系统时钟为72MHz函数
      • 4.1.1 Stm32_Clock_Init函数
    • 4.1 HAL库配置系统时钟为72MHz函数
  • 五、总结
  • 六、资料连接

2-STM32-复位和时钟控制RCC

摘要

在上一篇文章中,我们讲解了STM32F103C8T6最小系统中复位和时钟硬件部分,在本章中讲解最小系统中的复位和时钟的软件部分。本文章根据《1-STM32F10x-中文参考手册》的第6节复位和时钟为依据,并介绍时钟源选择外部8MHz晶震HSE,通过SystemInit()函数将STM32时钟配置为72HMz的代码,并在最后对比标准库和HAL库对时钟配置的不同。

说明

本系列,将整理STM32F103内置外设的使用,“基于标准库“进行学习开发,并将手册说明与标准库代码进行对应学习,在文章最后提供本系列中参考的文章和工程代码下载链接。

本文参考资料如下:


## 1.硬件平台
STM32F103C8T6最小系统板
## 2.软件平台
MDK5
## 3.参考文档
1.《1-STM32F10x-中文参考手册》
2.《3-STM32F103xCDE数据手册-中文》
3. 《STM32F103C8T6核心板原理图》
4.《Cortex-M3权威指南》

一、STM32最小系统回顾

在上一节STM32最小系统中,讲解了STM32最小系统由:电源、时钟、下载、复位、启动五个部分组成,本文主要讲解时钟和复位两个部分,因为这两个部分和后续编程紧密相连,而电源、下载、启动三个部分相对固定,编程上不需要太多改动。

STM32F103C8T6核心板原理图

STM32F103C8T6核心板原理图
图中标红的两个部分,时钟和复位就是本文要讲述的部分。复位使用NRST引脚复位,时钟使用外部晶体震荡器HSE

二、复位

由《1-STM32F10x-中文参考手册》的第6节复位和时钟可知,STM32复位方式有三类:系统复位、上电复位、备份区域复位,其中系统复位包含了:NRST引脚复位
复位方式

由系统复位方式可知:一共有5种复位方式,STM32最小系统中的复位就是NRST引脚复位,是硬件复位方式,也是最常用的一种复位方式。其余四种都是软件复位,IWDG、WWDG、SW三种复位方式,在后续看门狗实验时讲解。低功耗复位在低功耗实验时讲解。

三、时钟

时钟源选择

根据《1-STM32F10x-中文参考手册》的第6节时钟部分可知,STM32F103有5种时钟源,但是系统时钟源SYSCLK只有三种选择,HSE、HSI、PLL,LSI和LSE两种低速时钟是提供给RTC和IWDG使用。其中HSE和LSE是需要我们自己外接晶振的,HSI和LSI是STM32F103C8T6内置的,PLL是取自HSE或HSI。由于HSI不精确,所以为了系统时钟SYSCLK能达到72MHz,我们只能选择HSE。如果没有外接HSE的话,单片机会自动使用内部8MHz的HSI作为系统时钟SYSCLK,此时系统时钟就只有8MHz,且不精确。

3.1 时钟树

时钟树

时钟树是《1-STM32F10x-中文参考手册》的第6节时钟的图,此图介绍了5种时钟源是如何提供给单片机内部其它外设的,我们本文主要关心图中红色线:通过外接8MHz晶振,并通过倍频器PLL进行9倍放大后,得到72MHz的系统时钟SYSCLK的过程。外接8MHz晶振我们在STM32最小系统中,我们已经连接了时钟电路,即已经接好了外部8MHz晶振,接下来我们通过SystemInit()函数配置RCC的时钟控制寄存器CR和时钟配置寄存器CFGR,将SYSCLK配置为72MHz。
注:图中梯形表示选择器,矩形表示执行器。

3.2 STM32启动过程

单片机上电后第一行执行的代码是汇编文件startup_stm32f10x_md.s中的Reset_Handler标签,然后执行SystemInit()后才执行main()。所以在执行我们的main()函数之前,单片机会执行SystemInit()函数将单片机时钟配置为72MHz。
Reset_Handler

; Reset handler
Reset_Handler    PROCEXPORT  Reset_Handler             [WEAK]IMPORT  __mainIMPORT  SystemInitLDR     R0, =SystemInitBLX     R0LDR     R0, =__mainBX      R0ENDP

3.2 SystemInit()函数

在SystemInit()函数中会调用SetSysClock()—>>SetSysClockTo72(),SetSysClockTo72()执行完后STM32系统时钟为72MHz,是8MHz外部高速晶振HSE通过PLL进行9倍频后得到。

void SystemInit (void)
{/* Reset the RCC clock configuration to the default reset state(for debug purpose) *//* Set HSION bit */RCC->CR |= (uint32_t)0x00000001;/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CLRCC->CFGR &= (uint32_t)0xF8FF0000;
#elseRCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   /* Reset HSEON, CSSON and PLLON bits */RCC->CR &= (uint32_t)0xFEF6FFFF;/* Reset HSEBYP bit */RCC->CR &= (uint32_t)0xFFFBFFFF;/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */RCC->CFGR &= (uint32_t)0xFF80FFFF;#ifdef STM32F10X_CL/* Reset PLL2ON and PLL3ON bits */RCC->CR &= (uint32_t)0xEBFFFFFF;/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x00FF0000;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x009F0000;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000;      
#else/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)#ifdef DATA_IN_ExtSRAMSystemInit_ExtMemCtl(); #endif /* DATA_IN_ExtSRAM */
#endif /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers *//* Configure the Flash Latency cycles and enable prefetch buffer */SetSysClock();#ifdef VECT_TAB_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}

3.2.1 SystemInit()第1句:

  /* Reset the RCC clock configuration to the default reset state(for debug purpose) *//* Set HSION bit */RCC->CR |= (uint32_t)0x00000001;

时钟控制寄存器CR
这一行通过位或运算,将RCC->CR寄存器最低位置1,开启HSI时钟。这一句其实我感觉不要也是可以的,因为手册中CR寄存器复位值是0x0000 xx83,即HSION默认值就是1。

3.2.2 SystemInit()第2句:

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CLRCC->CFGR &= (uint32_t)0xF8FF0000;

时钟配置寄存器CFGR

其中#ifndef STM32F10X_CL条件成立,因为在STM32F103C8T6标准库中,并没有定义这个宏,因此执行RCC->CFGR &= (uint32_t)0xF8FF0000;正如备注所示是复位SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits。对照时钟复位寄存器CFGR中说明,0x00转化二进制是0000 0000,即SW[1:0]被置为00,HPRE[3:0]被置为0000,PPRE1[2:0]被置为000,PPRE2[2:0]被置为000,ADCPRE[1:0]被置为00。0xF8转为二进制是1111 1000,即MCO[2:0]被置为000。

3.2.3 SystemInit()第3句:

  /* Reset HSEON, CSSON and PLLON bits */RCC->CR &= (uint32_t)0xFEF6FFFF;/* Reset HSEBYP bit */RCC->CR &= (uint32_t)0xFFFBFFFF;/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */RCC->CFGR &= (uint32_t)0xFF80FFFF;

这三句和备注一样,对应查看CR寄存器和CFGR寄存器对应位说明,将右边的16进制数转化位二进制后对应查看。

3.3 SetSysClock()函数:

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();  
#elif defined SYSCLK_FREQ_72MHzSetSysClockTo72();
#endif/* If none of the define above is enabled, the HSI is used as System clocksource (default after reset) */ 
}

SYSCLK_FREQ_72MHz宏定义
在system_stm32F10x.c的115行定义了宏SYSCLK_FREQ_72MHz,所以会执行 SetSysClockTo72()。

3.4 SetSysClockTo72()函数:

static void SetSysClockTo72(void)
{__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    /* Enable HSE */    RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++;  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;}  if (HSEStatus == (uint32_t)0x01){/* Enable Prefetch Buffer */FLASH->ACR |= FLASH_ACR_PRFTBE;/* Flash 2 wait state */FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    /* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;#ifdef STM32F10X_CL/* Configure PLLs ------------------------------------------------------*//* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz *//* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);/* Enable PLL2 */RCC->CR |= RCC_CR_PLL2ON;/* Wait till PLL2 is ready */while((RCC->CR & RCC_CR_PLL2RDY) == 0){}/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLMULL9); 
#else    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |RCC_CFGR_PLLMULL));RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
#endif /* STM32F10X_CL *//* Enable PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Select PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    /* Wait till PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}}else{ /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */}
}

在SetSysClockTo72()函数中,开启了HSE,并配置了PLL进行9倍频,然后将SYSCLK配置为72MHz。

3.4.1 SetSysClockTo72()第1句:

  /* Enable HSE */    RCC->CR |= ((uint32_t)RCC_CR_HSEON);

时钟控制寄存器CR
时钟控制寄存器CR的bit16是HSEON,将这一位置1,即可开启外部高速时钟HSE。通过按F12跳转到定义发现,在stm32f10x.h中RCC_CR_HSEON定义如下,转换成二进制后,刚好是bit16为1,通过位或运算”|=“将bit16置1,而其它位不变。

#define  RCC_CR_HSEON                        ((uint32_t)0x00010000)        /*!< External High Speed clock enable */

3.4.2 SetSysClockTo72()第2句:

  /* Wait till HSE is ready and if Time out is reached exit */do{HSEStatus = RCC->CR & RCC_CR_HSERDY;StartUpCounter++;  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));if ((RCC->CR & RCC_CR_HSERDY) != RESET){HSEStatus = (uint32_t)0x01;}else{HSEStatus = (uint32_t)0x00;}

等待HSE稳定,并设置超时时间HSE_STARTUP_TIMEOUT,HSE稳定后将HSEStatus标志位置1,然后进行后续配置,如果失败置为0,默认使用8MHz的HSI作为系统时钟。

3.4.3 SetSysClockTo72()第3句:

  if (HSEStatus == (uint32_t)0x01){/* Enable Prefetch Buffer */FLASH->ACR |= FLASH_ACR_PRFTBE;/* Flash 2 wait state */FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    

这几句是配置FLASH的等待周期的,详情需要查看《STM32F10xxx闪存编程手册》。

3.4.4 SetSysClockTo72()第4句:

    /* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

这三句配置三条总线HCLK、PCLK2和PCLK1的时钟频率。即将PCLK2=HCLK = SYSCLK,PCLK1=HCLK/2。此时SYSCLK还不是72MHz,因为还没有配置PLL进行9倍频。

3.4.5 SetSysClockTo72()第5句:

    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |RCC_CFGR_PLLMULL));RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

这两句将PLL配置为对HSE进行9倍频。此时PLL时钟为72MHz。

3.4.6 SetSysClockTo72()第6句:

    /* Enable PLL */RCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Select PLL as system clock source */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    /* Wait till PLL is used as system clock source */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}

这几句是开启PLL时钟,并将其作为SYSCLK时钟源,等待PLL时钟稳定后,即可退出。此时SYSCLK为72MHz,PCLK2=HCLK = SYSCLK=72MHz,PCLK1=HCLK/2=36MHz。

3.4.7 SetSysClockTo72()第7句:

  else{ /* If HSE fails to start-up, the application will have wrong clock configuration. User can add here some code to deal with this error */}

此段代码是 如果HSE初始化失败,那么默认使用HSI作为SYSCLK时钟,我们也可以在此处进行我们自己的处理,但是通常都不会进行处理。

四、标准库与HAL库区别

共同点:单片机上电后会立即执行启动文件中的Reset_Handler标签,然后调用SystemInit()函数。
不同点:SystemInit()函数实现不一样,HAL库中SystemInit()函数不会调用 SetSysClock()将系统时钟初始化为72MHz,而是需要我们在main()函数中自己初始化为72Mhz。

4.1 HAL库SystemInit()函数

void SystemInit (void)
{/* Reset the RCC clock configuration to the default reset state(for debug purpose) *//* Set HSION bit */RCC->CR |= (uint32_t)0x00000001;/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#if !defined(STM32F105xC) && !defined(STM32F107xC)RCC->CFGR &= (uint32_t)0xF8FF0000;
#elseRCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F105xC */   /* Reset HSEON, CSSON and PLLON bits */RCC->CR &= (uint32_t)0xFEF6FFFF;/* Reset HSEBYP bit */RCC->CR &= (uint32_t)0xFFFBFFFF;/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */RCC->CFGR &= (uint32_t)0xFF80FFFF;#if defined(STM32F105xC) || defined(STM32F107xC)/* Reset PLL2ON and PLL3ON bits */RCC->CR &= (uint32_t)0xEBFFFFFF;/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x00FF0000;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000;
#elif defined(STM32F100xB) || defined(STM32F100xE)/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x009F0000;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000;      
#else/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x009F0000;
#endif /* STM32F105xC */#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG)#ifdef DATA_IN_ExtSRAMSystemInit_ExtMemCtl(); #endif /* DATA_IN_ExtSRAM */
#endif #ifdef VECT_TAB_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif 
}

最后没有调用 SetSysClock();也就不会调用 SetSysClockTo72();

4.1 HAL库配置系统时钟为72MHz函数

int main(void)
{HAL_Init();                    	 	//初始化HAL库    Stm32_Clock_Init(RCC_PLL_MUL9);   	//设置时钟,72Mwhile(1){}
}

需要我们编写 Stm32_Clock_Init()函数。

4.1.1 Stm32_Clock_Init函数

4.1 HAL库配置系统时钟为72MHz函数

void Stm32_Clock_Init(u32 PLL)
{HAL_StatusTypeDef ret = HAL_OK;RCC_OscInitTypeDef RCC_OscInitStructure; RCC_ClkInitTypeDef RCC_ClkInitStructure;RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE;    	//时钟源为HSERCC_OscInitStructure.HSEState=RCC_HSE_ON;                      	//打开HSERCC_OscInitStructure.HSEPredivValue=RCC_HSE_PREDIV_DIV1;		//HSE预分频RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON;					//打开PLLRCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE;			//PLL时钟源选择HSERCC_OscInitStructure.PLL.PLLMUL=PLL; 							//主PLL倍频因子ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化if(ret!=HAL_OK) while(1);//选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;		//设置系统时钟时钟源为PLLRCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;				//AHB分频系数为1RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV2; 				//APB1分频系数为2RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV1; 				//APB2分频系数为1ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2);	//同时设置FLASH延时周期为2WS,也就是3个CPU周期。if(ret!=HAL_OK) while(1);
}

调用HAL库HAL_RCC_ClockConfig()函数实现将SYSCLK配置为72MHz。

五、总结

通过标准库和HAL库对比,将STM32系统时钟SYSCLK配置为72MHz既可以在main()函数之前,也可以在main()函数里面,即在使用其它片上外设之前都可以。虽然标准库和HAL库调用的库函数不一样,但是最底层都是配置的RCC的CR和CFGR寄存器,只是封装不同而已,所以我们得熟悉手册对RCC使用的说明,再结合标准库和HAL库进行学习,才能理解得更加透彻。

六、资料连接

https://gitee.com/muzi_wood/stm32-f103

相关文章:

# 2-STM32F103-复位和时钟控制RCC

STM32-复位和时钟控制RCC 2-STM32-复位和时钟控制RCC摘要说明本文参考资料如下&#xff1a; 一、STM32最小系统回顾STM32F103C8T6核心板原理图 二、复位三、时钟3.1 时钟树3.2 STM32启动过程3.2 SystemInit()函数3.2.1 SystemInit()第1句&#xff1a;3.2.2 SystemInit()第2句&a…...

多模态大语言模型arxiv论文略读(七十五)

PosterLLaVa: Constructing a Unified Multi-modal Layout Generator with LLM ➡️ 论文标题&#xff1a;PosterLLaVa: Constructing a Unified Multi-modal Layout Generator with LLM ➡️ 论文作者&#xff1a;Tao Yang, Yingmin Luo, Zhongang Qi, Yang Wu, Ying Shan, C…...

Angular 知识框架

一、Angular 基础 1. Angular 简介 Angular 是什么&#xff1f; 基于 TypeScript 的前端框架&#xff08;Google 维护&#xff09;。 适用于构建单页应用&#xff08;SPA&#xff09;。 核心特性 组件化架构 双向数据绑定 依赖注入&#xff08;DI&#xff09; 模块化设计…...

企业数字化转型背景下的企业知识管理挑战与经验杂谈

一、引言 在数字化转型的浪潮下&#xff0c;企业知识管理正面临前所未有的挑战。随着数据量的急剧增长&#xff0c;企业内部积累的信息呈现出碎片化、分散化的趋势&#xff0c;传统的知识管理体系已难以有效应对这一变革。首先&#xff0c;信息碎片化问题日益严重&#xff0c;…...

使用frp实现客户端开机自启(含静默运行脚本)

本文整理了如何使用 frp 客户端并实现 Windows 系统下的开机静默自启&#xff0c;适合远程桌面、内网穿透等场景。 &#x1f4c1; 目录结构 我将 frp 客户端文件放置在以下路径&#xff1a; F:\git\frp>tree /f 卷 其它 的文件夹 PATH 列表 卷序列号为 A123-0F4E F:. │ …...

list 容器常见用法及实现

文章目录 1. list 的介绍与使用1.1 list 的介绍1.2 list 的使用1.2.1 list 的构造1.2.2 list iterator 的使用1.2.3 list capacity1.2.4 list element access1.2.5 list modifiers1.2.6 迭代器失效问题 2. list 的模拟实现2.1 值得注意的点&#xff1a;2.2 std::initializer_li…...

iOS视频编码详细步骤(视频编码器,基于 VideoToolbox,支持硬件编码 H264/H265)

iOS视频编码详细步骤流程 1. 视频采集阶段 视频采集所使用的代码和之前的相同&#xff0c;所以不再过多进行赘述 初始化配置&#xff1a; 通过VideoCaptureConfig设置分辨率1920x1080、帧率30fps、像素格式kCVPixelFormatType_420YpCbCr8BiPlanarFullRange设置摄像头位置&am…...

浅析 Golang 内存管理

文章目录 浅析 Golang 内存管理栈&#xff08;Stack&#xff09;堆&#xff08;Heap&#xff09;堆 vs. 栈内存逃逸分析内存逃逸产生的原因避免内存逃逸的手段 内存泄露常见的内存泄露场景如何避免内存泄露&#xff1f;总结 浅析 Golang 内存管理 在 Golang 当中&#xff0c;堆…...

记录: Windows下远程Liunx 系统xrdp 用到的一些小问题(免费踩坑 记录)

采用liunx Ubuntu22.04版本以下&#xff0c;需要安装 xrdp 或者VNC 具体过程就是下载 在linux命令行里 首先更新软件包&#xff1a;sudo apt update 安装xrdp服务&#xff1a;sudo apt install xrdp 启动XRDP&#xff1a;sudo systemctl start xrdp&#xff08;如果在启动的…...

C++ 并发编程(1)再学习,为什么子线程不调用join方法或者detach方法,程序会崩溃? 仿函数的线程启动问题?为什么线程参数默认传参方式是值拷贝?

本文的主要学习点&#xff0c;来自 这哥们的视频内容&#xff0c;感谢大神的无私奉献。你可以根据这哥们的视频内容学习&#xff0c;我这里只是将自己不明白的点&#xff0c;整理记录。 C 并发编程(1) 线程基础&#xff0c;为什么线程参数默认传参方式是值拷贝&#xff1f;_哔…...

【Python 算法零基础 2.模拟 ④ 基于矩阵】

目录 基于矩阵 Ⅰ、 2120. 执行所有后缀指令 思路与算法 ① 初始化结果列表 ② 方向映射 ③ 遍历每个起始位置 ④ 记录结果 Ⅱ、1252. 奇数值单元格的数目 思路与算法 ① 初始化矩阵 ② 处理每个操作 ③ 统计奇数元素 Ⅲ、 832. 翻转图像 思路与算法 ① 水平翻转图像 ② 像素值…...

【教程】Docker方式本地部署Overleaf

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 背景说明 下载仓库 初始化配置 修改监听IP和端口 自定义网站名称 修改数据存放位置 更换Docker源 更换Docker存储位置 启动Overleaf 创…...

3337|3335. 字符串转换后的长度 I(||)

1.字符串转换后的长度 I 1.1题目 3335. 字符串转换后的长度 I - 力扣&#xff08;LeetCode&#xff09; 1.2解析 递推法解析 思路框架 我们可以通过定义状态变量来追踪每次转换后各字符的数量变化。具体地&#xff0c;定义状态函数 f(i,c) 表示经过 i 次转换后&#xff0…...

PHP黑白胶卷底片图转彩图功能 V2025.05.15

关于底片转彩图 传统照片底片是摄影过程中生成的反色图像&#xff0c;为了欣赏照片&#xff0c;需要通过冲印过程将底片转化为正像。而随着数字技术的发展&#xff0c;我们现在可以使用数字工具不仅将底片转为正像&#xff0c;还可以添加色彩&#xff0c;重现照片原本的色彩效…...

字符串检索算法:KMP和Trie树

目录 1.引言 2.KMP算法 3.Trie树 3.1.简介 3.2.Trie树的应用场景 3.3.复杂度分析 3.4.Trie 树的优缺点 3.5.示例 1.引言 字符串匹配&#xff0c;给定一个主串 S 和一个模式串 P&#xff0c;判断 P 是否是 S 的子串&#xff0c;即找到 P 在 S 中第一次出现的位置。暴力匹…...

Java大师成长计划之第22天:Spring Cloud微服务架构

&#x1f4e2; 友情提示&#xff1a; 本文由银河易创AI&#xff08;https://ai.eaigx.com&#xff09;平台gpt-4o-mini模型辅助创作完成&#xff0c;旨在提供灵感参考与技术分享&#xff0c;文中关键数据、代码与结论建议通过官方渠道验证。 随着企业应用的不断扩展&#xff0c…...

瀑布模型VS敏捷模型VS喷泉模型

​目录 ​​1. 瀑布模型(Waterfall Model)​​ ​​2. 敏捷模型(Agile Model)​​ ​​3. 喷泉模型(Fountain Model)​​...

基于.Net开发的网络管理与监控工具

从零学习构建一个完整的系统 平常项目上线后&#xff0c;不仅意味着开发的完成&#xff0c;更意味着项目正式进入日常运维阶段。在这个阶段&#xff0c;网络的监控与管理也是至关重要的&#xff0c;这时候就需要一款网络管理工具&#xff0c;可以协助运维人员用于日常管理&…...

Python并发编程:开启性能优化的大门(7/10)

1.引言 在当今数字化时代&#xff0c;Python 已成为编程领域中一颗璀璨的明星&#xff0c;占据着编程语言排行榜的榜首。无论是数据科学、人工智能&#xff0c;还是 Web 开发、自动化脚本编写&#xff0c;Python 都以其简洁的语法、丰富的库和强大的功能&#xff0c;赢得了广大…...

Linux 中 open 函数的本质与细节全解析

一、open简介 在 Linux 下&#xff0c;一切皆文件。而对文件的读写&#xff0c;离不开文件的“打开”操作。虽然 C 语言标准库提供了方便的 fopen&#xff0c;但更底层、更强大的是系统调用 open&#xff0c;掌握它能让你对文件系统控制更细致&#xff0c;在系统编程、驱动开发…...

llama.cpp无法使用gpu的问题

使用cuda编译llama.cpp后&#xff0c;仍然无法使用gpu。 ./llama-server -m ../../../../../model/hf_models/qwen/qwen3-4b-q8_0.gguf -ngl 40 报错如下 ggml_cuda_init: failed to initialize CUDA: forward compatibility was attempted on non supported HW warning: n…...

Python Unicode字符串和普通字符串转换

Unicode 是一种字符编码标准&#xff0c;旨在为世界上所有书写系统的每个字符提供一个唯一的数字标识&#xff08;称为码点&#xff09;。 码点&#xff1a; 每个 Unicode 字符被分配一个唯一的数字&#xff0c;称为码点表示形式&#xff1a;u 后跟 4-6 位十六进制数&#xf…...

Ansible Roles 是一种用于层次化和结构化组织 Ansible Playbook 的机制。

Ansible Roles 是一种用于层次化和结构化组织 Ansible Playbook 的机制。它通过将变量、文件、任务、模板和处理器等放置在单独的目录中,简化了 Playbook 的管理和复用。Roles 自 Ansible 1.2 版本引入,极大地提高了代码的可维护性和可重用性。 目录结构 一个标准的 Ansibl…...

易学探索助手-个人记录(十)

在现代 Web 应用中&#xff0c;用户体验的重要性不断上升。近期我完成了两个功能模块 —— 语音播报功能 与 用户信息修改表单&#xff0c;分别增强了界面交互与用户自管理能力。 一、语音播报功能&#xff08;SpeechSynthesis&#xff09; 功能特点 支持播放、暂停、继续、停…...

Linux基础 -- SSH 流式烧录与压缩传输笔记

Linux SSH 流式烧录与压缩传输指南 一、背景介绍 在嵌入式开发和维护中&#xff0c;常常需要通过 SSH 从 PC 向设备端传输大文件&#xff08;如系统镜像、固件&#xff09;并将其直接烧录到指定磁盘&#xff08;如 /dev/mmcblk2&#xff09;。然而&#xff0c;设备端存储空间…...

学习51单片机01(安装开发环境)

新学期新相貌.......哈哈哈&#xff0c;我终于把贪吃蛇结束了&#xff0c;现在我们来学stc51单片机&#xff01; 要求&#xff1a;c语言的程度至少要到函数&#xff0c;指针尽量&#xff01;如果c语言不好的&#xff0c;可以回去看看我的c语言笔记。 1.开发环境的安装&#x…...

事件驱动reactor的原理与实现

fdset 集合&#xff1a;&#xff08;就是说&#xff09; fd_set是一个位图&#xff08;bitmap&#xff09;结构 每个位代表一个文件描述符 0表示不在集合中&#xff0c;1表示在集合中 fd_set结构&#xff08;简化&#xff09;&#xff1a; [0][1][2][3][4][5]...[1023] …...

大模型训练简介

在人工智能蓬勃发展的当下&#xff0c;大语言模型&#xff08;LLM&#xff09;成为了众多应用的核心驱动力。从智能聊天机器人到复杂的内容生成系统&#xff0c;LLM 的卓越表现令人瞩目。而这背后&#xff0c;大模型的训练过程充满了奥秘。本文将深入探讨 LLM 训练的各个方面&a…...

深度解析 MySQL 与 Spring Boot 长耗时进程:从故障现象到根治方案(含 Tomcat 重启必要性分析)

一、典型故障现象与用户痛点 在高并发业务场景中&#xff0c;企业级 Spring Boot 应用常遇到以下连锁故障&#xff1a; 用户侧&#xff1a;网页访问超时、提交表单无响应&#xff0c;报错 “服务不可用”。运维侧&#xff1a;监控平台报警 “数据库连接池耗尽”&#xff0c;To…...

More Effective C++:改善编程与设计(上)

More Effective C&#xff1a; 目录 More Effective C&#xff1a; 条款1&#xff1a;仔细区别pointers和 references 条款2:最好使用C转型操作符 条款3:绝对不要以多态方式处理数组 条款4:非必要不要提供default constructor 条款5:对定制的“类型转换函数”保持警觉 …...