1. 之前作业中的延时功能都是通过循环、delay/Hal_delay函数等实现,本次作业通过定时器Timer方式实现时间的精准控制,相当于给CPU上了一个闹钟,CPU平时处理其它任务,当定时时间到了以后,处理定时相关的任务。请设置一个5秒的定时器,每隔5秒从串口发送“hello windows!”;同时设置一个2秒的定时器,让LED等周期性地闪烁。
1.Stm32cubemx项目创建
1.新建项目后,选择芯片,我用的是stm32f103c8t6芯片。
2.配置RCC
3.配置sys
4.配置输出引脚PA1
5.配置定时器TIM2和TIM3分别作为串口通信和翻转Led灯状态的定时器,并使能中断
两个时钟配置都一样
注意;分频系数那里虽然写的是71,但系统处理的时候会自动加上1,所以实际进行的是72分频。由于时钟我们一般会配置为72MHZ,所以72分频后得到1MHZ的时钟。1MHZ的时钟,计数5000次,得到时间5000/1000000=0.005秒。也就是每隔0.005秒定时器2会产生一次定时中断。
6.配置串口用于向上位机发送信息
7.时钟配置
8.项目设置
9.点击GENRATE CODE创建项目
2、打开创建的项目
1.启动定时器
在main.c中添加代启动定时器TIM2和TIM3
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
2.串口通信
在main.c中编辑串口发送的信息
uint8_t hello[20]="hello windows! \n";
3.在main.c中重定义中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static uint32_t time_cnt =0;
static uint32_t time_cnt3 =0;
if(htim->Instance == TIM2)
{
if(++time_cnt >= 400)
{
time_cnt =0;
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_1);
}
}
if(htim->Instance == TIM3)
{
if(++time_cnt3 >= 1000)
{
time_cnt3 =0;
HAL_UART_Transmit(&huart1,hello,20,100000);
}
}
}
该函数为定时器的中断回调函数,当产生定时中断的时候,会自动调用这个函数。在函数内部定义了定时器的一个静态变量:time_cnt与定时器3 的time_cnt3。
例如time_cnt,当它大于等于100的时候,才会执行if里面的代码。也就是说需要发生400次中断,才会让LED的状态翻转。前面已经算过了,一次定时中断的时间是0.005秒,所以400次中断的时间是0.005400=2秒。也就是说每隔2秒,LED的状态翻转一次。
例如time_cnt3,当它大于等于1000的时候,才会执行if里面的代码。也就是说需要发生1000次中断,才会让串口发一次消息。0.0051000=5秒,符合题目要求。
3、结果演示
2. 了解实时时钟RTC的原理。STM32芯片自带RTC,因此不须像其他MCU需外接RTC模块。请编程实现STM32的日历读取、设置和输出。要求:
1)读取RTC初始时间,验证是否为 1970年1月1日零分零秒;
1、创建项目
1.设置串口
2.配置RTC
3.配置时钟
4.项目设置
2.打开项目
1.修改main.c主函数中的while循环
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* 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);
}
2.在main.c中重写printf函数
#include "stdio.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
int fputc(int ch,FILE *f){
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart1,temp,1,2);
return ch;
}
3.勾选Use MiscroLiB
4.效果演示
2)将RTC时间调整为当前时间,并以 2021年x月x日x分x秒的格式从串口输出(或输出到OLED屏),每1s改变一次;
1.rtc.c中修改为当前时间
2.修改main.c主函数中的while循环
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* 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日 \n",2000 + GetData.Year, GetData.Month, GetData.Date);
/* Display time Format : hh:mm:ss */
printf("%02d时%02d分%02d秒 \n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
printf(" \n");
HAL_Delay(1000);
}
3.效果演示
3)如果输出内容中需加入“星期x”,请修改代码。
1.修改main.c主函数中while循环
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* 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日 \n",2000 + GetData.Year, GetData.Month, GetData.Date);
/* Display time Format : hh:mm:ss */
printf("%02d时%02d分%02d秒 \n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
printf("星期%0d",GetData.WeekDay);
printf(" \n");
HAL_Delay(1000);
}
2.效果演示