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

RTC实时时钟

BKP(备份寄存器)

1. 什么是BKP?

备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域里,当VDD电 源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会 被复位。

此外, BKP控制寄存器用来管理侵入检测和RTC校准功能。

复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下 操作可以使能对备份寄存器和RTC的访问:

通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟

电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。

用户数据存储容量:

20字节(中容量和小容量)/ 84字节(大容量和互联型)

2. BKP框图

小实验:读写BKP

实验目的 读写BKP

/------------------------RTC.h------------------------/

#include "sys.h"void rtc_init(void);
uint16_t rtc_read_bkr(uint8_t bkrx);
void rtc_write_bkp(uint8_t bkrx,uint16_t data);

/------------------------RTC.c------------------------/

rtc初始化
RTC_HandleTypeDef rtc_handle = {0};void rtc_init(void)
{//备份寄存器和RTC的访问    1PWREN,BKPEN__HAL_RCC_PWR_CLK_ENABLE();__HAL_RCC_BKP_CLK_ENABLE();//对DBPDBP位来使能  pwrHAL_PWR_EnableBkUpAccess();//RTC部分rtc_handle.Instance = RTC;            //寄存器选择rtc_handle.Init.AsynchPrediv = 32767;rtc_handle.Init.OutPut      = RTC_OUTPUTSOURCE_NONE;HAL_RTC_Init(&rtc_handle);
}
指定读取的寄存器
uint16_t rtc_read_bkr(uint8_t bkrx)
{uint32_t data = 0;                          //接收返回值data = HAL_RTCEx_BKUPRead(&rtc_handle,bkrx);//句柄,指定读哪个寄存器return (uint16_t)data;                      //返回寄存器读出值
}

写的是哪个寄存器  写的数据是16位的数据

void rtc_write_bkp(uint8_t bkrx,uint16_t data)
{//句柄 哪个寄存器 写数据HAL_RTCEx_BKUPWrite(&rtc_handle,bkrx,data);}

/---------------------------------main.c---------------------------------/

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "rtc.h"
int main(void)
{HAL_Init();                         /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init();	/* LED初始化 */uart1_init(115200);rtc_init();
//			led1_on();
//			led1_off();printf("helloworld!\r\n");rtc_write_bkp(1,0xA5A5);printf("读出来的值为:%X\r\n",rtc_read_bkr(1));while(1){ }
}

十四、RTC

1. 什么是RTC?

实时时钟是一个独立的定时器。 RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历 的功能。修改计数器的值可以重新设置系统当前的时间和日期。

RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后, RTC的设置 和时间维持不变。

复位后,对备份寄存器和RTC的访问被禁止,并且备份域被保护以防止可能存在的意外的写操作。执行以下 操作可以使能对备份寄存器和RTC的访问:

  •         通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟
  •          电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。

32位的可编程计数器,可对应Unix时间戳的秒计数器。

Unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。

20位的可编程预分频器,可适配不同频率的输入时钟。

可选择三种RTC时钟源:

  1. HSE时钟除以128(通常为8MHz/128)
  2. LSE振荡器时钟(通常为32.768KHz)
  3. LSI振荡器时钟(40KHz) 

2. RTC框图 

 3. 寄存器及库函数

1.主要功能函数
设置日历参数
HAL_RTC_GetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);
HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
获取日历参数
HAL_RTC_SetTime(&hrtc, &RTC_Time, RTC_FORMAT_BIN);
HAL_RTC_SetDate(&hrtc, &RTC_Date, RTC_FORMAT_BIN);

其中,第一个参数为RTC结构体,第二个参数为Time和Date结构体,第三个参数可设置为:RTC_FORMAT_BIN或RTC_FORMAT_BCD

周期性唤醒中断
void RTC_WKUP_IRQHandler(void)
                        
原文链接:https://blog.csdn.net/weixin_44064233/article/details/108326975

只有在电源控制寄存器(PWR_CR)中的DBP位置’1’

位15 RTCEN:RTC时钟使能 (RTC clock enable)

RTCSEL[1:0]:RTC时钟源选择 (RTC clock source selection)

位9:800:无时钟; 01:LSE振荡器作为RTC时钟; 10:LSI振荡器作为RTC时钟; 11:HSE振荡器在128分频后作为RTC时钟。

不打开没有意义

LSEON:外部低速振荡器使能由软件置’1’或清’0’

0:外部32kHz振荡器关闭; 1:外部32kHz振荡器开启。

16.4.1 RTC控制寄存器高位(RTC_CRH)

RTC_CNT、RTC_ALR或RTC_PRL

等到为1是才能操作

16.4.3 RTC预分频装载寄存器(RTC_PRLH/RTC_PRLL)—20位的寄存器0~3低 0~15 

仅当RTOFF值为’1’时允许进行写操作

16.4.4 RTC预分频器余数寄存器(RTC_DIVH / RTC_DIVL)

与预分配装载寄存器差不多

HAL_RTC_Init

HAL_RTC_GetTime

HAL_RTC_GetDate

HAL_RTC_SetDate

HAL_RTC_SetTime

HAL_RTC_SetAlarm_IT

__HAL_RTC_ALARM_GET_FLAG  .h里面

获取时间是将cnt读出来

4. RTC驱动步骤

注意事项:

必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、 RTC_ALR寄存器

对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的 RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器

小实验1:读写RTC时间实验

/-----------------rtc.h------------------------------/

#include "sys.h"
#include "time.h"
#include "uart1.h"
void rtc_init(void);
uint16_t rtc_read_bkr(uint8_t bkrx);
void rtc_write_bkp(uint8_t bkrx,uint16_t data);
void rtc_set_time(struct tm time_data);
void rtc_get_time(void);

/-----------------rtc.c------------------------------/

rtc初始化
RTC_HandleTypeDef rtc_handle = {0};//rtc初始化
void rtc_init(void)
{//备份寄存器和RTC的访问   1PWREN,BKPEN__HAL_RCC_PWR_CLK_ENABLE();__HAL_RCC_BKP_CLK_ENABLE();//对DBPDBP位来使能   pwrHAL_PWR_EnableBkUpAccess();//RTC部分rtc_handle.Instance   = RTC;                         //寄存器选择rtc_handle.Init.AsynchPrediv = 32767;                //溢出预分频系数rtc_handle.Init.OutPut       = RTC_OUTPUTSOURCE_NONE;//侵入检测--HAL_RTC_Init(&rtc_handle);}
底层代码  

使能RTC,设置时钟源, 中断配置

void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{//使能RTC__HAL_RCC_RTC_ENABLE();RCC_OscInitTypeDef osc_initstruct = {0};RCC_PeriphCLKInitTypeDef periphclk_initstruct = {0};osc_initstruct.OscillatorType= RCC_OSCILLATORTYPE_LSE;//选择振荡器osc_initstruct.LSEState= RCC_LSE_ON;//选择lse的状态osc_initstruct.PLL.PLLState= RCC_PLL_NONE;//有没有用到锁相环//配置振荡器  设置时钟源  句柄 选择哪一路HAL_RCC_OscConfig(&osc_initstruct);periphclk_initstruct.PeriphClockSelection =RCC_PERIPHCLK_RTC;//配置rtc外设periphclk_initstruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;//时钟选择HAL_RCCEx_PeriphCLKConfig(&periphclk_initstruct);//配置RTC对三路进行选项
}
指定读取的寄存器
uint16_t rtc_read_bkr(uint8_t bkrx)
{uint32_t data = 0;//接收返回值data = HAL_RTCEx_BKUPRead(&rtc_handle,bkrx);//句柄,指定读哪个寄存器return (uint16_t)data;//返回寄存器读出值
}
指定写的是哪个寄存器

 写的数据是16位的数据

void rtc_write_bkp(uint8_t bkrx,uint16_t data)
{//句柄 哪个寄存器 写的数据HAL_RTCEx_BKUPWrite(&rtc_handle,bkrx,data);
}
获取时间  两个函数
void rtc_get_time(void)
{RTC_TimeTypeDef rtc_time = {0};RTC_DateTypeDef rtc_date = {0};HAL_RTC_GetTime(&rtc_handle, &rtc_time,RTC_FORMAT_BIN);HAL_RTC_GetDate(&rtc_handle, &rtc_date,RTC_FORMAT_BIN);//HAL库中年是两位的实验需要另外加2000 0X%设置格式为两位printf("rtc time: %d-%02d-%02d %02d:%02d:%02d\r\n",rtc_date.Year + 2000,rtc_date.Month,rtc_date.Date,rtc_time.Hours,rtc_time.Minutes, rtc_time.Seconds);
}

设置时间

 如果单独设置年月日时分秒就会特别长,实验可以设置一个结构体,但是库函数中已经存在一个结构体可以用

void rtc_set_time(struct tm time_data)
{RTC_TimeTypeDef rtc_time = {0};RTC_DateTypeDef rtc_date = {0};rtc_time.Hours = time_data.tm_hour;rtc_time.Minutes=time_data.tm_min;rtc_time.Seconds=time_data.tm_sec;HAL_RTC_SetTime(&rtc_handle, &rtc_time,RTC_FORMAT_BIN);rtc_date.Year = time_data.tm_year;rtc_date.Month = time_data.tm_mon;rtc_date.Date  = time_data.tm_mday;HAL_RTC_SetDate(&rtc_handle, &rtc_date,RTC_FORMAT_BIN);//按要求对任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器的RTOFF状态位判断while(!__HAL_RTC_ALARM_GET_FLAG(&rtc_handle,RTC_FLAG_RTOFF));}

/----------------------------main----------------------/

main

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "rtc.h"
int main(void)
{HAL_Init();                         /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init();	/* LED初始化 */uart1_init(115200);rtc_init();
//			led1_on();
//			led1_off();printf("helloworld!\r\n");//做一个记号,先读一下看看有没有找到记号if(rtc_read_bkr(1) !=0xA5A5){rtc_write_bkp(1,0xA5A5);printf("读出来的值为:%X\r\n",rtc_read_bkr(1));//获取时间,首先里面需要有时间struct tm time_data;time_data.tm_year = 24;time_data.tm_mon  =12;time_data.tm_mday =7;time_data.tm_hour =13;time_data.tm_min  =13;time_data.tm_sec  =9;rtc_set_time(time_data);}while(1){ rtc_get_time();delay_ms(1000);}
}

出现的问题

如果这里错了会只等待不中断

小实验2:RTC闹钟实验 

/--------------------------rtc--------------------------/

rtc初始化
void rtc_init(void)
{//备份寄存器和RTC的访问   1PWREN,BKPEN__HAL_RCC_PWR_CLK_ENABLE();__HAL_RCC_BKP_CLK_ENABLE();//对DBPDBP位来使能   pwrHAL_PWR_EnableBkUpAccess();//RTC部分rtc_handle.Instance   = RTC;                         //寄存器选择rtc_handle.Init.AsynchPrediv = 32767;                //溢出预分频系数rtc_handle.Init.OutPut       = RTC_OUTPUTSOURCE_NONE;//侵入检测--HAL_RTC_Init(&rtc_handle);}
底层代码  

使能RTC,设置时钟源, 中断配置

void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{//使能RTC__HAL_RCC_RTC_ENABLE();RCC_OscInitTypeDef osc_initstruct = {0};RCC_PeriphCLKInitTypeDef periphclk_initstruct = {0};osc_initstruct.OscillatorType= RCC_OSCILLATORTYPE_LSE;//选择振荡器osc_initstruct.LSEState= RCC_LSE_ON;//选择lse的状态osc_initstruct.PLL.PLLState= RCC_PLL_NONE;//有没有用到锁相环//配置振荡器  设置时钟源  句柄 选择哪一路HAL_RCC_OscConfig(&osc_initstruct);periphclk_initstruct.PeriphClockSelection =RCC_PERIPHCLK_RTC;//配置rtc外设periphclk_initstruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;//时钟选择HAL_RCCEx_PeriphCLKConfig(&periphclk_initstruct);//配置RTC对三路进行选项
}
中断函数
void RTC_Alarm_IRQHandler(void)
{HAL_RTC_AlarmIRQHandler(&rtc_handle);//公共处理函数  传进一个参数  有很多的处理函数
}

RTC只支持一个闹钟  

中断的内容  

闹钟响了之后的内容

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{printf("ring ring ring\r\n");}
指定读取的寄存器
uint16_t rtc_read_bkr(uint8_t bkrx)
{uint32_t data = 0;//接收返回值data = HAL_RTCEx_BKUPRead(&rtc_handle,bkrx);//句柄,指定读哪个寄存器return (uint16_t)data;//返回寄存器读出值}
指定写的是哪个寄存器

  写的数据是16位的数据

void rtc_write_bkr(uint8_t bkrx,uint16_t data)
{//句柄 哪个寄存器 写的数据HAL_RTCEx_BKUPWrite(&rtc_handle,bkrx,data);
}
获取时间  两个函数
void rtc_get_time(void)
{RTC_TimeTypeDef rtc_time = {0};RTC_DateTypeDef rtc_date = {0};HAL_RTC_GetTime(&rtc_handle, &rtc_time,RTC_FORMAT_BIN);HAL_RTC_GetDate(&rtc_handle, &rtc_date,RTC_FORMAT_BIN);//HAL库中年是两位的实验需要另外加2000 0X%设置格式为两位printf("rtc time: %d-%02d-%02d %02d:%02d:%02d\r\n",rtc_date.Year + 2000,rtc_date.Month,rtc_date.Date,rtc_time.Hours,rtc_time.Minutes, rtc_time.Seconds);}
设置时间  

如果单独设置年月日时分秒就会特别长,实验可以设置一个结构体,但是库函数中已经存在一个结构体可以用

void rtc_set_time(struct tm time_data)
{RTC_TimeTypeDef rtc_time = {0};RTC_DateTypeDef rtc_date = {0};rtc_time.Hours = time_data.tm_hour;rtc_time.Minutes=time_data.tm_min;rtc_time.Seconds=time_data.tm_sec;HAL_RTC_SetTime(&rtc_handle, &rtc_time,RTC_FORMAT_BIN);rtc_date.Year = time_data.tm_year - 2000;rtc_date.Month = time_data.tm_mon;rtc_date.Date  = time_data.tm_mday;HAL_RTC_SetDate(&rtc_handle, &rtc_date,RTC_FORMAT_BIN);//按要求对任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器的RTOFF状态位判断while(!__HAL_RTC_ALARM_GET_FLAG(&rtc_handle,RTC_FLAG_RTOFF));}
//设置闹钟函数
void rtc_set_alarm(struct tm alarm_data)
{RTC_AlarmTypeDef alarm = {0};//f1系列只有一个alarmalarm.Alarm = RTC_ALARM_A;alarm.AlarmTime.Hours  = alarm_data.tm_hour;alarm.AlarmTime.Minutes = alarm_data.tm_min;alarm.AlarmTime.Seconds = alarm_data.tm_sec;HAL_RTC_SetAlarm_IT(&rtc_handle, &alarm,RTC_FORMAT_BIN);//设置闹钟并可以产生中断
}

/--------------------------main.c------------------------/

 main
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "rtc.h"
int main(void)
{HAL_Init();                         /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */led_init();	/* LED初始化 */uart1_init(115200);rtc_init();
//			led1_on();
//			led1_off();printf("helloworld!\r\n");//做一个记号,先读一下看看有没有找到记号if(rtc_read_bkr(1) !=0xA5A5){rtc_write_bkr(1,0xA5A5);printf("读出来的值为:%X\r\n",rtc_read_bkr(1));//获取时间,首先里面需要有时间struct tm time_data,alarm_data;time_data.tm_year = 2024;time_data.tm_mon  =12;time_data.tm_mday =7;time_data.tm_hour =13;time_data.tm_min  =13;time_data.tm_sec  =9;rtc_set_time(time_data);//闹钟设置alarm_data.tm_hour =13;alarm_data.tm_min  =13;alarm_data.tm_sec  =12;rtc_set_alarm(alarm_data);}while(1){ rtc_get_time();delay_ms(1000);}
}
为什么

项目:实时时钟

项目需求

1. OLED屏幕显示当前时间、日期、闹钟等信息;

2. 正常模式下,按下 KEY1 ,进入时间设置模式,此时按下 KEY2 则可以循环跳转修改秒、分、时、日、 月、年;

3. 时间设置模式下,KEY3 增加数值,KEY4 减小数值,再次按下 KEY1 则退出时间设置模式,并保存修改 后的时间;

4. 正常模式下,按下 KEY2,进入闹钟设置模式,此时按下 KEY2 则可以循环跳转修改秒、分、时;

5. 闹钟设置模式下,KEY3 增加数值,KEY4 减小数值,再次按下 KEY1 则退出闹钟设置模式,并保存修改 后的闹钟;

6. 到达闹钟时间后,蜂鸣器响起。按下 KEY3 或 KEY4 停止蜂鸣器。

 /-------------------------rtc.h--------------------------------/

rtc

#include "sys.h"
#include "time.h"
#include "uart1.h"void rtc_init(void);
uint16_t rtc_read_bkr(uint8_t bkrx);
void rtc_write_bkr(uint8_t bkrx,uint16_t data);
void rtc_set_time(struct tm time_data);
void rtc_get_time(void);
void rtc_set_alarm(struct tm alarm_data); 

 /-------------------------rtc.c--------------------------------/

rtc初始化
RTC_HandleTypeDef rtc_handle = {0};//rtc初始化
void rtc_init(void)
{//备份寄存器和RTC的访问   1PWREN,BKPEN__HAL_RCC_PWR_CLK_ENABLE();__HAL_RCC_BKP_CLK_ENABLE();//对DBPDBP位来使能   pwrHAL_PWR_EnableBkUpAccess();//RTC部分rtc_handle.Instance   = RTC;                         //寄存器选择rtc_handle.Init.AsynchPrediv = 32767;                //溢出预分频系数rtc_handle.Init.OutPut       = RTC_OUTPUTSOURCE_NONE;//侵入检测--HAL_RTC_Init(&rtc_handle);}

底层代码

 使能RTC,设置时钟源, 中断配置

//底层代码  使能RTC,设置时钟源, 中断配置
void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc)
{//使能RTC__HAL_RCC_RTC_ENABLE();RCC_OscInitTypeDef osc_initstruct = {0};RCC_PeriphCLKInitTypeDef periphclk_initstruct = {0};osc_initstruct.OscillatorType= RCC_OSCILLATORTYPE_LSE;//选择振荡器osc_initstruct.LSEState= RCC_LSE_ON;//选择lse的状态osc_initstruct.PLL.PLLState= RCC_PLL_NONE;//有没有用到锁相环HAL_RCC_OscConfig(&osc_initstruct);//配置振荡器  设置时钟源  句柄 选择哪一路periphclk_initstruct.PeriphClockSelection =RCC_PERIPHCLK_RTC;//配置rtc外设periphclk_initstruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;//时钟选择HAL_RCCEx_PeriphCLKConfig(&periphclk_initstruct);//配置RTC对三路进行选项//设置中断优先级HAL_NVIC_SetPriority(RTC_Alarm_IRQn,2,2);HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
}

中断函数

void RTC_Alarm_IRQHandler(void)
{HAL_RTC_AlarmIRQHandler(&rtc_handle);//公共处理函数  传进一个参数  有很多的处理函数
}

RTC只支持一个闹钟  中断的内容  

闹钟响了之后的内容

//RTC只支持一个闹钟  中断的内容  闹钟响了之后的内容
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{beep_on();
}
指定读取的寄存器
uint16_t rtc_read_bkr(uint8_t bkrx)
{uint32_t data = 0;//接收返回值data = HAL_RTCEx_BKUPRead(&rtc_handle,bkrx);//句柄,指定读哪个寄存器return (uint16_t)data;//返回寄存器读出值}

指定写的是哪个寄存器  

写的数据是16位的数据

void rtc_write_bkr(uint8_t bkrx,uint16_t data)
{//句柄 哪个寄存器 写的数据HAL_RTCEx_BKUPWrite(&rtc_handle,bkrx,data);
}
获取时间  两个函数
void rtc_get_time(void)
{RTC_TimeTypeDef rtc_time = {0};RTC_DateTypeDef rtc_date = {0};HAL_RTC_GetTime(&rtc_handle, &rtc_time,RTC_FORMAT_BIN);HAL_RTC_GetDate(&rtc_handle, &rtc_date,RTC_FORMAT_BIN);time_data[0] = rtc_date.Year;time_data[1] = rtc_date.Month;time_data[2] = rtc_date.Date;time_data[3] = rtc_time.Hours;time_data[4] = rtc_time.Minutes;time_data[5] = rtc_time.Seconds;//HAL库中年是两位的实验需要另外加2000 0X%设置格式为两位//		printf("rtc time: %d-%02d-%02d %02d:%02d:%02d\r\n",rtc_date.Year + 2000,rtc_date.Month,rtc_date.Date,rtc_time.Hours,rtc_time.Minutes, 
//		rtc_time.Seconds);}

设置时间  

如果单独设置年月日时分秒就会特别长,实验可以设置一个结构体,但是库函数中已经存在一个结构体可以用

void rtc_set_time(uint8_t *time_data)
{RTC_TimeTypeDef rtc_time = {0};RTC_DateTypeDef rtc_date = {0};rtc_time.Hours = time_data[3];rtc_time.Minutes=time_data[4];rtc_time.Seconds=time_data[5];HAL_RTC_SetTime(&rtc_handle, &rtc_time,RTC_FORMAT_BIN);rtc_date.Year = time_data[0];//最大是256 传2000就溢出了rtc_date.Month = time_data[1];rtc_date.Date  = time_data[2];HAL_RTC_SetDate(&rtc_handle, &rtc_date,RTC_FORMAT_BIN);//按要求对任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器的RTOFF状态位判断while(!__HAL_RTC_ALARM_GET_FLAG(&rtc_handle,RTC_FLAG_RTOFF));}

读取闹钟的参数


void rtc_get_alarm(uint8_t *alarm_data)
{RTC_AlarmTypeDef alarm = {0};// 中断通道f1系列只有一个闹钟  位  rtc句柄,闹钟,指定闹钟,参数HAL_RTC_GetAlarm(&rtc_handle, &alarm,RTC_ALARM_A,RTC_FORMAT_BIN);//接收读出的数据alarm_data[0] = alarm.AlarmTime.Hours;alarm_data[1] = alarm.AlarmTime.Minutes;alarm_data[2] = alarm.AlarmTime.Seconds;
}

设置闹钟函数

void rtc_set_alarm(uint8_t *alarm_data)
{RTC_AlarmTypeDef alarm = {0};//f1系列只有一个alarmalarm.Alarm = RTC_ALARM_A;//闹钟Aalarm.AlarmTime.Hours  = alarm_data[0];alarm.AlarmTime.Minutes = alarm_data[1];alarm.AlarmTime.Seconds = alarm_data[2];HAL_RTC_SetAlarm_IT(&rtc_handle, &alarm,RTC_FORMAT_BIN);//设置闹钟并可以产生中断
}

 /-----------------------beep.c---------------------------------------/

beep 

#include "beep.h"
#include "sys.h"//初始化GPIO函数
void beep_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOC_CLK_ENABLE();                           // 使能GPIOB时钟//调用GPIO初始化函数gpio_initstruct.Pin = GPIO_PIN_13;                       // 蜂鸣器对应的引脚gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;             // 推挽输出gpio_initstruct.Pull = GPIO_PULLUP;                     // 上拉gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;           // 高速HAL_GPIO_Init(GPIOC, &gpio_initstruct);//关闭蜂鸣器beep_off();
}//打开蜂鸣器的函数
void beep_on(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);   // 拉低蜂鸣器引脚,打开蜂鸣器
}//关闭蜂鸣器的函数
void beep_off(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);     // 拉高蜂鸣器引脚,关闭蜂鸣器
}

/------------------------------key.c------------------------------------/

key

#include "beep.h"
#include "sys.h"//初始化GPIO函数
void beep_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOC_CLK_ENABLE();                           // 使能GPIOB时钟//调用GPIO初始化函数gpio_initstruct.Pin = GPIO_PIN_13;                       // 蜂鸣器对应的引脚gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;             // 推挽输出gpio_initstruct.Pull = GPIO_PULLUP;                     // 上拉gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;           // 高速HAL_GPIO_Init(GPIOC, &gpio_initstruct);//关闭蜂鸣器beep_off();
}//打开蜂鸣器的函数
void beep_on(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);   // 拉低蜂鸣器引脚,打开蜂鸣器
}//关闭蜂鸣器的函数
void beep_off(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);     // 拉高蜂鸣器引脚,关闭蜂鸣器
}

/---------------------------key.c---------------------------------------/

#include "key.h"
#include "delay.h"
//初始化GPIO
void key_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOA_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin  = GPIO_PIN_0 | GPIO_PIN_1  | GPIO_PIN_2  | GPIO_PIN_3;//K0,K1,K2,K3gpio_initstruct.Mode = GPIO_MODE_INPUT;//推完输入gpio_initstruct.Pull = GPIO_PULLUP;//由原理图可知默认高电平,按下就低电平gpio_initstruct.Speed= GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA,&gpio_initstruct);}
//按键扫描函数uint8_t key_scan(void)
{//检测按件是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET)//输出用 GPIO_PIN_RESET 低电平{//消抖delay_ms(10);//再将判断按键是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){//如果确定按键按下,等待按键松开while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) ==GPIO_PIN_RESET);//返回按键值--按下返回1,return KEY_SET;}}if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET)//输出用 GPIO_PIN_RESET 低电平{//消抖delay_ms(10);//再将判断按键是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET){//如果确定按键按下,等待按键松开while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) ==GPIO_PIN_RESET);//返回按键值--按下返回1,return KEY_SHIFT;}}if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2) == GPIO_PIN_RESET)//输出用 GPIO_PIN_RESET 低电平{//消抖delay_ms(10);//再将判断按键是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2) == GPIO_PIN_RESET){//如果确定按键按下,等待按键松开while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2) ==GPIO_PIN_RESET);//返回按键值--按下返回1,return KEY_UP;}}if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3) == GPIO_PIN_RESET)//输出用 GPIO_PIN_RESET 低电平{//消抖delay_ms(10);//再将判断按键是否按下if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3) == GPIO_PIN_RESET){//如果确定按键按下,等待按键松开while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3) ==GPIO_PIN_RESET);//返回按键值--按下返回1,return KEY_DOWN;}//返回默认值
}return 0;//松开返回0}

oled 

#include "oled.h"
#include "delay.h"
#include "font.h"void oled_gpio_init(void)
{GPIO_InitTypeDef gpio_initstruct;OLED_I2C_SCL_CLK();OLED_I2C_SDA_CLK();gpio_initstruct.Pin = OLED_I2C_SCL_PIN;          gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;             gpio_initstruct.Pull = GPIO_PULLUP;                     gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;           HAL_GPIO_Init(OLED_I2C_SCL_PORT, &gpio_initstruct);gpio_initstruct.Pin = OLED_I2C_SDA_PIN;          HAL_GPIO_Init(OLED_I2C_SDA_PORT, &gpio_initstruct);
}void oled_i2c_start(void)
{OLED_SCL_SET();OLED_SDA_SET();OLED_SDA_RESET();OLED_SCL_RESET();
}void oled_i2c_stop(void)
{OLED_SCL_SET();OLED_SDA_RESET();OLED_SDA_SET();
}void oled_i2c_ack(void)
{OLED_SCL_SET();OLED_SCL_RESET();
}void oled_i2c_write_byte(uint8_t data)
{uint8_t i, tmp;tmp = data;for(i = 0; i < 8; i++){if((tmp & 0x80) == 0x80)OLED_SDA_SET();elseOLED_SDA_RESET();tmp = tmp << 1;OLED_SCL_SET();OLED_SCL_RESET();}
}void oled_write_cmd(uint8_t cmd)
{oled_i2c_start();oled_i2c_write_byte(0x78);oled_i2c_ack();oled_i2c_write_byte(0x00);oled_i2c_ack();oled_i2c_write_byte(cmd);oled_i2c_ack();oled_i2c_stop();
}void oled_write_data(uint8_t data)
{oled_i2c_start();oled_i2c_write_byte(0x78);oled_i2c_ack();oled_i2c_write_byte(0x40);oled_i2c_ack();oled_i2c_write_byte(data);oled_i2c_ack();oled_i2c_stop();
}void oled_init(void)
{oled_gpio_init();delay_ms(100);oled_write_cmd(0xAE);    //设置显示开启/关闭,0xAE关闭,0xAF开启oled_write_cmd(0xD5);    //设置显示时钟分频比/振荡器频率oled_write_cmd(0x80);    //0x00~0xFFoled_write_cmd(0xA8);    //设置多路复用率oled_write_cmd(0x3F);    //0x0E~0x3Foled_write_cmd(0xD3);    //设置显示偏移oled_write_cmd(0x00);    //0x00~0x7Foled_write_cmd(0x40);    //设置显示开始行,0x40~0x7Foled_write_cmd(0xA1);    //设置左右方向,0xA1正常,0xA0左右反置oled_write_cmd(0xC8);    //设置上下方向,0xC8正常,0xC0上下反置oled_write_cmd(0xDA);    //设置COM引脚硬件配置oled_write_cmd(0x12);oled_write_cmd(0x81);    //设置对比度oled_write_cmd(0xCF);    //0x00~0xFFoled_write_cmd(0xD9);    //设置预充电周期oled_write_cmd(0xF1);oled_write_cmd(0xDB);    //设置VCOMH取消选择级别oled_write_cmd(0x30);oled_write_cmd(0xA4);    //设置整个显示打开/关闭oled_write_cmd(0xA6);    //设置正常/反色显示,0xA6正常,0xA7反色oled_write_cmd(0x8D);    //设置充电泵oled_write_cmd(0x14);oled_write_cmd(0xAF);    //开启显示oled_fill(0x00);
}void oled_set_cursor(uint8_t x, uint8_t y)
{oled_write_cmd(0xB0 + y);oled_write_cmd((x & 0x0F) | 0x00);oled_write_cmd(((x & 0xF0) >> 4) | 0x10);
}void oled_fill(uint8_t data)
{uint8_t i, j;for(i = 0; i < 8; i++){oled_set_cursor(0, i);for(j = 0; j < 128; j++)oled_write_data(data);}
}void oled_show_char(uint8_t x, uint8_t y, uint8_t num, uint8_t size)
{uint8_t i, j, page;num = num - ' ';page = size / 8;if(size % 8)page++;for(j = 0; j < page; j++){oled_set_cursor(x, y + j);for(i = size / 2 * j; i < size /2 * (j + 1); i++){if(size == 12)oled_write_data(ascii_6X12[num][i]);else if(size == 16)oled_write_data(ascii_8X16[num][i]);else if(size == 24)oled_write_data(ascii_12X24[num][i]);}}
}void oled_show_string(uint8_t x, uint8_t y, char *p, uint8_t size)
{while(*p != '\0'){oled_show_char(x, y, *p, size);x += size/2;p++;}
}//void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N, uint8_t size)
//{
//    uint16_t i, j;
//    for(j = 0; j < size/8; j++)
//    {
//        oled_set_cursor(x, y + j);
//        for(i = size *j; i < size * (j + 1); i++)
//        {
//            if(size == 16)
//                oled_write_data(chinese_16x16[N][i]);
//            else if(size == 24)
//                oled_write_data(chinese_24x24[N][i]);
//        }
//    }
//}void oled_show_chinese(uint8_t x, uint8_t y, uint8_t N)
{uint16_t i, j;for(j = 0; j < 2; j++){oled_set_cursor(x, y + j);for(i = 16 * j; i < 16 * (j + 1); i++)       oled_write_data(chinese_time[N][i]);}
}//布局显示函数void oled_show_init(void)
{oled_fill(0x00);oled_show_string(8,0,"2000",16);    //2024oled_show_chinese(40,0,0);          //年oled_show_string(56,0,"00",16);     //07oled_show_chinese(72,0,1);          //月oled_show_string(88,0,"00",16);     //03oled_show_chinese(104, 0,2);       //日oled_show_string(26, 2, "00", 16);              //12oled_show_char(45, 2, ':', 16);                 //:oled_show_string(56, 2, "00", 16);              //35oled_show_char(75, 2, ':', 16);                 //:oled_show_string(86, 2, "00", 16);              //20oled_show_chinese(10, 4, 3);                    //闹oled_show_chinese(26, 4, 4);                    //钟oled_show_char(42, 4, ':', 16);                 //:oled_show_string(26, 6, "00", 16);              //12oled_show_char(45, 6, ':', 16);                 //:oled_show_string(56, 6, "00", 16);              //35oled_show_char(75, 6, ':', 16);                 //:oled_show_string(86, 6, "00", 16);              //20}//清空两个字符  先清空上半部分然后下半部分
void oled_clear_2char(uint8_t x,uint8_t y)
{uint8_t i = 0;oled_set_cursor(x,y);//上半部分清空for(i = 0;i < 16; i++)	oled_write_data(0x00);oled_set_cursor(x,y+1);//下半部分清空for(i = 0;i < 16;i++)oled_write_data(0x00);
}//填坑   年  24对 10取模
void oled_show_year(uint8_t num, uint8_t display_flag)
{if(display_flag)//显示{//显示年份坑位  24对 10取模 将其高位地位取出来oled_show_char(24,0,num/10 + '0',16);oled_show_char(32,0,num%10 + '0',16);}else//不显示年份的坑位oled_clear_2char(24,0);
}//月
void oled_show_month(uint8_t num, uint8_t display_flag)
{if(display_flag){oled_show_char(56, 0, num/10 + '0', 16);oled_show_char(64, 0, num%10 + '0', 16);}elseoled_clear_2char(56, 0);
}//日
void oled_show_day(uint8_t num, uint8_t display_flag)
{if(display_flag){oled_show_char(88, 0, num/10 + '0', 16);oled_show_char(96, 0, num%10 + '0', 16);}elseoled_clear_2char(88, 0);
}//时
void oled_show_hour(uint8_t num, uint8_t display_flag)
{if(display_flag){oled_show_char(26, 2, num/10 + '0', 16);oled_show_char(34, 2, num%10 + '0', 16);}elseoled_clear_2char(26, 2);
}//分
void oled_show_minute(uint8_t num, uint8_t display_flag)
{if(display_flag){oled_show_char(56, 2, num/10 + '0', 16);oled_show_char(64, 2, num%10 + '0', 16);}elseoled_clear_2char(56, 2);
}//秒
void oled_show_second(uint8_t num, uint8_t display_flag)
{if(display_flag){oled_show_char(86, 2, num/10 + '0', 16);oled_show_char(94, 2, num%10 + '0', 16);}elseoled_clear_2char(86, 2);
}//闹钟:时
void oled_show_alarm_hour(uint8_t num, uint8_t display_flag)
{if(display_flag){oled_show_char(26, 6, num/10 + '0', 16);oled_show_char(34, 6, num%10 + '0', 16);}elseoled_clear_2char(26, 6);
}//闹钟:分
void oled_show_alarm_minute(uint8_t num, uint8_t display_flag)
{if(display_flag){oled_show_char(56, 6, num/10 + '0', 16);oled_show_char(64, 6, num%10 + '0', 16);}elseoled_clear_2char(56, 6);
}//闹钟:秒
void oled_show_alarm_second(uint8_t num, uint8_t display_flag)
{if(display_flag){oled_show_char(86, 6, num/10 + '0', 16);oled_show_char(94, 6, num%10 + '0', 16);}elseoled_clear_2char(86, 6);
}//显示元素
void oled_show_element(uint8_t num,uint8_t display_flag,uint8_t element)
{switch(element){case TIME_YEAR  :oled_show_year(num,display_flag); break;case TIME_MONTH :oled_show_month(num,display_flag);break;case TIME_DAY   :oled_show_day(num,display_flag);break;case TIME_HOUR  :oled_show_hour(num,display_flag);break;case TIME_MINUTE:oled_show_minute(num,display_flag);break;case TIME_SECOND:oled_show_second(num,display_flag);break;case ALARM_HOUR  :oled_show_alarm_hour(num,display_flag);break;case ALARM_MINUTE:oled_show_alarm_minute(num,display_flag);break;case ALARM_SECOND:oled_show_alarm_second(num,display_flag);break;default : break;}
}//时间显示,在while中不停的获取rtc的时间
void oled_show_time_alarm(uint8_t *time,uint8_t *alarm)
{oled_show_year(time[0],1);oled_show_month(time[1],1);oled_show_day(time[2],1);oled_show_hour(time[3],1);oled_show_minute(time[4],1);oled_show_second(time[5],1);oled_show_alarm_hour(alarm[0],1);oled_show_alarm_minute(alarm[1],1);oled_show_alarm_second(alarm[2],1);}
void oled_show_image(uint8_t x, uint8_t y, uint8_t width, uint8_t height, uint8_t *bmp)
{uint8_t i, j;for(j = 0; j < height; j++){oled_set_cursor(x, y + j);for(i = 0; i < width; i++)oled_write_data(bmp[width * j + i]);}
}

/-----------------------------led.c-------------------------------------/

 led

#include "led.h"
#include "sys.h"//初始化GPIO函数
void led_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打开时钟__HAL_RCC_GPIOB_CLK_ENABLE();//调用GPIO初始化函数gpio_initstruct.Pin  = GPIO_PIN_8 | GPIO_PIN_9;gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;gpio_initstruct.Pull = GPIO_PULLUP;//上拉gpio_initstruct.Speed= GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB,&gpio_initstruct);//关闭LEDled1_off();}//点亮LED的函数void led1_on(void)
{//由电路图可知,将GPIO拉低HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);}
//熄灭LED1的函数void led1_off(void)
{//由电路图可知,将GPIO拉低HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);}
//翻转LED1状态的函数void led1_toggle(void)
{HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);}void led3_on(void)
{//由电路图可知,将GPIO拉低HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);}
//熄灭LED1的函数void led3_off(void)
{//由电路图可知,将GPIO拉低HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);}
//翻转LED1状态的函数void led3_toggle(void)
{HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);}

main 

/--------------------------main----------------------------------------/

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include  "beep.h"
#include "key.h"
#include "oled.h"
#include "rtc.h"int main(void)
{HAL_Init();                         /* 初始化HAL库 */stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */uart1_init(115200);beep_init();key_init();oled_init();rtc_init();//	//oled_clear_2char(86,2);
//	oled_show_year(24,1);
//	oled_show_element(16, ON,TIME_HOUR);//该函数显示或者不显示printf("helloworld!\r\n");uint8_t time_data[6] = {24,7,4,16,8,30};uint8_t alarm_data[3] = {16,8,40};uint8_t set_time_shift = TIME_SECOND;//显示修改的坑过,刚开始是秒开始改uint8_t set_alarm_shift  = ALARM_SECOND;uint8_t set_time_flag    = 0;uint8_t set_alarm_flag   = 0;oled_show_init();//写入一个记号  无记号做记号,有就不需要if(rtc_read_bkr(1) != 0xA5A5){rtc_write_bkr(1,0xA5A5);rtc_set_time(time_data);rtc_set_alarm(alarm_data);}while(1){ //获取时钟及闹钟rtc_get_time(time_data);rtc_get_alarm(alarm_data);//并在oled屏幕显示oled_show_time_alarm(time_data,alarm_data);//按键扫描  有四个结果  switch(key_scan()){case KEY_SET://进入时间设置模式, 判断什么时候按下  参数判断结束条件set_time_flag = 1;set_time_shift = TIME_SECOND;while(set_time_flag){//闪动要修改的坑位  年月日时分秒oled_show_element(time_data[set_time_shift],OFF,set_time_shift);//传入一个数组,然后关掉,元素delay_ms(100);oled_show_element(time_data[set_time_shift],ON,set_time_shift);//传入一个数组,然后打开,元素delay_ms(100);switch(key_scan()){case KEY_SET://退出时间设置模式set_time_flag = 0;set_time_shift = TIME_SECOND;//挪回起始位置//保存修改后的时间rtc_set_time(time_data);break;case KEY_SHIFT://跳转到下一个需要修改的数据元素if(set_time_shift-- <= TIME_YEAR)set_time_shift = TIME_SECOND;break;case KEY_UP://增加数值if(set_time_shift == TIME_SECOND || set_time_shift == TIME_MINUTE)  //分秒if(time_data[set_time_shift] < 59)time_data[set_time_shift]++;if(set_time_shift == TIME_HOUR)  //小时if(time_data[set_time_shift] < 23)time_data[set_time_shift]++;if(set_time_shift == TIME_DAY)  //日if(time_data[set_time_shift] < 31)time_data[set_time_shift]++;if(set_time_shift == TIME_DAY)  //月if(time_data[set_time_shift] < 12)time_data[set_time_shift]++;if(set_time_shift == TIME_DAY)  //年if(time_data[set_time_shift] < 99)time_data[set_time_shift]++;													break;case KEY_DOWN://减少数值 if(time_data[set_time_shift] > 0)time_data[set_time_shift]--;break;default:break;}}break;case KEY_SHIFT:   //为什么会交替//进入闹钟设置模式set_alarm_flag=1;while(set_alarm_flag){//闪动需要修改的坑位oled_show_element(alarm_data[set_alarm_shift - ALARM_HOUR],OFF,set_alarm_shift);//闹钟是从8开始,如果所以刚开始是8的话就越界了,因为他只有3个数所以要对alarm_hour进行偏移delay_ms(100);oled_show_element(alarm_data[set_alarm_shift - ALARM_HOUR],ON,set_alarm_shift);delay_ms(100);switch(key_scan()){case KEY_SET://退出闹钟模式set_alarm_flag = 0;set_alarm_shift = ALARM_SECOND;//保存修改后的闹钟rtc_set_alarm(alarm_data);break;case KEY_SHIFT://跳转到下一个需要修改的元素if(set_alarm_shift-- <= ALARM_HOUR)set_alarm_shift = ALARM_SECOND;break;case KEY_UP://增加数值if(alarm_data[set_alarm_shift - ALARM_HOUR] < 59)alarm_data[set_alarm_shift - ALARM_HOUR]++;break;case KEY_DOWN:if(alarm_data[set_alarm_shift - ALARM_HOUR] > 0)alarm_data[set_alarm_shift - ALARM_HOUR]--;							break; }}break;case KEY_UP:case KEY_DOWN://停止蜂鸣器beep_off();break;default:break;}}
}

相关文章:

RTC实时时钟

BKP&#xff08;备份寄存器&#xff09; 1. 什么是BKP&#xff1f; 备份寄存器是42个16位的寄存器&#xff0c;可用来存储84个字节的用户应用程序数据。他们处在备份域里&#xff0c;当VDD电 源被切断&#xff0c;他们仍然由VBAT维持供电。当系统在待机模式下被唤醒&#xff…...

移动网络(2,3,4,5G)设备TCP通讯调试方法

背景&#xff1a; 当设备是移动网络设备连接云平台的时候&#xff0c;如果服务器没有收到网络数据&#xff0c;移动物联设备发送不知道有没有有丢失数据的时候&#xff0c;需要一个抓取设备出来的数据和服务器下发的数据的方法。 1.服务器系统是很成熟的&#xff0c;一般是linu…...

项目二十三:电阻测量(需要简单的外围检测电路,将电阻转换为电压)测量100,1k,4.7k,10k,20k的电阻阻值,由数码管显示。要求测试误差 <10%

资料查找&#xff1a; 01 方案选择 使用单片机测量电阻有多种方法&#xff0c;以下是一些常见的方法及其原理&#xff1a; 串联分压法&#xff08;ADC&#xff09; 原理&#xff1a;根据串联电路的分压原理&#xff0c;通过测量已知电阻和待测电阻上的电压&#xff0c;计算出…...

如何使用checkBox组件实现复选框

文章目录 概念介绍使用方法示例代码我们在上一章回中介绍了DatePickerDialog Widget相关的内容,本章回中将介绍Checkbox Widget.闲话休提,让我们一起Talk Flutter吧。 概念介绍 我们在这里说的Checkbox也是叫复选框,没有选中时是一个正方形边框,边框内容是空白的,选中时会…...

用bootstrap搭建侧边栏

要注意&#xff1a; 标签的id"v-pills-dataset1-tab"要和跳转内容的aria-labelledby"v-pills-dataset1-tab"一致 标签的aria-controls"v-pills-dataset1"要和跳转内容的id"v-pills-dataset1"一致 <!-- 左边的列&#xff08;侧边栏…...

手眼标定工具操作文档

1.手眼标定原理介绍 术语介绍 手眼标定&#xff1a;为了获取相机与机器人坐标系之间得位姿转换关系&#xff0c;需要对相机和机器人坐标系进行标定&#xff0c;该标定过程成为手眼标定&#xff0c;用于存储这一组转换关系的文件称为手眼标定文件。 ETH&#xff1a;即Eye To …...

巧记斜边函数hypot

hypot是一个数学函数&#xff0c;源于英文"hypotenuse&#xff08;斜边&#xff09;"&#xff0c;hypot(a, b)返回直角边边长为a、b的直角三角形&#xff08;right-angled triangle&#xff09;的斜边长度。该函数定义在<math.h>头文件中&#xff0c;其功能相当…...

STM32单片机芯片与内部33 ADC 单通道连续DMA

目录 一、ADC DMA配置——标准库 1、ADC配置 2、DMA配置 二、ADC DMA配置——HAL库 1、ADC配置 2、DMA配置 三、用户侧 1、DMA开关 &#xff08;1&#xff09;、标准库 &#xff08;2&#xff09;、HAL库 2、DMA乒乓 &#xff08;1&#xff09;、标准库 &#xff…...

【程序人生】掌握一门编程语言

掌握一门编程语言不仅仅是能够编写正确的语法&#xff0c;它还涉及到对语言特性、工具链、最佳实践以及解决问题的能力有深入的理解。以下是衡量你是否掌握了某门编程语言的关键指标&#xff1a; 语法与基本概念 语法熟悉度&#xff1a;能够在不查阅文档的情况下写出正确的代码…...

数据库发生了死锁怎么办

当项目中存在公共的数据表&#xff0c;比如日志表&#xff0c;同时存在对这张表的读写操作&#xff0c;或者是对数据量较大的表加索引同时伴随其他并发操作&#xff0c;那么这张表就有较高概率发生死锁。 现象&#xff1a;对于这张表的任何操作都会被阻塞&#xff0c;项目出现…...

传递函数的幅值在0到1之间

为什么所有传递函数的幅值应该在 0 到 1 之间 在声学、振动学和信号处理等领域&#xff0c;传递函数的幅值表示系统对输入信号的响应幅度。在许多声学实验中&#xff0c;传递函数的幅值反映了声波的传输或反射特性。理论上&#xff0c;所有传递函数的幅值应当在 0 到 1 之间&a…...

[Unity Shader]【图形渲染】 数学基础4 - 矩阵定义和矩阵运算详解

矩阵是计算机图形学中的重要数学工具,尤其在Shader编程中,它被广泛用于坐标变换、投影变换和模型动画等场景。本文将详细介绍矩阵的定义、基本运算以及如何在Shader中应用矩阵,为初学者打下坚实的数学基础。 一、什么是矩阵? 矩阵是一个由数字排列成的长方形数组,通常记作…...

蓝桥杯练习生第四天

小蓝每天都锻炼身体。 正常情况下&#xff0c;小蓝每天跑 11 千米。如果某天是周一或者月初&#xff08;11 日&#xff09;&#xff0c;为了激励自己&#xff0c;小蓝要跑 22 千米。如果同时是周一或月初&#xff0c;小蓝也是跑 22 千米。 小蓝跑步已经坚持了很长时间&#x…...

Jmeter压测实战:Jmeter二次开发之自定义函数

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Jmeter是Apache基金会下的一款应用场景非常广的压力测试工具&#xff0c;具备轻量、高扩展性、分布式等特性。Jmeter已支持实现随机数、计数器、时间戳、大小写转换…...

梯度(Gradient)和 雅各比矩阵(Jacobian Matrix)的区别和联系:中英双语

雅各比矩阵与梯度&#xff1a;区别与联系 在数学与机器学习中&#xff0c;梯度&#xff08;Gradient&#xff09; 和 雅各比矩阵&#xff08;Jacobian Matrix&#xff09; 是两个核心概念。虽然它们都描述了函数的变化率&#xff0c;但应用场景和具体形式有所不同。本文将通过…...

[python SQLAlchemy数据库操作入门]-02.交易数据实体类建立

哈喽,大家好,我是木头左! 为了顺利地使用SQLAlchemy进行股票交易数据的处理,首先需要搭建一个合适的开发环境。这包括安装必要的软件包以及配置相关的依赖项。 安装Python及虚拟环境 下载并安装Python(推荐使用最新版)。创建一个新的虚拟环境以避免依赖冲突。python -m …...

python打包exe文件

由于用户需要&#xff0c;将采集数据解析成txt文件&#xff0c;为了方便使用&#xff0c;将python解析方法打包成exe文件供用户使用 安装环境 ./pip.exe install pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simplepython导入需要的包 import tkinter as tk from tkin…...

C# opencvsharp 流程化-脚本化-(2)ROI

ROI ROI也是经常需要使用的方法。特别是在图像编辑中。ROI又称感兴趣的区域&#xff0c;但是图像是矩阵是矩形的&#xff0c;感兴趣的是乱八七糟的&#xff0c;所以还有一个Mask需要了解一下的。 public class RoiStep : IImageProcessingStep{public ImageProcessingStepType…...

【Python】基于Python的CI/CD工具链:实现自动化构建与发布

《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 在现代软件开发中,持续集成(CI)和持续交付(CD)已经成为提高开发效率和软件质量的重要实践。CI/CD流程帮助开发团队自动化构建、测试、…...

Flutter组件————Scaffold

Scaffold Scaffold 是一个基础的可视化界面结构组件&#xff0c;它实现了基本的Material Design布局结构。使用 Scaffold 可以快速地搭建起包含应用栏&#xff08;AppBar&#xff09;、内容区域&#xff08;body&#xff09;、抽屉菜单&#xff08;Drawer&#xff09;、底部导…...

2024年《网络安全事件应急指南》

在这个信息技术日新月异的时代&#xff0c;网络攻击手段的复杂性与日俱增&#xff0c;安全威胁层出不穷&#xff0c;给企事业单位的安全防护能力带 来了前所未有的挑战。深信服安全应急响应中心&#xff08;以下简称“应急响应中心”&#xff09;编写了《网络安全事件应急指南》…...

通过smem 定时检测系统内存占用情况

编写定时任务脚本 cat >> /usr/local/bin/smem.sh <<-"EOF"if [[ ! -d /var/log/smem ]];thenmkdir -p /var/log/smem fi smem -tk >> /var/log/smem/smem.log EOFchmod 755 /usr/local/bin/smem.sh配置定时任务 echo "" >> /et…...

京准电钟:电厂自控NTP时间同步服务器技术方案

京准电钟&#xff1a;电厂自控NTP时间同步服务器技术方案 京准电钟&#xff1a;电厂自控NTP时间同步服务器技术方案 随着计算机和网络通信技术的飞速发展&#xff0c;火电厂热工自动化系统数字化、网络化的时代已经到来。一方面它为控制和信息系统之间的数据交换、分析和应用…...

Face to face

1.西班牙添加5G volte 首先carrierconfig里使能 <boolean name"carrier_nr_available_bool" value"true" /> <boolean name"carrier_volte_available_bool" value"true" /> 其次 组件apn配置ims参数 2.印度j…...

C语言中的文件操作:基础与实践

欢迎来到我的&#xff1a;世界 希望作者的文章对你有所帮助&#xff0c;有不足的地方还请指正&#xff0c;大家一起学习交流 ! 目录 前言内容文件文件操作&#xff1a;数据库文件概述&#xff1a;文件的打开和关闭理解流的概念文件指针 文件的打开与关闭文件的读和写文件的顺序…...

从地铁客流讲开来:十二城日常地铁客运量特征

随着城市化进程的加速和人口的不断增长&#xff0c;公共交通系统在现代都市生活中扮演着日益重要的角色。地铁作为高效、环保的城市交通方式&#xff0c;已经成为居民日常出行不可或缺的一部分。本文聚焦于2024年10月28日至12月1日期间&#xff0c;对包括北上广深这四个超一线城…...

VMWare 的克隆操作

零、碎碎念 VMWare 的这个克隆操作很简单&#xff0c;单拎出来成贴的目的是方便后续使用。 一、操作步骤 1.1、在“源”服务器上点右键&#xff0c;选择“管理--克隆” 1.2、选择“虚拟机的当前状态”为基础制作克隆&#xff0c;如下图所示&#xff0c;然后点击“下一页” 1.3、…...

经济学 ppt 2 部分

前言 上一次复习经济学是好久之前了&#xff0c;看了第一章的 ppt &#xff0c;好像重点就是谁是软件经济学之父。昨天老师讲了一下题型&#xff0c;20 分选择题&#xff0c; 20 分判断题&#xff0c;20 分计算题&#xff0c;6 6 8 三个计算题&#xff0c;25 分表格&#xff0…...

R(4.4.2)的下载与安装(Windows系统)

进入官网&#xff1a;https://www.r-project.org/ 首先点击CRAN链接&#xff0c;选择一个镜像链接地址 进入CRAN所显示页面如下&#xff1a; 选择China下的一个镜像站点&#xff0c;本文选择第一个 选择windows系统下载 点击“base” 下载&#xff1a; 打开下载的文件 默认中文…...

一文流:JVM精讲(多图提醒⚠️)

一文流系列是作者苦于技术知识学了-忘了,背了-忘了的苦恼,决心把技术知识的要点一笔笔✍️出来,一图图画出来,一句句讲出来,以求刻在🧠里。 该系列文章会把核心要点提炼出来,以求掌握精髓,至于其他细节,写在文章里,留待后续回忆。 目前进度请查看: :::info https:/…...

C盘下的文件夹

在Windows操作系统中&#xff0c;C盘通常是系统安装的盘符&#xff0c;其中包含了许多重要的文件夹和系统文件。以下是一些常见的文件夹&#xff1a;系统文件夹 Windows: 包含Windows操作系统的核心文件和组件。 Program Files: 存储大多数安装的软件程序。 Program Files (x86…...

视频直播点播平台EasyDSS与无人机技术的森林防火融合应用

随着科技的飞速发展&#xff0c;无人机技术以其独特的优势在各个领域得到了广泛应用&#xff0c;特别是在森林防火这一关键领域&#xff0c;EasyDSS视频平台与无人机技术的融合应用更是为传统森林防火手段带来很大的变化。 一、无人机技术在森林防火中的优势 ‌1、快速响应与高…...

通过阿里云 Milvus 与 PAI 搭建高效的检索增强对话系统

背景介绍 阿里云向量检索服务Milvus版&#xff08;简称阿里云Milvus&#xff09;是一款云上全托管服务&#xff0c;确保了了与开源Milvus的100%兼容性&#xff0c;并支持无缝迁移。在开源版本的基础上增强了可扩展性&#xff0c;能提供大规模 AI 向量数据的相似性检索服务。相…...

Unity 3D饼状图效果

一. 效果展示 二.基础类 using System.Collections; using System.Collections.Generic; using UnityEngine;public class DrawCylinder : MonoBehaviour {// 网格渲染器MeshRenderer meshRenderer;// 网格过滤器MeshFilter meshFilter;// 用来存放顶点数据List<Vector3>…...

OpenHarmony-4.HDI 框架

HDI 框架 1.HDI介绍 HDI&#xff08;Hardware Device Interface&#xff0c;硬件设备接口&#xff09;是HDF驱动框架为开发者提供的硬件规范化描述性接口&#xff0c;位于基础系统服务层和设备驱动层之间&#xff0c;是连通驱动程序和系统服务进行数据流通的桥梁&#xff0c;是…...

ArcGIS Pro 3.4新功能2:Spatial Analyst新特性,密度、距离、水文、太阳能、表面、区域分析

Spatial Analyst 扩展模块在 ArcGIS Pro 3.4 中引入了新功能和增强功能。此版本为您提供了用于表面和区域分析的新工具以及改进的密度和距离分析功能&#xff0c;多种用于水文分析的工具性能的提高&#xff0c;一些新的太阳能分析功能。 目录 1.密度分析 2.距离分析 3.水文…...

GitLab分支管理策略和最佳实践

分支管理是 Git 和 GitLab 中非常重要的部分&#xff0c;合理的分支管理可以帮助团队更高效地协作和开发。以下是一些细化的分支管理策略和最佳实践&#xff1a; 1. 分支命名规范 • 主分支&#xff1a;通常命名为 main 或 master&#xff0c;用于存放稳定版本的代码。 • …...

uniapp自定义树型结构数据弹窗,给默认选中的节点,禁用所有子节点

兼容H5、安卓App、微信小程序 实现逻辑&#xff1a;给默认选中节点的所有子节点添加一个disabled属性&#xff0c;以此禁用子节点。 /components/sonTreeNode/sonTreeNode.vue 封装成组件 <template><view><view :class"[item,item.is_level1?pL1:item…...

方正畅享全媒体新闻采编系统 screen.do SQL注入漏洞复现

0x01 产品简介 方正畅享全媒体新闻生产系统是以内容资产为核心的智能化融合媒体业务平台,融合了报、网、端、微、自媒体分发平台等全渠道内容。该平台由协调指挥调度、数据资源聚合、融合生产、全渠道发布、智能传播分析、融合考核等多个平台组成,贯穿新闻生产策、采、编、发…...

5G 模组 RG500Q常用AT命令

5G 模组 RG500Q常用AT命令 5G 模组 RG500Q常用AT命令 at ATQNWPREFCFG\"mode_pref\",nr5g && sleep 1 at ATQNWPREFCFG\"nr5g_band\",79 && sleep 1 at atqnwlock\"commo…...

day38-SSH安全登录

机器准备 什么是SSH SSH 或 Secure Shell 协议是一种远程管理协议&#xff0c;允许用户通过 Internet 访问、控制和修改其远程服务器。 SSH 服务是作为未加密 Telnet 的安全替代品而创建的&#xff0c;它使用加密技术来确保进出远程服务器的所有通信都以加密方式进行。 SS…...

U盘出现USBC乱码文件的全面解析与恢复指南

一、乱码现象初探&#xff1a;USBC乱码文件的神秘面纱 在数字时代&#xff0c;U盘已成为我们日常生活中不可或缺的数据存储工具。然而&#xff0c;当U盘中的文件突然变成乱码&#xff0c;且文件名前缀显示为“USBC”时&#xff0c;这无疑给用户带来了极大的困扰。这些乱码文件…...

mac iterm2 使用 lrzsz

前言 mac os 终端不支持使用 rz sz 上传下载文件&#xff0c;本文提供解决方法。 mac 上安装 brew install lrzsz两个脚本 注意&#xff1a;/usr/local/bin/iterm2-send-zmodem.sh 中的 sz命令路径要和你mac 上 sz 命令路径一致。 /usr/local/bin/iterm2-recv-zmodem.sh 中…...

京东大数据治理探索与实践 | 京东零售技术实践

01背景和方案 在当今的数据驱动时代&#xff0c;数据作为关键生产要素之一&#xff0c;其在商业活动中的战略价值愈加凸显&#xff0c;京东也不例外。 作为国内领先的电商平台&#xff0c;京东在数据基础设施上的投入极为巨大&#xff0c;涵盖数万台服务器、数 EB 级存储、数百…...

应该连续学一个科目,还是多学科切换?

https://www.zhihu.com/question/333420829https://www.zhihu.com/question/333420829...

游戏何如防抓包

游戏抓包是指在游戏中&#xff0c;通过抓包工具捕获和分析游戏客户端与服务器之间传输的封包数据的过程。抓包工具可实现拦截、篡改、重发、丢弃游戏的上下行数据包&#xff0c;市面上常见的抓包工具有WPE、Fiddler和Charles Proxy等。 抓包工具有两种实现方式&#xff0c;一类…...

asp.net core发布配置端口号,支持linux

方式一&#xff0c;修改配置文件 appsettings.json 找到文件 appsettings.json&#xff0c; 添加如下节点配置&#xff0c;在linux环境需要设置0.0.0.0才可以正常代表本机&#xff0c;然后被其他机器访问&#xff0c;此处设置端口8000&#xff0c; "Kestrel": {&quo…...

基于linux下实现的ping程序(C语言)

linux下实现的ping程序 一、设计目的 PING程序是我们使用的比较多的用于测试网络连通性的程序。PING程序基于ICMP&#xff0c;使用ICMP的回送请求和回送应答来工作。由计算机网络课程知道&#xff0c;ICMP是基于IP的一个协议&#xff0c;ICMP包通过IP的封装之后传递。 课程设…...

109.【C语言】数据结构之求二叉树的高度

目录 1.知识回顾&#xff1a;高度&#xff08;也称深度&#xff09; 2.分析 设计代码框架 返回左右子树高度较大的那个的写法一:if语句 返回左右子树高度较大的那个的写法二:三目操作符 3.代码 4.反思 问题 出问题的代码 改进后的代码 执行结果 1.知识回顾&#xf…...

线段覆盖(c++)

题目描述 在一条数轴上&#xff0c;有 N 条线段&#xff0c;第 i 条线段的左端点是 si​&#xff0c;右端点是 ei​。如果线段有重叠&#xff08;即使是端点重叠也算是重叠&#xff09;&#xff0c;则输出 “impossible”, 如果没有重叠则输出 “possible” 。 输入格式 多组…...