蓝桥杯嵌入式第四课--定时器

前言

蓝桥杯对于定时器这部分的考察主要集中在定时器中断PWM输出以及输入捕获三个方面,本节课着眼于应用,介绍一下定时器的使用。

定时器中断

一、基础概念

对没接触过定时器的新手来说,如果想要快速上手定时器的使用,首先要先对定时器建立一个初步的印象。我们所说的定时器,从本质上看其实是一个计数器,可以从零开始计数,计到一个最大值,我们称其为 自动重装载值(ARR),然后清零,再重新开始计数,如此往复。这就是最基础也是最常用的向上计数模式,在此基础上,还有向下计数,和中央对齐计数(即从0到ARR,再从ARR到0)。

在计数器的基础上打个比方,如果我们需要定时10秒,我们只需让计数器每秒加1,加到10之后告诉我们时间到了,然后再从零开始即可。

针对上面的描述,我们又引出一个参数:定时器的频率。针对我们的比赛,计数器每计一个数需要消耗的时间 t = 系统时钟频率/预分频值。也就是:

f = 80Mhz/psc

并且,定时器到时间后还需要提醒我们,因此,每当计数值满了时(即溢出),都要产生一个定时器中断。

二、配置操作

一、CubeMx激活定时器

如上图所示:

  1. 选择一个定时器

  1. 选择定时器的时钟源

  1. 配置定时器的预分频系数 Prescaler、以及自动重装载值ARR

这里的重点在于Psc参数和ARR参数的设置。公式如下:

二、使能中断

我们使用定时器的更新中断作为实验的中断源。

三、编写代码

定时器中断主要添加两个函数即可:

  HAL_TIM_Base_Start_IT(&htim1);   //该函数开启定时器,置于main.c中定时器初始化代码之后

以及回调函数:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){ //置于main()函数之后
    if(htim == &htim1)  //判断中断是否来自于定时器1
   {
       代码;
   }
}

这样当计数器溢出时,中断就会触发,并执行回调函数。

四、实验任务

如果你现在看到这了,请完成一个,每隔1s加一的计时器,并将结果显示在LCD上(5分钟即可解决,代码后续我会附上)。

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();
  HAL_TIM_Base_Start_IT(&htim1);   //启动计数
  LCD_Init();
  /* USER CODE BEGIN 2 */
  char text[30];
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    
    LCD_Clear(White);
    LCD_SetBackColor(Blue);
    LCD_SetTextColor(Black);
 
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
sprintf(text,"    t = %d   ",i);
 LCD_DisplayStringLine(Line4,(unsigned char *)text);
    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
    if(htim == &htim1)  //判断中断是否来自于定时器1
   {
       i++;
   }
}

任意占空比PWM输出

一、基础概念

PWM输出其实是在定时器的基础上发展而来的一个外设。核心原理就是设置一个数,我们称之为CCR(比较寄存器),当我们的计数值CNT小于CCR时,输出高电平,大于CCR时,输出低电平,只要我们改变CCR的值就可以实现占空比可调的PWM波输出。

二、配置操作

  1. 选择输出管脚

像上面这种带N的和其它一些奇怪的都不要选择,我们可以选择TIM4_CH4作为输出PWM的定时器通道。

  1. 选择时钟源和输出模式

3.配置定时器的PSC和ARR

这两个参数对PWM的频率产生决定性的影响,需要好好计算一下,上面的参数配置了PWM的频率为1000Hz。

4.配置通道的参数

对于通道而言,这个的Mode选择PWM mode 1,并且,Pulse参数设置的是占空比,这里我们设置为零,这个参数在程序中可以通过函数进行实时设置。

三、编写代码

在代码中,需要补充如下函数:

1、HAL_TIM_PWM_Start;开启PWM输出
/**
  * @brief  Starts the PWM signal generation.
  * @param  htim TIM handle
  * @param  Channel TIM Channels to be enabled
  *          This parameter can be one of the following values:
  *            @arg TIM_CHANNEL_1: TIM Channel 1 selected
  *            @arg TIM_CHANNEL_2: TIM Channel 2 selected
  *            @arg TIM_CHANNEL_3: TIM Channel 3 selected
  *            @arg TIM_CHANNEL_4: TIM Channel 4 selected
  *            @arg TIM_CHANNEL_5: TIM Channel 5 selected
  *            @arg TIM_CHANNEL_6: TIM Channel 6 selected
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)

与此对应还有

HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
2、__HAL_TIM_SetCompare;设置占空比
__HAL_TIM_SetCompare(&htimx, TIM_CHANNEL_x, pwm_value); 
3、_HAL_TIM_SET_AUTORELOAD;设置频率
__HAL_TIM_SET_AUTORELOAD(&htimx, prc_value);    

小结

定时器最基本的两个应用就是定时器中断和PWM输出。定时器的配置过程为:

  1. 设置分频系数PSC与自动重装载值ARR,以确定定时器中断的触发时间

  1. 打开定时器中断

  1. 代码中启动定时器HAL_TIM_Base_Start_IT以及编写回调函数HAL_TIM_PeriodElapsedCallback

PWM的配置过程在前面基础上(可不开启中断):

  1. 配置PWM的模式,以及CCR寄存器值,以确定占空比

  1. 代码中启动PWM:HAL_TIM_PWM_Start,并且设置占空比__HAL_TIM_SetCompare与频率_HAL_TIM_SET_AUTORELOAD;

下一篇文章介绍输入捕获的配置!

<think>好的,我需要帮助用户查找与小蜜蜂蓝桥杯相关的定时器实现或问题。首先,我需要回顾用户提供的参考引用,看看哪些涉及定时器内容。引用[1]和[3]、[4]、[5]都提到了定时器的使用。 引用[1]提到定时器的基本原理,包括TMOD寄存器设置、中断允许控制等,这可能是用户需要的基础知识。引用[3]详细展示了定时器初始化函数和中断服务程序的代码,用于实现秒表功能,这里涉及到定时器0的模式设置和中断处理。引用[4]讨论了如何用定时器实现秒闪功能,显示格式包括分、秒和50ms单位。引用[5]强调了定时器与其他模块(如数码管、按键)的综合应用,这可能对用户整合功能有帮助。 用户的问题集中在“实现”和“问题”上,因此我需要整理出具体的实现步骤和常见问题。首先,定时器的初始化流程是关键,包括设置TMOD、计算初值、开启中断和启动定时器。然后,中断服务程序中的重装初值和计数逻辑需要注意准确性。此外,时间数据的处理,比如将计数转换为分、秒,以及显示格式的处理,也是重要部分。常见问题可能包括定时不准、中断冲突、显示刷新问题等,需要根据引用中的代码和描述给出解决方案。 需要确保回答结构清晰,分点说明实现步骤和问题解决方法,同时结合用户提供的代码示例。还要注意使用正确的中文术语和格式,比如寄存器名称用代码块标出。最后,生成的相关问题应围绕定时器的配置、优化、多任务处理等,帮助用户进一步学习。</think>### 小蜜蜂蓝桥杯定时器实现与问题解析 #### 一、定时器基础实现 1. **定时器初始化** 根据引用[3],定时器初始化需配置寄存器`TMOD`选择模式(如模式1:`TMOD=0x01`),计算初值并装载到`TH0/TL0`,开启中断(`ET0=1`和`EA=1`),最后通过`TR0`控制定时器启停。 例如,实现50ms中断的代码: ```c void InitTimer0() { TMOD = 0x01; // 定时器0模式1(16位定时器) TH0 = (65535 - 50000) / 256; // 计算50ms初值(12MHz晶振) TL0 = (65535 - 50000) % 256; ET0 = 1; // 允许定时器0中断 EA = 1; // 开启总中断 TR0 = 0; // 初始关闭定时器 } ``` 2. **中断服务程序** 在中断中需重装初值,并通过计数器实现时间累积。例如,实现秒表功能的逻辑: ```c unsigned int t_005s = 0, t_s = 0, t_m = 0; void ServiceTimer0() interrupt 1 { TH0 = (65535 - 50000)/256; // 重装初值 TL0 = (65535 - 50000)%256; t_005s++; if (t_005s == 20) { // 20*50ms=1s t_s++; t_005s = 0; if (t_s == 60) { // 秒进位到分 t_m++; t_s = 0; if (t_m == 99) t_m = 0; // 分钟归零 } } } ``` 3. **时间显示处理** 根据引用[4],显示格式需将`t_m`(分)、`t_s`(秒)、`t_005s`(50ms单位)转换为`XX-XX-XX`格式,例如`08-26-18`表示8分26秒900ms。 --- #### 二、常见问题与解决方法 1. **定时器中断不触发** - 检查`TMOD`配置是否正确(如模式1应为`0x01`)。 - 确认`ET0`和`EA`是否开启。 - 检查初值计算是否匹配晶振频率(如12MHz下50ms初值为`50000`)。 2. **时间累积误差** - 中断服务程序必须**优先执行**,避免被其他代码阻塞。 - 重装初值时需使用`TH0/TL0 = ...`而非`+=`操作[^3]。 3. **数码管显示闪烁或卡顿** - 确保中断服务程序执行时间短(避免复杂计算)。 - 显示刷新代码应放在主循环中,而非中断内[^5]。 4. **多任务冲突** - 若同时使用定时器0和1,需分别配置`TMOD`(如`TMOD=0x11`)。 - 通过状态标志位协调任务(如`flag_50ms`触发显示更新)[^5]。 --- #### 三、扩展应用 1. **按键消抖与定时器** 可利用定时器中断实现按键状态扫描,避免机械抖动干扰。 2. **PWM调光控制** 通过定时器中断调节LED占空比,实现呼吸灯效果。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值