第8周作业
文章目录
前言
第8周-定时器与日历时钟
一、定时器
1、LED周期闪烁
1)创建项目
1.打开外部时钟,点击“System Core”,选择RCC,在右侧弹出的菜单栏中选择“Crystal/Ceramic Resonator”。
2.选择调试接口,点击“System Core”,选择RCC。,在右侧弹出的菜单栏中选择“Serial Wire”。
3.配置IO。LED部分和实验2一样,配置PC15,并命名为D1。
4.配置定时器2。这里我们使用定时器2来实现定时的功能。如图所示,依次点击位置1,选中定时器2;位置2,配置定时器2的时钟源为内部时钟;位置3,分频系数为71,向上计数模式,计数周期为5000,使能自动重载模式。
分频系数那里虽然写的是71,但系统处理的时候会自动加上1,所以实际进行的是72分频。由于时钟我们一般会配置为72MHZ,所以72分频后得到1MHZ的时钟。1MHZ的时钟,计数5000次,得到时间5000/1000000=0.005秒。也就是每隔0.005秒定时器2会产生一次定时中断。
5.配置中断。如下图所示,开启定时器2的中断。
如下图所示,生成定时器2中断优先级配置代码。
6.时钟配置
7.进行相应配置,生成工程文件
2)配置keil
1.修改工程。生成工程后,打开,添加中断响应之后所需的一些代码。在main.c文件中添加如下内容
代码如下:
HAL_TIM_Base_Start_IT(&htim2);
代码如下:
//定时器回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint32_t time_cnt =0;
if(htim->Instance == TIM2)
{
if(++time_cnt >= 400)
{
time_cnt =0;
HAL_GPIO_TogglePin(D1_GPIO_Port,D1_Pin);
}
}
}
该函数为定时器的中断回调函数,当产生定时中断的时候,会自动调用这个函数。在函数内部定义了一个静态变量:time_cnt。当它大于等于400的时候,才会执行if里面的代码。也就是说需要发生400次中断,才会让LED的状态翻转。前面已经算过了,一次定时中断的时间是0.005秒,所以400次中断的时间是0.005*400=2秒。也就是说每隔2秒,LED的状态翻转一次。
2.修改后,编译,烧录,重新上电。可以看到LED1差不多每隔2秒翻转一次,实现了我们想要的效果。
3)效果展示
TIMER2_LED
2、串口周期发送
1)配置项目
其他设置和1、中一样。
2)在keil配置代码
1.在main函数前定义全局变量
2.在main函数中设置接收中断
代码如下:
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
3.main函数中的while循环里面添加传输代码
4.在main函数下面重写中断处理函数
代码如下:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
//当输入的指令为0时,发送提示并改变flag
if(c=='0'){
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips2, strlen(tips2),0xFFFF);
}
//当输入的指令为1时,发送提示并改变flag
else if(c=='1'){
flag=1;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips1, strlen(tips1),0xFFFF);
}
//当输入不存在指令时,发送提示并改变flag
else {
flag=0;
HAL_UART_Transmit(&huart1, (uint8_t *)&tips, strlen(tips),0xFFFF);
}
//重新设置中断
HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 1);
}
5.打开野火助手发现每隔5s发送一次hello windows。
3)效果展示
hellowindows
二、日历时钟
1、了解时钟RTC并验证初始时间
1)RTC及其特征
RTC是个独立的定时器。RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。
RCT特征:
● 可编程的预分频系数:分频系数高为220。
● 32位的可编程计数器,可用于较长时间段的测量。
● 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟 频率的四分之一以上)。
● 可以选择以下三种RTC的时钟源:
● HSE时钟除以128;
● LSE振荡器时钟;
● LSI振荡器时钟
● 2个独立的复位类型:
● APB1接口由系统复位;
● RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位
● 3个专门的可屏蔽中断:
● 1.闹钟中断,用来产生一个软件可编程的闹钟中断。
● 2.秒中断,用来产生一个可编程的周期性中断信号(长可达1秒)。
● 3.溢出中断,指示内部可编程计数器溢出并回转为0的状态。
RTC时钟源:
三种不同的时钟源可被用来驱动系统时钟(SYSCLK):
● HSI振荡器时钟
● HSE振荡器时钟
● PLL时钟
这些设备有以下2种二级时钟源:
● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。 RTC用于从停机/待机模式下自动唤醒系统。
● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。
2)RTC原理框图
3)初始时间
4)验证
2、以 x年x月x日x分x秒的格式从串口输出
1)创建项目
1.配置RCC(设置高速外部时钟,使能外部晶振LSE)
2.配置RTC(激活时钟源(Activate Clock Source)和日历(Activate Calendar))
3.设置时间为2022/11/3 14:50
4.使能串口
5.时钟树配置
6.设置项目
2)添加代码
1.打开stm32f1xx_hal_rtc.h文件可以看到以下函数
2.在main.c文件中重写fputc函数,完成printf函数的重定向
代码如下:
//添加头文件#include "stdio.h"
int fputc(int ch,FILE *f){
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,2);
return ch;
}
3.在main.c中定义时间和日期的结构体用来获取时间和日期
RTC_DateTypeDef GetData; //获取日期结构体
RTC_TimeTypeDef GetTime; //获取时间结构体
如图:
4.在main函数的while循环中添加以下代码
/* Get the RTC current Time */
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
/* Display date Format : yy/mm/dd */
printf("%02d/%02d/%02d\r\n",2000 + GetData.Year, GetData.Month, GetData.Date);
/* Display time Format : hh:mm:ss */
printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
printf("\r\n");
HAL_Delay(1000);
如图:
接下来,编译并且烧录。
3)效果展示
输出的时间就是现在的时间。并且输出间隔是1s。
3、输出内容中加入“星期x”
1)添加代码
1.在下图所示位置后面加上以下代码
代码如下:
/* Display date Format : weekday */
if(GetData.WeekDay==1){
printf("星期一\r\n");
}else if(GetData.WeekDay==2){
printf("星期二\r\n");
}else if(GetData.WeekDay==3){
printf("星期三\r\n");
}else if(GetData.WeekDay==4){
printf("星期四\r\n");
}else if(GetData.WeekDay==5){
printf("星期五\r\n");
}else if(GetData.WeekDay==6){
printf("星期六\r\n");
}else if(GetData.WeekDay==7){
printf("星期日\r\n");
}
2.编译烧录。
2)效果展示
正确输出了此时的星期数-----星期一。
总结
本次作业让我学会了如何通过定时器Timer方式实现时间的精准控制,了解了实时时钟RTC的原理,按年月日时分星期输出。