欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > 25/1/18 嵌入式笔记 STM32F103

25/1/18 嵌入式笔记 STM32F103

2025/5/12 13:20:24 来源:https://blog.csdn.net/yyyy2711/article/details/145215325  浏览:    关键词:25/1/18 嵌入式笔记 STM32F103

Unix时间戳

BKP和RTC

RTC基本结构

是一种用于跟踪时间的硬件模块,通常集成在微控制器或独立的芯片中。RTC 可以提供年、月、日、时、分、秒等时间信息,并且在系统断电时通过备用电池保持运行。

RTC 的基本功能

  • 时间跟踪:提供年、月、日、时、分、秒等信息。

  • 日期计算:自动处理闰年、月份天数等。

  • 闹钟功能:在特定时间触发中断。

  • 低功耗:在系统断电时通过备用电池供电。

RTC 的硬件连接

RTC 通常需要以下硬件支持:

  • 主电源:为 RTC 提供运行电源。

  • 备用电池:在系统断电时为 RTC 供电(如纽扣电池)。

  • 晶振:提供精确的时钟信号(通常为 32.768 kHz)。

 RTC 的寄存器

RTC 通常通过一组寄存器来配置和读取时间信息。常见的寄存器包括:

  • 时间寄存器:存储时、分、秒。

  • 日期寄存器:存储年、月、日。

  • 控制寄存器:配置 RTC 的工作模式。

  • 闹钟寄存器:设置闹钟时间。

 RTC 的实现步骤

初始化 RTC
RTC_HandleTypeDef hrtc;void RTC_Init(void) {hrtc.Instance = RTC;hrtc.Init.HourFormat = RTC_HOURFORMAT_24;  // 24 小时制hrtc.Init.AsynchPrediv = 127;              // 异步预分频hrtc.Init.SynchPrediv = 255;               // 同步预分频hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;     // 禁用输出hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;HAL_RTC_Init(&hrtc);
}
解析
  • hrtc.Instance:选择 RTC 外设实例。

  • hrtc.Init.HourFormat:设置时间格式(12 小时制或 24 小时制)。

  • hrtc.Init.AsynchPrediv 和 hrtc.Init.SynchPrediv:设置预分频值,用于生成 1 Hz 的时钟信号。

  • HAL_RTC_Init(&hrtc):初始化 RTC 外设。

设置时间和日期
void RTC_SetTime(uint8_t hour, uint8_t minute, uint8_t second) {RTC_TimeTypeDef sTime = {0};sTime.Hours = hour;sTime.Minutes = minute;sTime.Seconds = second;HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
}void RTC_SetDate(uint8_t year, uint8_t month, uint8_t day) {RTC_DateTypeDef sDate = {0};sDate.Year = year;sDate.Month = month;sDate.Date = day;HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
}
  • RTC 需要初始时间和日期才能开始计时。

  • 通过设置函数初始化 RTC 的时间和日期。

解析
  • RTC_TimeTypeDef 和 RTC_DateTypeDef:时间和日期的结构体。

  • HAL_RTC_SetTime() 和 HAL_RTC_SetDate():HAL 库函数,用于设置时间和日期。

读取时间和日期
void RTC_GetTime(uint8_t *hour, uint8_t *minute, uint8_t *second) {RTC_TimeTypeDef sTime = {0};HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);*hour = sTime.Hours;*minute = sTime.Minutes;*second = sTime.Seconds;
}void RTC_GetDate(uint8_t *year, uint8_t *month, uint8_t *day) {RTC_DateTypeDef sDate = {0};HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);*year = sDate.Year;*month = sDate.Month;*day = sDate.Date;
}
作用
  • 读取 RTC 的当前时间和日期。

为什么需要
  • 通过读取函数获取 RTC 的当前时间和日期。

解析
  • HAL_RTC_GetTime() 和 HAL_RTC_GetDate():HAL 库函数,用于读取时间和日期。

主函数中使用
int main(void) {HAL_Init();SystemClock_Config();RTC_Init();  // 初始化 RTC// 设置初始时间和日期RTC_SetTime(12, 0, 0);  // 12:00:00RTC_SetDate(23, 10, 15); // 2023 年 10 月 15 日uint8_t hour, minute, second, year, month, day;while (1) {// 读取当前时间和日期RTC_GetTime(&hour, &minute, &second);RTC_GetDate(&year, &month, &day);// 打印时间和日期(通过串口或调试工具)printf("Time: %02d:%02d:%02d\n", hour, minute, second);printf("Date: 20%02d-%02d-%02d\n", year, month, day);HAL_Delay(1000);  // 延时 1 秒}
}
解析
  • HAL_Init():初始化 HAL 库。

  • SystemClock_Config():配置系统时钟。

  • RTC_Init():初始化 RTC 外设。

  • RTC_SetTime() 和 RTC_SetDate():设置初始时间和日期。

  • RTC_GetTime() 和 RTC_GetDate():读取当前时间和日期。

  • printf():打印时间和日期(需要重定向串口)。

  • HAL_Delay(1000):延时 1 秒。

PWR电源控制

修改主频的配置

修改主频是通过配置系统时钟源和分频器来实现的。STM32 的时钟源包括:

  • HSI:内部高速时钟(通常为 8 MHz)。

  • HSE:外部高速时钟(通常为 8-25 MHz)。

  • PLL:锁相环,用于倍频时钟。

代码实现
void SystemClock_Config(void) {RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};// 配置HSE和PLLRCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 8;RCC_OscInitStruct.PLL.PLLN = 336;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;RCC_OscInitStruct.PLL.PLLQ = 7;HAL_RCC_OscConfig(&RCC_OscInitStruct);// 配置时钟树RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
}
  1. HSE(外部高速时钟)

    • HSE通常是一个外部晶振(如8MHz),提供更精确和稳定的时钟源。

    • RCC_OscInitStruct.HSEState = RCC_HSE_ON:启用HSE。

  2. PLL(锁相环)

    • PLL用于将输入时钟倍频到更高的频率。

    • PLLM = 8:将HSE时钟分频为1MHz(8MHz / 8 = 1MHz)。

    • PLLN = 336:将1MHz倍频到336MHz。

    • PLLP = RCC_PLLP_DIV2:将PLL输出分频为168MHz(336MHz / 2 = 168MHz),作为系统时钟(SYSCLK)。

    • PLLQ = 7:用于生成USB、SDIO等外设的时钟。

  3. 时钟树配置

    • SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK:选择PLL输出作为系统时钟。

    • AHBCLKDivider = RCC_SYSCLK_DIV1:AHB总线时钟与系统时钟相同(168MHz)。

    • APB1CLKDivider = RCC_HCLK_DIV4:APB1总线时钟为42MHz(168MHz / 4)。

    • APB2CLKDivider = RCC_HCLK_DIV2:APB2总线时钟为84MHz(168MHz / 2)。

  4. FLASH_LATENCY

    • 根据主频设置FLASH延迟,确保CPU能够正确读取FLASH中的数据。168MHz需要FLASH_LATENCY_5

睡眠模式的配置

睡眠模式下,CPU停止运行,但外设和时钟仍然运行。可以通过WFI(等待中断)或WFE(等待事件)指令进入睡眠模式。

代码解析:

void Enter_Sleep_Mode(void) {HAL_SuspendTick();  // 挂起SysTickHAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);HAL_ResumeTick();   // 恢复SysTick
}

配置原因:

  1. 挂起SysTick

    • HAL_SuspendTick():在进入睡眠模式前,挂起SysTick定时器,避免其产生中断唤醒CPU。

  2. 进入睡眠模式

    • HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI)

      • PWR_MAINREGULATOR_ON:保持主稳压器开启,以快速恢复运行。

      • PWR_SLEEPENTRY_WFI:使用WFI指令进入睡眠模式。

  3. 恢复SysTick

    • HAL_ResumeTick():退出睡眠模式后,恢复SysTick定时器。

停止模式的配置

停止模式下,所有时钟都停止,但SRAM和寄存器内容保持不变。可以通过WFIWFE指令进入停止模式。

代码解析:

void Enter_Stop_Mode(void) {HAL_SuspendTick();  // 挂起SysTickHAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);HAL_ResumeTick();   // 恢复SysTickSystemClock_Config();  // 重新配置时钟
}

配置原因:

  1. 挂起SysTick

    • HAL_SuspendTick():挂起SysTick定时器。

  2. 进入停止模式

    • HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI)

      • PWR_LOWPOWERREGULATOR_ON:启用低功耗稳压器,进一步降低功耗。

      • PWR_STOPENTRY_WFI:使用WFI指令进入停止模式。

  3. 恢复时钟

    • 退出停止模式后,时钟会被关闭,因此需要重新配置时钟树(SystemClock_Config())。

 待机模式的配置

待机模式下,除了备份域和待机电路,所有时钟和电源都被关闭。可以通过WFIWFE指令进入待机模式。

代码解析:

void Enter_Standby_Mode(void) {HAL_PWR_EnterSTANDBYMode();
}

配置原因:

  1. 进入待机模式

    • HAL_PWR_EnterSTANDBYMode():关闭所有时钟和电源,仅保留备份域和待机电路。

    • 唤醒后,系统会从头开始执行(类似于复位)。

总结

  • 修改主频:通过配置时钟树,选择合适的时钟源和PLL参数,达到所需的主频。

  • 睡眠模式:挂起SysTick,使用WFI进入睡眠模式,适用于需要快速唤醒的场景。

  • 停止模式:挂起SysTick,使用WFI进入停止模式,适用于需要更低功耗的场景。

  • 待机模式:直接进入待机模式,适用于需要最低功耗的场景。

WDG看门狗

看门狗(Watchdog,简称WDG)是嵌入式系统中用于检测和恢复系统故障的重要机制。它的核心原理是通过定时器监控系统的运行状态,如果系统在一定时间内未能正常“喂狗”(即重置看门狗定时器),看门狗会强制复位系统,从而防止系统因软件错误或硬件故障而进入死循环或卡死状态。

看门狗的基本原理

看门狗的核心是一个递减计数器(或递增计数器),当计数器达到特定值时,看门狗会触发系统复位。为了防止复位,系统需要定期“喂狗”,即在计数器达到特定值之前重置计数器。

工作流程:

  1. 初始化看门狗

    • 配置看门狗的计数器初始值和超时时间。

  2. 启动看门狗

    • 启动看门狗定时器,计数器开始递减(或递增)。

  3. 喂狗

    • 在程序正常运行期间,定期重置看门狗计数器。

  4. 超时复位

    • 如果程序未能及时喂狗,计数器达到超时值,看门狗触发系统复位。

  1. 独立看门狗(IWDG,Independent Watchdog)

    • 由独立的硬件模块实现,通常使用内部低速时钟(LSI)作为时钟源。

    • 独立于主系统时钟,即使主系统时钟失效,独立看门狗仍能正常工作。

    • 适用于检测系统死机或严重故障。

  2. 窗口看门狗(WWDG,Window Watchdog)

    • 由主系统时钟驱动,通常用于检测软件逻辑错误。

    • 喂狗时间必须在规定的“窗口”内,过早或过晚喂狗都会触发复位。

    • 适用于检测程序跑飞或逻辑错误。

独立看门狗(IWDG)配置示例(STM32 HAL库)

#include "stm32f4xx_hal.h"void IWDG_Init(void) {// 初始化独立看门狗hiwdg.Instance = IWDG;hiwdg.Init.Prescaler = IWDG_PRESCALER_32;  // 预分频系数hiwdg.Init.Reload = 4095;                 // 计数器初值HAL_IWDG_Init(&hiwdg);
}void IWDG_Feed(void) {// 喂狗HAL_IWDG_Refresh(&hiwdg);
}

窗口看门狗(WWDG)配置示例(STM32 HAL库):

#include "stm32f4xx_hal.h"void WWDG_Init(void) {// 初始化窗口看门狗hwwdg.Instance = WWDG;hwwdg.Init.Prescaler = WWDG_PRESCALER_8;  // 预分频系数hwwdg.Init.Window = 0x5F;                // 上窗口值hwwdg.Init.Counter = 0x7F;               // 计数器初值hwwdg.Init.EWIMode = WWDG_EWI_DISABLE;   // 禁用早期唤醒中断HAL_WWDG_Init(&hwwdg);
}void WWDG_Feed(void) {// 喂狗HAL_WWDG_Refresh(&hwwdg);
}

 Flash 内存的特点

  1. 非易失性

    • 数据在断电后不会丢失。

  2. 按扇区管理

    • Flash 内存通常分为多个扇区,每个扇区可以独立擦除和编程。

  3. 有限的擦写次数

    • Flash 内存的擦写次数有限(通常为 10,000 到 100,000 次),因此需要谨慎使用。

  4. 读写速度较慢

    • 相比 RAM,Flash 的读写速度较慢,尤其是写操作需要较长时间。

  5. 写前需擦除

    • Flash 内存的写操作需要先擦除,擦除的最小单位通常是一个扇区。

STM32 的 Flash 内存结构

以 STM32F4 系列为例,Flash 内存的结构如下:

  • 主存储区:用于存储程序代码和数据。

  • 系统存储区:存储 Bootloader 代码(由 ST 提供,用于串口或 USB 下载程序)。

  • 选项字节:用于配置读写保护、看门狗、复位模式等。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词