【stm32】RTC时钟的介绍与使用

RTC时钟的介绍与使用

  • 一、时间戳
    • 1、Unix时间戳
    • 2、UTC/GMT
    • 3、时间戳转换
  • 二、BKP简介及代码编写
    • 1、BKP简介
    • 2、BKP基本结构
    • 3、BKP库函数介绍:
    • 4、程序编写:
  • 三、RTC简介及代码编写
    • 1、RTC简介
    • 2、RTC框图
    • 2、RTC基本结构
    • 3、RTC相关库函数介绍:
    • 4、程序编写:
    • 5、RTC操作注意事项

一、时间戳

1、Unix时间戳

  • Unix 时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒
  • 时间戳是一个计数器数值,这个数值表示从1970年1月1日0时0分0秒开始到现在总共所经过的秒数
  • 时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量
  • 世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间
    在这里插入图片描述

2、UTC/GMT

  • GMT(Greenwich Mean Time)格林尼治标准时间(伦敦标准时间)是一种以地球自转为基础的时间计量系统。它将地球自转一周的时间间隔等分为24小时,以此确定计时标准
  • UTC(Universal Time Coordinated)协调世界时是一种以原子钟为基础的时间计量系统。它规定铯133原子基态的两个超精细能级间在零磁场下跃迁辐射9,192,631,770周所持续的时间为1秒。当原子钟计时一天的时间与地球自转一周的时间相差超过0.9秒时,UTC会执行闰秒来保证其计时与地球自转的协调一致

3、时间戳转换

\quad C语言的time.h模块提供了时间获取和时间戳转换的相关函数,可以方便地进行秒计数器、日期时间和字符串之间的转换。
在这里插入图片描述

在这里插入图片描述

二、BKP简介及代码编写

1、BKP简介

  • BKP(Backup Registers)备份寄存器
  • BKP可用于存储用户应用程序数据。当VDD(2.0-3.6V)电源被切断,他们仍然由VBAT(1.8~3.6V)维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位
    • VSS1、VDD1、VSS2、VDD2、VSS3、VDD3是内部数字部分电路的供电,VDDA、VSSA 是内部模拟部分电路的供电,以上四组以VDD开头的供电,都是系统的主电源,在正常使用STM32时,以上四组供电均都需要接到33V的电源上;VBAT 是备用电池供电引脚,如果要使用STM32内部的BKP和RTC,该引脚必须接备用电池,用来维持BKP和RTC,在VDD主电源掉电后的供电。
  • TAMPER引脚产生的侵入事件将所有备份寄存器内容清除
    • TAMPER引脚:用于安全保障设计
  • RTC引脚输出RTC校准时钟、RTC闹钟脉冲或者秒脉冲(RTC配置)
  • 存储RTC时钟校准寄存器(RTC配置)
  • 用户数据存储容量:
    • 20字节(中容量和小容量设备中BKP为20字节)/ 84字节(大容量和互联型设备中BKP为84字节)

2、BKP基本结构

在这里插入图片描述
\quad 后备区域:指的是BKP备份寄存器、RTC相关电路
\quad STM32后备区域的特性:当VDD主电源掉电时,后备区域仍然可以由VBAT的备用电池供电;当VDD主电源上电时,后备区域供电会由VBAT切换到VDD

3、BKP库函数介绍:

void BKP_DeInit(void);  // 恢复缺省配置
void BKP_TamperPinLevelConfig(uint16_t BKP_TamperPinLevel);// 配置TAMPER引脚的有效电平
void BKP_TamperPinCmd(FunctionalState NewState);// 是否开启侵入检测功能LMDDUGd
void BKP_ITConfig(FunctionalState NewState);// 中断配置,
void BKP_RTCOutputConfig(uint16_t BKP_RTCOutputSource);//时钟输出功能配置
void BKP_SetRTCCalibrationValue(uint8_t CalibrationValue);// 设置RTC校准值
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);// 写备份寄存器
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);// 读备份寄存器
FlagStatus BKP_GetFlagStatus(void);
void BKP_ClearFlag(void);
ITStatus BKP_GetITStatus(void);
void BKP_ClearITPendingBit(void);

4、程序编写:

现象:PB1引脚接上按键,按下按键,数组的值写入BKP寄存器,主电源掉电后,能保存最后一次变化的值;若VBT也掉电,则BKP寄存器的值会被清空

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Key.h"uint8_t KeyNum;uint16_t ArrayWrite[] = {0x1234, 0x5678};
uint16_t ArrayRead[2];int main(void)
{OLED_Init();Key_Init();OLED_ShowString(1, 1, "W:");OLED_ShowString(2, 1, "R:");RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE); // 开启PWR的时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE); // 开启BKP的时钟PWR_BackupAccessCmd(ENABLE); // PWR备份访问控制while (1){KeyNum = Key_GetNum();if (KeyNum == 1){ArrayWrite[0] ++;ArrayWrite[1] ++;BKP_WriteBackupRegister(BKP_DR1, ArrayWrite[0]);BKP_WriteBackupRegister(BKP_DR2, ArrayWrite[1]);OLED_ShowHexNum(1, 3, ArrayWrite[0], 4);OLED_ShowHexNum(1, 8, ArrayWrite[1], 4);}ArrayRead[0] = BKP_ReadBackupRegister(BKP_DR1);ArrayRead[1] = BKP_ReadBackupRegister(BKP_DR2);OLED_ShowHexNum(2, 3, ArrayRead[0], 4);OLED_ShowHexNum(2, 8, ArrayRead[1], 4);}
}

三、RTC简介及代码编写

1、RTC简介

  • RTC(Real Time Clock)实时时钟
  • RTC是一个独立的定时器,可为系统提供时钟和日历的功能
  • RTC和时钟配置系统处于后备区域,系统复位时数据不清零,VDD(2.0-3.6V)断电后可借助VBAT(1.8~3.6V)供电继续走时
  • 32位的可编程计数器,可对应Unix时间戳的秒计数器
  • 20位的可编程预分频器,可适配不同频率的输入时钟
  • 可选择三种RTC时钟源:
    HSE时钟除以128(通常为8MHz/128)
    LSE振荡器时钟(通常为32.768KHz)
    LSI振荡器时钟(40KHz)

2、RTC框图

在这里插入图片描述

  • 核心部分:(中左)分频和计数计时部分, (中右)中断输出使能和NVIC部分,(上)APB1总线读写部分,(下)与PWR关联的部分(作用是RTC的闹钟可以唤醒设备,退出待机模式),灰色区域为后备区域,在主电源掉电后可以使用备用电池维持供电
    • 分频和计数计时部分:RTCCLK—>RTC预分频器进行分频(由两个寄存器组成:重装载寄存器RTC_PRL-也是计数目标、RTC_DIV余数寄存器-自减计数器,存储当前的计数值 )—>32位可编程计数器(可以看作是Unix时间戳的秒计数器,闹钟寄存器RTC_ALR:当CNT的值跟ALR设定的闹钟值一样时,产生RTC_Alarm闹钟信号,通往右边的中断系统,另外一个功能是闹钟信号可以让STM32退出待机模式)
    • 中断部分:以下三个信号可触发中断,
      1、RTC_Second,秒中断,来源于CNT的输入时钟,如果开启此中断,程序会每秒进一次RTC中断
      2、RTC_Overflow,溢出中断,当CNT的32位计数器计满溢出,会触发一次中断
      3、RTC_Alarm,闹钟中断,当计数器和闹钟值相等时,触发中断,同时,闹钟信号可以把设备从待机模式唤醒
    • 中断标志位和中断输出控制:F(Flag)结尾的是对应的中断标志位,IE(Interrupt Enable)结尾的是中断使能,最后3个信号通过一个或门,进入到NVIC中断控制器
    • APB1总线和APB1接口:程序读写寄存器的地方

PCLK1在主电源掉电后停止,为了保证RTC主电源掉电正常工作,RTC里的寄存器都是在RTCCLK的同步下变更的,当我们用PCLK1驱动的总线,去读取RTCCLK驱动的寄存器时,就会有一个时钟不同步的问题,RTC奇存器,只有在RTCCLK的上升沿更新,但是PCLK1的频率36MHZ,远大于RTCCLK的频率32KHZ,如果在APB1刚开启时,就立刻读取RTC奇存器,有可能RTC寄存器还没有更新到APB1总线上,此时读取到的值,就是错误的(通常读取到0),所以要求,在APB1总线刚开启时,等待RTCCLK的触发上升沿后,RTC把它所在寄存器的值同步到APB1总线上,之后再读取的值就是正确的
对于使用库函数,只需在初始化时,调用一个等待同步的函数即可实现

\quad 32位可编程计数器:对应时间戳中的秒计数器,在读取时间时,得到的是秒数,再使用time.h模块里的localtime函数,即可得到年月日时分秒的信息;写入时间时,先填充年月日时分秒信息到struct tm结构体,在用mktime函数,得到秒数,写入32位计数器即可
\quad 20位的可编程预分频器:对于32位秒计数器,1s需要自增一次, 所以驱动计数器的时钟需要1HZ的信号,但实际提供给RTC的时钟RTCCLK的频率较高,此时就需要在提供给计数器时钟前加一个分频器降频,保证分频器输出给计数器的频率为1HZ,计时才是对的,为了适配各种频率的RTCCLK,加了一个20位的分频器,可以选择对输入时钟进行1~2^20范围的分频

高速时钟,一般供内部程序运行和主要外设使用
低速时钟,一般供RTC、看门狗使用

2、RTC基本结构

在这里插入图片描述

3、RTC相关库函数介绍:

// rcc.h
void RCC_LSEConfig(uint8_t RCC_LSE);      // 配置LSE外部低速时钟
void RCC_LSICmd(FunctionalState NewState);// 配置LSI内部低速时钟
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);// RTCCLK配置,选择RTCCLK的时钟源
void RCC_RTCCLKCmd(FunctionalState NewState);// 启动RTCCLKvoid RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);// 配置中断输出
void RTC_EnterConfigMode(void);// 进入配置模式
void RTC_ExitConfigMode(void);// 退出配置模式
uint32_t  RTC_GetCounter(void);// 获取CNT计数器的值  读取时钟
void RTC_SetCounter(uint32_t CounterValue); // 写入CNT计数器的值  设置时间
void RTC_SetPrescaler(uint32_t PrescalerValue);// 写入预分频器(PRL重装寄存器,用来配置预分频器的分频系数)
void RTC_SetAlarm(uint32_t AlarmValue);// 写入闹钟值
uint32_t  RTC_GetDivider(void);// 读取预分频器中的DIV余数寄存器
void RTC_WaitForLastTask(void);// 等待上次操作完成
void RTC_WaitForSynchro(void);// 等待同步
FlagStatus RTC_GetFlagStatus(uint16_t RTC_FLAG);
void RTC_ClearFlag(uint16_t RTC_FLAG);
ITStatus RTC_GetITStatus(uint16_t RTC_IT);
void RTC_ClearITPendingBit(uint16_t RTC_IT);

4、程序编写:

// myRTC.c
#include "stm32f10x.h"                  // Device header
#include <time.h>uint16_t MyRTC_Time[] = {2023, 1, 1, 23, 59, 55};void MyRTC_SetTime(void);void MyRTC_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);PWR_BackupAccessCmd(ENABLE); // 电源控制寄存器(PWR_CR) 的 DBP 位来使能对后备寄存器和 RTC 的访问// 如果BKP 寄存器被清0,说明备用电池断电,才需要初始化RTC,重新设置时间if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)  {RCC_LSEConfig(RCC_LSE_ON);  // 配置LSE外部低速时钟while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) != SET);// 等待标志位RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);// 选择RTCCLK时钟源RCC_RTCCLKCmd(ENABLE);  // 使能RTC时钟RTC_WaitForSynchro();  // 等待同步RTC_WaitForLastTask(); // 等待上一次操作完成//RTC_SetPrescaler(32768 - 1); // 配置预分频器;LSE频率:32768HZ,得到1HZ:32768/(32768-1)RTC_WaitForLastTask();  // 等待上一次操作完成MyRTC_SetTime();// 将A5A5写入到BKP寄存器中,备用电源断电才会被清0,确保在有备用电源供电的情况下只初始化一次BKP_WriteBackupRegister(BKP_DR1, 0xA5A5); }else  // 写入BKP寄存器的数据未被清0{RTC_WaitForSynchro(); // 等待同步RTC_WaitForLastTask();// 等待操作完成}
}//如果LSE无法起振导致程序卡死在初始化函数中
//可将初始化函数替换为下述代码,使用LSI当作RTCCLK
//LSI无法由备用电源供电,故主电源掉电时,RTC走时会暂停
/* 
void MyRTC_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);PWR_BackupAccessCmd(ENABLE);if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5){RCC_LSICmd(ENABLE);while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != SET);RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);RCC_RTCCLKCmd(ENABLE);RTC_WaitForSynchro();RTC_WaitForLastTask();RTC_SetPrescaler(40000 - 1);RTC_WaitForLastTask();MyRTC_SetTime();BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);}else{RCC_LSICmd(ENABLE);while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) != SET);RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);RCC_RTCCLKCmd(ENABLE);RTC_WaitForSynchro();RTC_WaitForLastTask();}
}*/void MyRTC_SetTime(void)
{time_t time_cnt;struct tm time_date;// 将时间填入struct tm结构体time_date.tm_year = MyRTC_Time[0] - 1900;time_date.tm_mon = MyRTC_Time[1] - 1;time_date.tm_mday = MyRTC_Time[2];time_date.tm_hour = MyRTC_Time[3];time_date.tm_min = MyRTC_Time[4];time_date.tm_sec = MyRTC_Time[5];time_cnt = mktime(&time_date) - 8 * 60 * 60;   // 日期时间转换成秒计数器RTC_SetCounter(time_cnt);  // 把指定的秒数写入RTC的CNT寄存器RTC_WaitForLastTask();     // 等待操作完成 
}void MyRTC_ReadTime(void)
{time_t time_cnt;struct tm time_date;time_cnt = RTC_GetCounter() + 8 * 60 * 60;  // 读取CNT寄存器中的秒数存储到time_cnt  转换为东八区(+8h)time_date = *localtime(&time_cnt);// 将秒数转成日期时间MyRTC_Time[0] = time_date.tm_year + 1900;MyRTC_Time[1] = time_date.tm_mon + 1;MyRTC_Time[2] = time_date.tm_mday;MyRTC_Time[3] = time_date.tm_hour;MyRTC_Time[4] = time_date.tm_min;MyRTC_Time[5] = time_date.tm_sec;
}
//myRTC.h
#ifndef __MYRTC_H
#define __MYRTC_Hextern uint16_t MyRTC_Time[];void MyRTC_Init(void);
void MyRTC_SetTime(void);
void MyRTC_ReadTime(void);#endif
//main.c
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"int main(void)
{OLED_Init();MyRTC_Init();OLED_ShowString(1, 1, "Date:XXXX-XX-XX");OLED_ShowString(2, 1, "Time:XX:XX:XX");OLED_ShowString(3, 1, "CNT :");OLED_ShowString(4, 1, "DIV :");while (1){MyRTC_ReadTime();  // 读取RTC时间OLED_ShowNum(1, 6, MyRTC_Time[0], 4);OLED_ShowNum(1, 11, MyRTC_Time[1], 2);OLED_ShowNum(1, 14, MyRTC_Time[2], 2);OLED_ShowNum(2, 6, MyRTC_Time[3], 2);OLED_ShowNum(2, 9, MyRTC_Time[4], 2);OLED_ShowNum(2, 12, MyRTC_Time[5], 2);OLED_ShowNum(3, 6, RTC_GetCounter(), 10);
//        OLED_ShowNum(4, 6, RTC_GetDivider(), 10);// 从32767减到0 为1s// 32767-0 为1000ms 线性转换成0-999 1000msOLED_ShowNum(4, 6, (32767-RTC_GetDivider()) / 32767.0 * 999, 10);// 从32767减到0 为1s}
}

5、RTC操作注意事项

  • 执行以下操作将使能对BKP和RTC的访问:
    设置RCC_APB1ENR的PWREN和BKPEN,使能PWR和BKP时钟
    设置PWR_CR的DBP,使能对BKP和RTC的访问
  • 若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1
  • 必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器
  • 对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器

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

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

相关文章

界面控件DevExpress JS ASP.NET Core v24.1亮点 - 支持Angular 18

DevExtreme拥有高性能的HTML5 / JavaScript小部件集合&#xff0c;使您可以利用现代Web开发堆栈&#xff08;包括React&#xff0c;Angular&#xff0c;ASP.NET Core&#xff0c;jQuery&#xff0c;Knockout等&#xff09;构建交互式的Web应用程序。从Angular和Reac&#xff0c…

如何检索 LINEMOD 数据集的相机内参

简介 BOP (Benchmark for 6D Object Pose Estimation) 是一个专为6D物体姿态估计而设计的基准测试平台。它为研究人员提供了多种数据集&#xff0c;以帮助评估和比较物体识别和姿态估计算法的性能。官方网站是 BOP&#xff0c;你可以在这里找到丰富的资源和信息。 检索 LINEM…

机器学习与数据挖掘_使用梯度下降法训练线性回归模型

目录 实验内容 实验步骤 1. 导入必要的库 2. 加载数据并绘制散点图 3. 设置模型的超参数 4. 实现梯度下降算法 5. 打印训练后的参数和损失值 6. 绘制损失函数随迭代次数的变化图 7. 绘制线性回归拟合曲线 8. 基于训练好的模型进行新样本预测 实验代码 实验结果 实验…

web——sqliabs靶场——第一关

今天开始搞这个靶场&#xff0c;从小白开始一点点学习,加油&#xff01;&#xff01;&#xff01;&#xff01; 1.搭建靶场 注意点&#xff1a;1.php的版本问题&#xff0c;要用老版本 2.小p要先改数据库的密码&#xff0c;否则一直显示链接不上数据库 2.第一道题&#xff0…

Xamarin 实现播放视频 MP4

我的想法是在App启动时播放一段视频&#xff0c;实现方式如下&#xff1a; 准备一个视频&#xff1a; Logo.mp4 添加到资源中&#xff1a;Assets 然后将资源设置为 AndroidAsset 启动时&#xff0c;将资源文件拷贝到程序目录的files下&#xff1a; protected override void On…

4070显卡只要一毛钱?这个双十一太疯狂了

2024年双十一大战正酣&#xff0c;各大商家使尽浑身解数&#xff0c;奇招频出&#xff0c;真是让人看得目瞪口呆。每日口令红包、攒火力值领裂变红包、限时抢免定金红包……还有各类满减和打折优惠活动&#xff0c;玩法千奇百怪&#xff0c;算来算去索性放弃&#xff0c;真是没…

C++优选算法四 前缀和

前缀和算法是一种常用的优化技术&#xff0c;主要用于加速某些涉及连续子数组或子序列求和的问题。 一、定义与原理 定义&#xff1a;前缀和是指数组中某个位置之前&#xff08;包括该位置&#xff09;所有元素的和。前缀和算法则是通过提前计算并存储这些前缀和&#xff0c;…

yum安装指定版本Redis

一&#xff0c;yum安装Redis 1&#xff0c;列出可用的redis版本 yum --showduplicates list redis 只有5.0.3.5版本&#xff0c;如果已经满足需求&#xff0c;可以直接安装 2&#xff0c;安装redis yum -y install 如果显示installed&#xff0c; 说明安装成功了 也可以通过…

DAY21|二叉树Part08|LeetCode: 669. 修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

目录 LeetCode: 669. 修剪二叉搜索树 基本思路 C代码 LeetCode: 108.将有序数组转换为二叉搜索树 基本思路 C代码 LeetCode: 538.把二叉搜索树转换为累加树 基本思路 C代码 LeetCode: 669. 修剪二叉搜索树 力扣代码链接 文字讲解&#xff1a;LeetCode: 669. 修剪二叉搜…

HarmonyOS基础:鸿蒙系统组件导航Navigation

大家好&#xff01;我是黑臂麒麟&#xff08;起名原因&#xff1a;一个出生全右臂自带纹身的高质量程序员&#x1f60f;&#xff09;&#xff0c;也是一位6&#xff08;约2个半坤年&#xff09;的前端&#xff1b; 学习如像练武功一样&#xff0c;理论和实践要相结合&#xff0…

​Houdini云渲染如何使用?如何让一个镜头使用成百上千台机器渲染,提高渲染效率

​Houdini云渲染如何使用&#xff1f;如何让一个镜头使用成百上千台机器渲染&#xff0c;提高渲染效率呢&#xff0c;最简单的教程来了&#xff01; 第一步&#xff1a;云渲码6666注册成都渲染101&#xff0c;并且下载渲染101客户端 客户端是上传下载的工具&#xff0c;将文件…

如何使用Varjo直接观看Blender内容

最近&#xff0c;开源的3D建模程序Blender为Varjo提供了出色的OpenXR支持&#xff0c;包括四视图和凹进渲染扩展。但是在Blender中&#xff0c;默认不启用VR场景检查。要开始使用VR场景检查&#xff0c;只需遵循以下步骤&#xff1a; 1. 下载并安装Blender 2.启用Blender VR场景…

linux 安装anaconda3

1.下载 使用repo镜像网址下载对应安装包 右击获取下载地址&#xff0c;使用终端下载 wget https://repo.anaconda.com/archive/Anaconda3-2024.02-1-Linux-x86_64.sh2.安装 使用以下命令可直接指定位置 bash Anaconda3-2024.02-1-Linux-x86_64.sh -b -p /home/anaconda3也…

JavaScript。—关于语法基础的理解—

一、程序控制语句 JavaScript 提供了 if 、if else 和 switch 3种条件语句&#xff0c;条件语句也可以嵌套。 &#xff08;一&#xff09;、条件语句 1、单向判断 &#xff1a; if... &#xff08;1&#xff09;概述 < if >元素用于在判断该语句是否满足特定条…

DDD学习笔记

DDD学习笔记 1. 什么是 DDD&#xff1f; 领域驱动设计&#xff08;Domain-Driven Design, DDD&#xff09;是一种复杂软件系统设计的方法&#xff0c;强调以业务领域为核心进行设计与开发。它通过将业务逻辑与代码组织紧密结合&#xff0c;帮助开发团队更好地理解和实现业务需…

c语言简单编程练习8

1、递归函数&#xff1a; 通过调用自身来解决问题的函数&#xff0c;递归也就是传递和回归&#xff1b; 递归函数的两个条件&#xff1a; 1&#xff09;函数调用函数本身 2&#xff09;一定要有结束条件 循环与递归的区别&#xff1a; 每调用一次递归函数&#xff0c;都会…

如何将MySQL彻底卸载干净

目录 背景&#xff1a; MySQL的卸载 步骤1&#xff1a;停止MySQL服务 步骤2&#xff1a;软件的卸载 步骤3&#xff1a;残余文件的清理 步骤4&#xff1a;清理注册表 步骤五:删除环境变量配置 总结&#xff1a; 背景&#xff1a; MySQL卸载不彻底往往会导致重新安装失败…

linux-环境变量

环境变量是系统提供的一组 name value 的变量&#xff0c;不同的变量有不同的用途&#xff0c;通常都具有全局属性 env 查看环境变量 PATH PATH是一个保存着系统指令路径的一个环境变量&#xff0c;系统提供的指令不需要路径&#xff0c;直接就可以使用就是因为指令的路径…

IDEA修改生成jar包名字的两种方法实现

IDEA修改生成jar包名字的两种方法实现 更新时间&#xff1a;2023年08月18日 11:45:36 作者&#xff1a;白白白鲤鱼 本文主要介绍了IDEA修改生成jar包名字的两种方法实现,通过简单的步骤,您可以修改项目名称并在打包时使用新的名称,具有一定的参考价值,感兴趣的可以了解下 …

【Java Web】JSP实现数据传递和保存(中)中文乱码 转发与重定向

文章目录 中文乱码转发与重定向转发重定向区别 升级示例1 中文乱码 JSP 中默认使用的字符编码方式&#xff1a;iso-8859-1&#xff0c;不支持中文。常见的支持中文的编码方式及其收录的字符&#xff1a; gb2312&#xff1a;常用简体汉字gbk&#xff1a;简体和繁体汉字utf-8&a…