定时器与日历时钟
一、STM32通过hal库使用定时器
1.实验目的
设置一个5秒的定时器,每隔5秒从串口发送“hello windows!”;同时设置一个2秒的定时器,让LED灯周期性地闪烁。
2.实验材料
软件:
Keil5
STM32CubeMx
硬件:
STM32F103C8T6最小板
CH340模块
LED灯一个
面包板
杜邦线
3.实验过程
(1)配置时钟
使用STM32CubeMx创建项目后,先配置HSE,如下图
然后按下图配置Clock Configuration
(2)配置GPIO引脚
因为要用定时器来控制LED灯的亮灭,所以我们要配置一个输出引脚,引脚的选择,我这里选择PA5
(3)配置定时器
本次实验既要控制LED,又要串口输出,所以要用两个定时器。
我们不需要用到高级定时器,就用通用计时器TIM2~4即可。
下图是TIM2的配置
分频系数是71,但系统处理的时候会自动加上1,所以实际是72分频。
因为时钟我们的配置为72MHZ,所以72分频后得到1MHZ的时钟,即0.001ms记一次数,这里写成2000就是2ms触发一次中断。
后面我们只需要写代码让每触发1000次中断就闪烁一次LED灯,就满足了2s闪烁一次的条件。
然后我们还要开启中断以及生成优先级函数,如下图
TIM3用于串口通信,原理同上,就直接看图配置即可
(4)配置串口
只要设置为异步即可,别的都是默认配置。
(5)配置项目
(6)配置代码
以下代码用于手动开启定时器,需要放到main函数里面
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
然后要编写中断函数,注意:
首先要声明两个静态变量,分别记录两个定时器触发中断的次数。
static uint32_t time_cnt1 =0;
static uint32_t time_cnt2 =0;
if(htim->Instance == TIM2)用于判断使用的定时器是TIM2
if(++time_cnt1 >= 1000)用于判断触发中断的次数,也就是前文说的1次中断的时间为2ms,1000次就为2s,然后就执行相应的操作。
TIM3同理。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint32_t time_cnt1 =0;
static uint32_t time_cnt2 =0;
if(htim->Instance == TIM2)
{
if(++time_cnt1 >= 1000)
{
time_cnt1 =0;
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5);
}
}
if(htim->Instance == TIM3)
{
if(++time_cnt2 >= 1000)
{
time_cnt2 =0;
uint8_t hello[20]="hello windows!\n";
HAL_UART_Transmit(&huart1,hello,20,100000);
}
}
}
(7)配置电路
LED短脚接PA5,长脚接正。按下图接即可:
4.实验效果
二、STM32通过hal库读取RTC数据发送给串口助手
1.实验目的
了解实时时钟RTC的原理。STM32芯片自带RTC,因此不须像其他MCU需外接RTC模块。请编程实现STM32的日历读取、设置和输出。
要求:
1)读取RTC初始时间,验证是否为 1970年1月1日零分零秒;
2)将RTC时间调整为当前时间,并以 2021年x月x日x分x秒的格式从串口输出(或输出到OLED屏),每1s改变一次;
3)如果输出内容中需加入“星期x”,请修改代码。
2.实验材料
软件:
Keil5
STM32CubeMx
硬件:
STM32F103C8T6最小板
CH340模块
LED灯一个
面包板
杜邦线
3.实验过程
(1)配置时钟
创建好项目后,按下图配置时钟使能RCC和HSE,下图第5步可能需要开启RTC后才能配置,这里等后面开启RTC后再配置。
(2)配置RTC
下面只需要勾选即可,框中的BCD码是用来设置RTC中的时间初值的,后面会用到,这里可以不管。
(3)配置串口
前文已经配置过了,只要设置成异步即可。
(4)配置项目
也同前文一样
(5)配置代码
首先要编写一个fputc函数,然后使能printf,代码和配置图如下,注意要勾选魔术棒里的Use Micro Lib
#include "stdio.h"
int fputc(int ch,FILE *f){
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,2);
return ch;
}
然后我们需要获取日期结构体和时间结构体。
GetDate用来接受日期,GetTime用来接收时间
RTC_DateTypeDef GetDate;
RTC_TimeTypeDef GetTime;
然后我们可以打开rtc.c文件,我们可以看到RTC中的时间都在这里被初始化
也就是说,如果我们不修改的话,默认的是00年1月1日,0时0分0秒。
同时要注意:HAL库的年是从2000年开始的,输入0x00,保存的是2000年,而星期是由年月日自动计算出来的,我们无法修改。所以我们如果要输出2021年的第一天的话就要把Year=0x21即可。
接下来就可以往while循环里写代码了,以下代码中,发送一次信息给串口的速度为1s,其中printf中的1,2,3,4,5,6,7代表的是星期一到星期日,:
HAL_RTC_GetTime(&hrtc,&GetTime,RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc,&GetDate,RTC_FORMAT_BIN);
printf("%02d-%02d-%02d %02d:%02d:%02d ",GetDate.Year,GetDate.Month,GetDate.Date,GetTime.Hours,GetTime.Minutes,GetTime.Seconds);
if(GetDate.WeekDay==1){
printf(" 1\r\n");
}else if(GetDate.WeekDay==2){
printf(" 2\r\n");
}else if(GetDate.WeekDay==3){
printf(" 3\r\n");
}else if(GetDate.WeekDay==4){
printf(" 4\r\n");
}else if(GetDate.WeekDay==5){
printf(" 5\r\n");
}else if(GetDate.WeekDay==6){
printf(" 6\r\n");
}else if(GetDate.WeekDay==7){
printf(" 7\r\n");
}
HAL_Delay(1000);
(6)配置电路
前文的电路不用拆直接使用即可,多余的接线对本次实验并无影响,且不会导致短路。
4.实验效果
在不修改任何日期设置时,默认时间为00年1月1日 00:00:00,星期六
修改年份为0x21后,时间变为了21年1月1日00:00:00,星期五
三、总结
本次实验学到了挺多,一个是定时器,它的使用原理是计数个数到达一定值后触发中断,我们利用中断进行我们想要的操作,一个是RTC,要声明结构体来接受数据,还有日期的设定是用BCD码来进行设置,且默认为0x00就是2000年,0x21就是2022年,还有星期的计算是自动计算的,我们不能更改。