STM32用Timer控制LED,RTC设置日历

Timer

在使用定时器时,我们会涉及到三个非常重要的概念——分频,计数,重载。这三个概念可以结合生活中使用的时钟来理解。

分频
时钟上不同的指针需要有不同的速度,也就是不同的频率,从而精确的表示时间。
计数
定时器中的计数也是和计数时间成正比的值,频率越高增长速度越快。
重载
重载值就是计数上限,显然计数器不可能无限计数,当定时器中的计数值达到重载值时,计数值就会被清零。
要实现定时或者延时功能,一般有三种方法:软件定时,不可编程硬件定时,可编程硬件定时。

软件定时——让软件循环执行一段程序,程序本身并无执行目的,而是通过执行程序延时固定的时间,也就是以前的程序中经常使用的延时程序。这种方法降低了cpu的利用率。

不可编程硬件定时——如外部芯片555 时基电路,通过外部阻容,达到一定的延时功能,改变阻容大小可以改变延时长度。这种定时器取决于硬件,设定好以后不能通过软件更改。

可编程定时器——这种定时器的定时值可以通过软件确定和修改,使用灵活便捷。
定时器定时时间简单计算方法:定时时间=(设置时钟频率+1)**(分频数+1)/输入频率
Tout = ((arr+1)*(psc+1))/Tclk

Prescaler分频系数psc
Counter Period时钟频率arr
配置HAL库:
PB6对LED输出信号:
STM32用Timer控制LED,RTC设置日历_第1张图片
设置输入频率72MHZ:
STM32用Timer控制LED,RTC设置日历_第2张图片
设置TIM1:
STM32用Timer控制LED,RTC设置日历_第3张图片

设置TIM2:
STM32用Timer控制LED,RTC设置日历_第4张图片
代码的编写,主要是对main.c的修改:

gpio波形:
STM32用Timer控制LED,RTC设置日历_第5张图片
usart1输出信号:
STM32用Timer控制LED,RTC设置日历_第6张图片

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 
{ 
	if(htim == &htim1) 
	{ 
		
		 HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_6); 
	} 
	if(htim==&htim2)
	{	char data[]="hello windows!\n";
		HAL_UART_Transmit(&huart1, (uint8_t *)data, 15, 0xffff);	}
}
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();

  /* Initialize interrupts */
  MX_NVIC_Init();
  /* USER CODE BEGIN 2 */
 HAL_TIM_Base_Start_IT(&htim1);
  HAL_TIM_Base_Start_IT(&htim2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

烧录运行效果:

VID_20221030_113105

2.使用RTC

STM32F2的实时时钟(RTC)是一个独立的BCD(Binary Coded Decimal)定时器/计时器,提供了一个包括时间与日期的时钟/日历功能,两个闹钟中断,一个定期唤醒中断,并且包括一个自动唤醒单位管理的低功耗模式。实时时钟的缩写是RTC(Real_Time Clock)。RTC 是集成电路,通常称为时钟芯片。
实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
在hal库中生成的代码,每次断电就RTC时间会重置,每次上电都会重新初始化时间
【日期格式】Binary data format 表示十六进制;BCD data format BCD表示码进制
配置RTC:
Activate Clock Source 激活时钟源
Activate calendar激活日历
RTC_OUT设置为[Not RTC_OUT],也就是是否使能 tamper(PC13)引脚上输出校正的秒脉冲时钟
注意,RTC_OUT和Tamper选项共用引脚PC13,因此两个功能只能选择其一。
STM32用Timer控制LED,RTC设置日历_第7张图片
时钟配置:
STM32用Timer控制LED,RTC设置日历_第8张图片

STM32用Timer控制LED,RTC设置日历_第9张图片
时间参数配置:
STM32用Timer控制LED,RTC设置日历_第10张图片
使用自动配置,初始化时间必须使用BCD data format,原因是库函数存在bug,如果使用Binary data format,月份配置会出错
我们想要验证默认时间是否为 1970年1月1日零分零秒,使用HAL_RTC_GetTime(),HAL_RTC_GetDate()读取时间和日期,并保存到结构体变量中,然后通过串口输出读取的时间和日期。
先调用HAL_RTC_GetTime,再调用HAL_RTC_GetDate,否则不能解锁,即被锁死。
它们的HAL库声明如下:

HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);

如果按默认配置运行的话,时间显示如下
STM32用Timer控制LED,RTC设置日历_第11张图片
这样运行年份和时间显示就是:
在这里插入图片描述
因为年份默认只能配置两位,所以最后结果还要在代码里添加对应年份前两位。
显然,cubemx默认将RTC配置为 00/01/01 00:00:00
我们重写fputc函数实现printf函数:

int fputc(int ch,FILE *f){
 uint8_t temp[1]={ch};
 HAL_UART_Transmit(&huart1,temp,1,2);
 return ch;
}

我们要先获取系统当前时间,每秒把日期加一,打印输出日期、时间及星期,需要用到的结构体在stm32f1xx_hal_rtc.h定义:

typedef struct
{
  uint8_t WeekDay;  /*!< Specifies the RTC Date WeekDay (not necessary for HAL_RTC_SetDate).
                         This parameter can be a value of @ref RTC_WeekDay_Definitions */

  uint8_t Month;    /*!< Specifies the RTC Date Month (in BCD format).
                         This parameter can be a value of @ref RTC_Month_Date_Definitions */

  uint8_t Date;     /*!< Specifies the RTC Date.
                         This parameter must be a number between Min_Data = 1 and Max_Data = 31 */

  uint8_t Year;     /*!< Specifies the RTC Date Year.
                         This parameter must be a number between Min_Data = 0 and Max_Data = 99 */

} RTC_DateTypeDef;
typedef struct
{
  uint8_t Hours;            /*!< Specifies the RTC Time Hour.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 23 */

  uint8_t Minutes;          /*!< Specifies the RTC Time Minutes.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

  uint8_t Seconds;          /*!< Specifies the RTC Time Seconds.
                                 This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

} RTC_TimeTypeDef;

注意,weekday是0-6之间取值。
本实验在代码上主要编写的是main.c文件,先定义getdata获取日期,gettime获取时间,setdate修改日期:

RTC_DateTypeDef GetData; 
RTC_DateTypeDef SetData;
RTC_TimeTypeDef GetTime;   

定义函数使得RTC_DateTypeDef自动增加一天:

RTC_DateTypeDef autoAddDate(RTC_DateTypeDef date1 ){
	 uint8_t mon=date1.Month;
	uint8_t day=date1.Date;
	uint8_t yea=date1.Year+2000;
	uint8_t week=date1.WeekDay;
	day++;
	int gap=0;
	if((yea%400==0)||(yea%4==0&&yea%100!=0))
		gap=1;
	if(mon==2){
		if(gap&&(day>29))
		{mon++;day=1;}
		else if(day>28)
		{mon++;day=1;}
	}
	else if(((mon<8&&mon%2==1)||(mon>7&&mon%2==0))&&(day>31))
	{   mon++;
		day=1;
	}
	else if(day>30){
	 mon++;
		day=1;
	}
	if(mon>12)
	{mon=1;
		yea++;}
	week=(1+week)%7;
		yea=yea-2000;
		date1.Month=mon;
		date1.Date=day;
		date1.Year=yea;
		date1.WeekDay=week;
		return date1;
}

int main函数编写如下:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
       HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
      /* Get the RTC current Date */
      HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
		 printf("%02d/%02d/%02d\r\n", 2000+GetData.Year, GetData.Month, GetData.Date);
		/* Display date Format : weekday */
		switch(GetData.WeekDay){
			case 1:printf("星期一\r\n");
				   break;
			case 2:printf("星期二\r\n");
				   break;
			case 3:printf("星期三\r\n");
				   break;
			case 4:printf("星期四\r\n");
				   break;
			case 5:printf("星期五\r\n");
				   break;
			case 6:printf("星期六\r\n");
				   break;
			case 0:printf("星期天\r\n");
				   break;
			default:
				break;
		} 
      /* Display time Format : hh:mm:ss */
      printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);

      printf("\r\n");
	     SetData=autoAddDate(GetData);
      HAL_RTC_SetDate(&hrtc, &SetData, RTC_FORMAT_BIN);
      HAL_Delay(1000);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

串口打印输出结果:
STM32用Timer控制LED,RTC设置日历_第12张图片

你可能感兴趣的:(stm32,单片机)