HAL库源码移植与使用之RTC时钟

实时时钟(Real Time Clock,RTC),本质是一个计数器,计数频率常为秒,专门用来记录时间。

普通定时器无法掉电运行!但RTC可由VBAT备用电源供电,断电不断时

这里讲F1系列的RTC

可以产生三个中断信号,秒  闹钟  溢出信号

其中闹钟可以唤醒wwdg和iwdg

后备寄存器:

后备寄存器不仅有存数据的地方还有存状态,存配置rtc等后备外设的配置寄存器的存在,这些寄存器全部都复位不重置,所以可以在有备用电池的状态下做点文章

因为rcc内有状态位在不断电情况下可以知道上次复位是因为什么造成的

标准库还有用后备寄存器存数据的  temper引脚防破解  校准时钟输出等实验,正点原子hal教学没有,得自己探索

你选时钟源的时候如果32.768khz坏了,也可以选择rc振荡器40khz和高速内部rc振荡器但不推荐,因为他俩很容易受外部影响

你可以获取分频器的分频计数值来更加精确的处理得出时间 

函数解析:

下面的函数是正点原子自己写的,专门用于处理时间戳的函数,你也可以自己用time.h跟标准库那时候一样

rtc.c

#include "./BSP/RTC/rtc.h"
#include "./BSP/LED/led.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"RTC_HandleTypeDef g_rtc_handle; /* RTC控制句柄 */
_calendar_obj calendar;         /* 时间结构体 *//*** @brief       RTC写入后备区域SRAM* @param       bkrx : 后备区寄存器编号,范围:0~41对应 RTC_BKP_DR1~RTC_BKP_DR42* @param       data : 要写入的数据,16位长度* @retval      无*/
void rtc_write_bkr(uint32_t bkrx, uint16_t data)
{HAL_PWR_EnableBkUpAccess(); /* 取消备份区写保护 */HAL_RTCEx_BKUPWrite(&g_rtc_handle, bkrx + 1, data);
}/*** @brief       RTC读取后备区域SRAM* @param       bkrx : 后备区寄存器编号,范围:0~41对应 RTC_BKP_DR1~RTC_BKP_DR42* @retval      读取到的值*/
uint16_t rtc_read_bkr(uint32_t bkrx)
{uint32_t temp = 0;temp = HAL_RTCEx_BKUPRead(&g_rtc_handle, bkrx + 1);return (uint16_t)temp; /* 返回读取到的值 */
}/*** @brief       RTC初始化*   @note*              默认尝试使用LSE,当LSE启动失败后,切换为LSI.*              通过BKP寄存器0的值,可以判断RTC使用的是LSE/LSI:*              当BKP0==0X5050时,使用的是LSE*              当BKP0==0X5051时,使用的是LSI*              注意:切换LSI/LSE将导致时间/日期丢失,切换后需重新设置.** @param       无* @retval      0,成功*              1,进入初始化模式失败*/
uint8_t rtc_init(void)
{/* 检查是不是第一次配置时钟 */uint16_t bkpflag = 0;__HAL_RCC_PWR_CLK_ENABLE(); /* 使能PWR电源时钟 */__HAL_RCC_BKP_CLK_ENABLE(); /* 使能BKP备份时钟 */HAL_PWR_EnableBkUpAccess(); /* 取消备份区写保护 */g_rtc_handle.Instance = RTC;g_rtc_handle.Init.AsynchPrediv = 32767;     /* 时钟周期设置,理论值:32767, 这里也可以用 RTC_AUTO_1_SECOND */g_rtc_handle.Init.OutPut = RTC_OUTPUTSOURCE_NONE;if (HAL_RTC_Init(&g_rtc_handle) != HAL_OK)  /* 初始化RTC */{return 1;}bkpflag = rtc_read_bkr(0);  /* 读取BKP0的值 */if ((bkpflag != 0X5050) && (bkpflag != 0x5051))         /* 之前未初始化过,重新配置 */{rtc_set_time(2020, 4, 25, 20, 25, 35);              /* 设置时间 */}__HAL_RTC_ALARM_ENABLE_IT(&g_rtc_handle, RTC_IT_SEC);   /* 允许秒中断 */__HAL_RTC_ALARM_ENABLE_IT(&g_rtc_handle, RTC_IT_ALRA);  /* 允许闹钟中断 */HAL_NVIC_SetPriority(RTC_IRQn, 0x2, 0);                 /* 设置RTC中断 */HAL_NVIC_EnableIRQ(RTC_IRQn);                           /* 使能中断 */rtc_get_time(); /* 更新时间 */return 0;
}/*** @brief       RTC初始化*   @note*              RTC底层驱动,时钟配置,此函数会被HAL_RTC_Init()调用* @param       hrtc:RTC句柄* @retval      无*/
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{uint16_t retry = 200;__HAL_RCC_RTC_ENABLE();     /* RTC时钟使能 */RCC_OscInitTypeDef rcc_oscinitstruct;RCC_PeriphCLKInitTypeDef rcc_periphclkinitstruct;/* 使用寄存器的方式去检测LSE是否可以正常工作 */RCC->BDCR |= 1 << 0;    /* 开启外部低速振荡器LSE */while (retry && ((RCC->BDCR & 0X02) == 0))  /* 等待LSE准备好 */{retry--;delay_ms(5);}if (retry == 0)     /* LSE起振失败 使用LSI */{rcc_oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_LSI;  /* 选择要配置的振荡器 */rcc_oscinitstruct.LSIState = RCC_LSI_ON;                    /* LSI状态:开启 */rcc_oscinitstruct.PLL.PLLState = RCC_PLL_NONE;              /* PLL无配置 */HAL_RCC_OscConfig(&rcc_oscinitstruct);                      /* 配置设置的rcc_oscinitstruct */rcc_periphclkinitstruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;   /* 选择要配置的外设 RTC */rcc_periphclkinitstruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;   /* RTC时钟源选择 LSI */HAL_RCCEx_PeriphCLKConfig(&rcc_periphclkinitstruct);                /* 配置设置的rcc_periphClkInitStruct */rtc_write_bkr(0, 0X5051);}else{rcc_oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_LSE ; /* 选择要配置的振荡器 */rcc_oscinitstruct.LSEState = RCC_LSE_ON;                    /* LSE状态:开启 */rcc_oscinitstruct.PLL.PLLState = RCC_PLL_NONE;              /* PLL不配置 */HAL_RCC_OscConfig(&rcc_oscinitstruct);                      /* 配置设置的rcc_oscinitstruct */rcc_periphclkinitstruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;   /* 选择要配置外设 RTC */rcc_periphclkinitstruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;   /* RTC时钟源选择LSE */HAL_RCCEx_PeriphCLKConfig(&rcc_periphclkinitstruct);                /* 配置设置的rcc_periphclkinitstruct */rtc_write_bkr(0, 0X5055);}
}/*** @brief       RTC时钟中断*   @note      秒钟中断 / 闹钟中断 共用同一个中断服务函数*              根据RTC_CRL寄存器的 SECF 和 ALRF 位区分是哪个中断* @param       无* @retval      无*/
void RTC_IRQHandler(void)
{if (__HAL_RTC_ALARM_GET_FLAG(&g_rtc_handle, RTC_FLAG_SEC) != RESET)     /* 秒中断 */{rtc_get_time();     /* 更新时间 */__HAL_RTC_ALARM_CLEAR_FLAG(&g_rtc_handle, RTC_FLAG_SEC);            /* 清除秒中断 *///printf("sec:%d\r\n", calendar.sec);   /* 打印秒钟 */}if (__HAL_RTC_ALARM_GET_FLAG(&g_rtc_handle, RTC_FLAG_ALRAF) != RESET)   /* 闹钟中断 */{__HAL_RTC_ALARM_CLEAR_FLAG(&g_rtc_handle, RTC_FLAG_ALRAF);          /* 清除闹钟中断 */printf("Alarm Time:%d-%d-%d %d:%d:%d\n", calendar.year, calendar.month, calendar.date, calendar.hour, calendar.min, calendar.sec);}__HAL_RTC_ALARM_CLEAR_FLAG(&g_rtc_handle, RTC_FLAG_OW);                 /* 清除溢出中断标志 */while (!__HAL_RTC_ALARM_GET_FLAG(&g_rtc_handle, RTC_FLAG_RTOFF));       /* 等待RTC寄存器操作完成, 即等待RTOFF == 1 */
}/*** @brief       判断年份是否是闰年*   @note      月份天数表:*              月份   1  2  3  4  5  6  7  8  9  10 11 12*              闰年   31 29 31 30 31 30 31 31 30 31 30 31*              非闰年 31 28 31 30 31 30 31 31 30 31 30 31* @param       year : 年份* @retval      0, 非闰年; 1, 是闰年;*/
static uint8_t rtc_is_leap_year(uint16_t year)
{/* 闰年规则: 四年闰百年不闰,四百年又闰 */if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)){return 1;}else{return 0;}
}/*** @brief       设置时间, 包括年月日时分秒*   @note      以1970年1月1日为基准, 往后累加时间*              合法年份范围为: 1970 ~ 2105年HAL默认为年份起点为2000年* @param       syear : 年份* @param       smon  : 月份* @param       sday  : 日期* @param       hour  : 小时* @param       min   : 分钟* @param       sec   : 秒钟* @retval      0, 成功; 1, 失败;*/
uint8_t rtc_set_time(uint16_t syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec)
{uint32_t seccount = 0;seccount = rtc_date2sec(syear, smon, sday, hour, min, sec); /* 将年月日时分秒转换成总秒钟数 */__HAL_RCC_PWR_CLK_ENABLE(); /* 使能电源时钟 */__HAL_RCC_BKP_CLK_ENABLE(); /* 使能备份域时钟 */HAL_PWR_EnableBkUpAccess(); /* 取消备份域写保护 *//* 上面三步是必须的! */RTC->CRL |= 1 << 4;         /* 进入配置模式 */RTC->CNTL = seccount & 0xffff;RTC->CNTH = seccount >> 16;RTC->CRL &= ~(1 << 4);      /* 退出配置模式 */while (!__HAL_RTC_ALARM_GET_FLAG(&g_rtc_handle, RTC_FLAG_RTOFF));       /* 等待RTC寄存器操作完成, 即等待RTOFF == 1 */return 0;
}/*** @brief       设置闹钟, 具体到年月日时分秒*   @note      以1970年1月1日为基准, 往后累加时间*              合法年份范围为: 1970 ~ 2105年* @param       syear : 年份* @param       smon  : 月份* @param       sday  : 日期* @param       hour  : 小时* @param       min   : 分钟* @param       sec   : 秒钟* @retval      0, 成功; 1, 失败;*/
uint8_t rtc_set_alarm(uint16_t syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec)
{uint32_t seccount = 0;seccount = rtc_date2sec(syear, smon, sday, hour, min, sec); /* 将年月日时分秒转换成总秒钟数 */__HAL_RCC_PWR_CLK_ENABLE(); /* 使能电源时钟 */__HAL_RCC_BKP_CLK_ENABLE(); /* 使能备份域时钟 */HAL_PWR_EnableBkUpAccess(); /* 取消备份域写保护 *//* 上面三步是必须的! */RTC->CRL |= 1 << 4;         /* 进入配置模式 */RTC->ALRL = seccount & 0xffff;RTC->ALRH = seccount >> 16;RTC->CRL &= ~(1 << 4);      /* 退出配置模式 */while (!__HAL_RTC_ALARM_GET_FLAG(&g_rtc_handle, RTC_FLAG_RTOFF));       /* 等待RTC寄存器操作完成, 即等待RTOFF == 1 */return 0;
}/*** @brief       得到当前的时间*   @note      该函数不直接返回时间, 时间数据保存在calendar结构体里面* @param       无* @retval      无*/
void rtc_get_time(void)
{static uint16_t daycnt = 0;uint32_t seccount = 0;uint32_t temp = 0;uint16_t temp1 = 0;const uint8_t month_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* 平年的月份日期表 */seccount = RTC->CNTH; /* 得到计数器中的值(秒钟数) */seccount <<= 16;seccount += RTC->CNTL;temp = seccount / 86400; /* 得到天数(秒钟数对应的) */if (daycnt != temp) /* 超过一天了 */{daycnt = temp;temp1 = 1970;   /* 从1970年开始 */while (temp >= 365){if (rtc_is_leap_year(temp1)) /* 是闰年 */{if (temp >= 366){temp -= 366;    /* 闰年的秒钟数 */}else{break;}}else{temp -= 365;        /* 平年 */}temp1++;}calendar.year = temp1;      /* 得到年份 */temp1 = 0;while (temp >= 28)      /* 超过了一个月 */{if (rtc_is_leap_year(calendar.year) && temp1 == 1) /* 当年是不是闰年/2月份 */{if (temp >= 29){temp -= 29; /* 闰年的秒钟数 */}else{break;}}else{if (temp >= month_table[temp1]){temp -= month_table[temp1]; /* 平年 */}else{break;}}temp1++;}calendar.month = temp1 + 1; /* 得到月份 */calendar.date = temp + 1;   /* 得到日期 */}temp = seccount % 86400;                                                    /* 得到秒钟数 */calendar.hour = temp / 3600;                                                /* 小时 */calendar.min = (temp % 3600) / 60;                                          /* 分钟 */calendar.sec = (temp % 3600) % 60;                                          /* 秒钟 */calendar.week = rtc_get_week(calendar.year, calendar.month, calendar.date); /* 获取星期 */
}/*** @brief       将年月日时分秒转换成秒钟数*   @note      输入公历日期得到星期(起始时间为: 公元0年3月1日开始, 输入往后的任何日期, 都可以获取正确的星期)*              使用 基姆拉尔森计算公式 计算, 原理说明见此贴:*              https://www.cnblogs.com/fengbohello/p/3264300.html* @param       syear : 年份* @param       smon  : 月份* @param       sday  : 日期* @retval      0, 星期天; 1 ~ 6: 星期一 ~ 星期六*/
uint8_t rtc_get_week(uint16_t year, uint8_t month, uint8_t day)
{uint8_t week = 0;if (month < 3){month += 12;--year;}week = (day + 1 + 2 * month + 3 * (month + 1) / 5 + year + (year >> 2) - year / 100 + year / 400) % 7;return week;
}/*** @brief       将年月日时分秒转换成秒钟数*   @note      以1970年1月1日为基准, 1970年1月1日, 0时0分0秒, 表示第0秒钟*              最大表示到2105年, 因为uint32_t最大表示136年的秒钟数(不包括闰年)!*              本代码参考只linux mktime函数, 原理说明见此贴:*              http://www.openedv.com/thread-63389-1-1.html* @param       syear : 年份* @param       smon  : 月份* @param       sday  : 日期* @param       hour  : 小时* @param       min   : 分钟* @param       sec   : 秒钟* @retval      转换后的秒钟数*/
static long rtc_date2sec(uint16_t syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec)
{uint32_t Y, M, D, X, T;signed char monx = smon;    /* 将月份转换成带符号的值, 方便后面运算 */if (0 >= (monx -= 2))       /* 1..12 -> 11,12,1..10 */{monx += 12; /* Puts Feb last since it has leap day */syear -= 1;}Y = (syear - 1) * 365 + syear / 4 - syear / 100 + syear / 400; /* 公元元年1到现在的闰年数 */M = 367 * monx / 12 - 30 + 59;D = sday - 1;X = Y + M + D - 719162;                      /* 减去公元元年到1970年的天数 */T = ((X * 24 + hour) * 60 + min) * 60 + sec; /* 总秒钟数 */return T;
}

rtc.h

#ifndef __RTC_H
#define __RTC_H#include "./SYSTEM/sys/sys.h"/* 时间结构体, 包括年月日周时分秒等信息 */
typedef struct
{uint8_t hour;       /* 时 */uint8_t min;        /* 分 */uint8_t sec;        /* 秒 *//* 公历年月日周 */uint16_t year;      /* 年 */uint8_t  month;     /* 月 */uint8_t  date;      /* 日 */uint8_t  week;      /* 周 */
} _calendar_obj;extern _calendar_obj calendar;                      /* 时间结构体 *//* 静态函数 */
static uint8_t rtc_is_leap_year(uint16_t year);     /* 判断当前年份是不是闰年 */
static long rtc_date2sec(uint16_t syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec);   /* 将年月日时分秒转换成秒钟数 *//* 接口函数 */
uint8_t rtc_init(void);                             /* 初始化RTC */
void rtc_get_time(void);                            /* 获取RTC时间信息 */
uint16_t rtc_read_bkr(uint32_t bkrx);               /* 读取后备寄存器 */
void rtc_write_bkr(uint32_t bkrx, uint16_t data);   /* 写后备寄存器 */ 
uint8_t rtc_get_week(uint16_t year, uint8_t month, uint8_t day);    /* 根据年月日获取星期几 */
uint8_t rtc_set_time(uint16_t syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec);   /* 设置时间 */
uint8_t rtc_set_alarm(uint16_t syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec);  /* 设置闹钟时间 */#endif

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

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

相关文章

Kafka之存储设计

文章目录 1. 分区和副本的存储结构1. 分区和副本的分布2. 存储目录结构3. 文件描述 2. 相关配置3. 数据文件类型4. 数据定位原理LogSegment 类UnifiedLog 类 5. 副本数据同步HW水位线LEO末端偏移量HW更新原理 6. 数据清除 1. 分区和副本的存储结构 在一个多 broker 的 Kafka 集…

文心一言大模型

文心一言是百度基于其强大的“文心”大模型技术推出的生成式AI产品&#xff08;英文名&#xff1a;ERNIE Bot&#xff09;。以下是关于文心一言的详细介绍&#xff1a; 一、产品定位与功能 定位&#xff1a;文心一言被定位为人工智能基座型的赋能平台&#xff0c;旨在助力金融…

MFC:以消息为基础的事件驱动系统和消息映射机制

以消息为基础的事件驱动系统和消息映射机制 (1)消息 A.What&#xff08;什么是消息&#xff09; 本质是一个数据结构&#xff0c;用于应用程序不同部分之间进行通信和交互 typedef struct tagMSG {HWND hwnd; // 接收该消息的窗口句柄UINT message; // 消息标…

【C语言】 利用栈完成十进制转二进制(分文件编译,堆区申请空间malloc)

利用栈先进后出的特性&#xff0c;在函数内部&#xff0c;进行除二取余的操作&#xff0c;把每次的余数存入栈内&#xff0c;最后输出刚好就是逆序输出&#xff0c;为二进制数 学习过程中&#xff0c;对存储栈进行堆区的内存申请时候&#xff0c;并不是很熟练&#xff0c;一开始…

双边性:构建神经网络的新方法

正如承诺的那样&#xff0c;这是最近我遇到的最有趣的想法之一的第二部分。如果你错过了&#xff0c;请务必观看本系列的第一部分 - 神经科学家对改进神经网络的看法 - 我们讨论了双边性的生物学基础以及我们大脑的不对称性质如何带来更高的性能。 在这篇文章中&#xff0c;我…

v-for 进行列表的 增删改查

通过对象下标替换属性值 但是通过实践此方法是错误的&#xff0c;Vue监听的是students这个对象&#xff0c;而不是这个对象里面的数组信息&#xff0c;也就是说&#xff0c;改变里面的值&#xff0c;并不能在页面上实现更新的功能 <!DOCTYPE html> <html lang"en…

通俗地理解主动元数据管理

元数据管理&#xff0c;是企业开展数据管理的核心基础&#xff0c;内容涉及元数据的创建&#xff0c;确定需要捕获哪些元数据&#xff0c;通过哪些工具和流程进行创建&#xff0c;继而将元数据妥善存储&#xff0c;保障安全性和可访问性&#xff0c;并不断更新维护&#xff0c;…

[渗透测试] 反序列化漏洞

反序列化漏洞 ​ 序列化&#xff1a;将对象的状态信息转换为可以传输或存储的形式的过程。简单的来说&#xff0c;就是将一个抽象的对象转换成可以传输的字符串 &#xff0c;以特定的形式在进行之间实现跨平台的传输。 序列化大多以字节流、字符串、json串的形式来传输。将对…

linux/windows wps node.js插件对PPT状态监听并且通知其他应用

需求背景 公司要求对Window系统&#xff0c;和国产操作系统&#xff08;UOS&#xff09;的wps 软件在 PPT开始播放 结束播放&#xff0c;和播放中翻页 上一页 下一页 等状态进行监听&#xff0c;并通知到我们桌面应用。 技术方案 开发WPS插件&#xff0c;使用node.JS 插件开…

系统架构设计师①:计算机组成与体系结构

系统架构设计师①&#xff1a;计算机组成与体系结构 计算机结构 计算机的组成结构可以概括为以下几个主要部分&#xff1a;中央处理器&#xff08;CPU&#xff09;、存储器&#xff08;包括主存和外存&#xff09;、输入设备、输出设备&#xff0c;以及控制器、运算器、总线和…

如何查看jvm资源占用情况

如何设置jar的内存 java -XX:MetaspaceSize256M -XX:MaxMetaspaceSize256M -XX:AlwaysPreTouch -XX:ReservedCodeCacheSize128m -XX:InitialCodeCacheSize128m -Xss512k -Xmx2g -Xms2g -XX:UseG1GC -XX:G1HeapRegionSize4M -jar your-application.jar以上配置为堆内存4G jar项…

使用puma部署ruby on rails的记录

之前写过一篇《记录一下我的Ruby On Rails的systemd服务脚本》的记录&#xff0c;现在补上一个比较政治正确的Ruby On Rails的生产环境部署记录。使用Puma部署项目。 创建文件 /usr/lib/systemd/system/puma.service [Unit] DescriptionPuma HTTP Server DocumentationRuby O…

[AWS]MSK调用,报错Access denied

背景&#xff1a;首先MSK就是配置一个AWS的托管 kafka&#xff0c;创建完成之后就交给开发进行使用&#xff0c;开发通常是从代码中&#xff0c;编写AWS的access_key 和secret_key进行调用。 但是开发在进行调用的时候&#xff0c;一直报错连接失败&#xff0c;其实问题很简单&…

Electron 企业级开发通信与本地存储实用解决方案

背景 之前写了一篇Electron通信的方式&#xff0c;讲述了一下三者之间的通信机制&#xff0c;比较恶心&#xff0c;后来发现有个electron/remote&#xff0c; Electron 渲染进程直接调用主进程的API库electron/remote引用讲解-CSDN博客文章浏览阅读58次。remote是个老库&…

蓝队黑名单IP解封提取脚本

应用场景&#xff1a;公司给蓝队人员一个解封IP列表&#xff0c;假如某个IP满足属于某某C段&#xff0c;则对该IP进行解封。该脚本则是进行批量筛选出符合条件的白名单IP 实操如下&#xff1a;公司给了一个已经封禁了的黑名单IP列表如下&#xff08;black&#xff09; 公司要求…

高清视频,无损音频,LDR6023——打造极致视听与高效充电的双重享受!

Type-C PD&#xff08;Power Delivery&#xff09;芯片是一种支持USB Type-C接口规范的电源管理单元&#xff0c;其主要功能包括&#xff1a; 快速充电&#xff1a;Type-C PD芯片支持高功率传输&#xff0c;能够提供更快的充电速度&#xff0c;使电子设备在短时间内充满电&…

微信小程序:多图片显示及图片点击放大,多视频显示

微信小程序&#xff1a;多图片显示及图片点击放大&#xff0c;多视频显示 01 多图片显示及图片点击放大02 多视频03 全部代码 01 多图片显示及图片点击放大 <view><view class"title">图片&#xff1a;</view><block wx:if"{{photoUrlList…

源码搭建国内微短剧系统(APP+小程序)云存储配置流程

国内微短剧系统很多人不知道云存储和配置的操作流程&#xff0c;我整理了一份非常详细的操作文档流程&#xff0c;给大家介绍短剧系统云存储配置的详细操作流程。顺便推荐一下国内微短剧系统。 推荐下他们的开源地址&#xff1a;https://gitee.com/nymaite_com_2878868888/tjg…

CrowdStrike更新致850万Windows设备宕机,微软紧急救火!

7月18日&#xff0c;网络安全公司CrowdStrike发布了一次软件更新&#xff0c;导致全球大范围Windows系统宕机。 预估CrowdStrike的更新影响了将近850万台Windows设备&#xff0c;多行业服务因此停滞&#xff0c;全球打工人原地放假&#xff0c;坐等吃瓜&#xff0c;网络上爆梗…

适用于 Mac 或 MacBook 的最佳数据恢复软件

Apple 设计的电脑可靠且用户友好&#xff0c;但即使是最好的最新款 MacBook硬件也会出现故障。当您的存储出现问题时&#xff0c;数据恢复软件可以帮助您恢复丢失和损坏的文件。 数据丢失的另一个原因是有时会发生令人尴尬的错误。如果您不小心丢弃了所需的文件&#xff0c;然…