@TOC
前言
本篇文章将带大家学习如何巧妙的使用systick,本篇文章将完善之前编写的按键程序,使用systick取代消抖函数的使用,增强代码的运行效率。
一、systick介绍
Systick是STM32系列单片机中的一种计时器,它可以提供一个可编程的基础定时器,用于实现实时操作系统(RTOS)中的系统节拍定时器。 Systick定时器可用于生成周期性的中断,并且它的时钟源通常与CPU时钟源相同。在STM32中,Systick定时器被实现为一个24位的递减计数器(SysTick_LOAD_RELOAD_Msk)和一个预分频器(SysTick_CTRL_CLKSOURCE_Msk),其精度可以达到1us。
Systick定时器的基本工作原理如下: 1. 在初始化Systick定时器之前,必须先使能计时器时钟,并设置预分频器;
2. 设置Systick定时器的中断周期,通常设置为1ms;
3. 启动Systick定时器;
3. 当定时器到达设定的周期时,会自动触发一个中断。 使用Systick定时器可以进行以下操作: 1. 计数器开始计数和停止计数; 2. 设定Systick定时器的时钟源; 3. 设定Systick定时器的中断周期; 4. 读取当前计数器的值; 5. 清除中断标志。 总的来说,Systick是STM32单片机中非常重要的一个模块之一,它可以用于实现实时操作系统(RTOS)中的系统节拍定时器、延时函数、计数器等功能。
说白了systick就像人的心跳一样维持着单片机的基本运行。
二、使用systick实现LED闪烁
之前就给大家讲过了HAL_Delay的实现原理,这里就不多说了,其实HAL_Delay这个函数就是使用到了systick实现的。
led_Tick是一个静态变量,用来记录上一次LED状态切换的时间,它的初值为0。当函数第一次执行时,这个静态变量就会被初始化。在LED_process()函数内部,每次执行到当前时间与上一次切换时间的差值少于500ms时,就会直接返回,不执行后续代码。这样就可以保证LED状态每隔500ms才会进行一次切换。
当到了LED状态应该切换的时间时,会更新led_Tick为当前的uwTick变量(uwTick表示系统启动以来的滴答定时器时间),然后更新status为当前状态的反转值。接着,调用Led_Set_Status()函数来设置LED的状态。
__IO uint32_t led_Tick = 0;
void LED_process(void)
{
static u8 status = 0;
if(uwTick - led_Tick < 500)
{
return ;
}
led_Tick = uwTick;
status = !status;
Led_Set_Status(1, status);
Led_Set_Status(3, status);
}
调用这个函数我们即可实现对应的LED灯闪烁了。 这个的核心就是return,当没有达到预定的时间时就会return返回出去,不会一直阻塞等待,这样极大提高了代码的运行效率。
LED_process();
三、按键代码的改写
key.h 宏定义KEYPORT将四个按键的状态读取,并将其中的高四位设置为1,表示没有按键按下。
#ifndef __KEY_H__
#define __KEY_H__
#include "main.h"
#define KB1 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)
#define KB2 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)
#define KB3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)
#define KB4 HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)
#define KEYPORT KB1 | (KB2<<1) | (KB3<<2) | (KB4<<3) | 0xf0
extern u8 Trg; // 全局变量,单次触发
extern u8 Cont; // 全局变量,长按
void Key_Read(void);
#endif
key.c 在函数Key_Read()中,首先定义局部变量ReadData来读取按键状态,并通过异或反转操作将其转化成按键按下时对应的二进制码。例如,当KB1被按下时,KB1对应的二进制位为0,与其异或则为1,反转之后就成了按键按下的状态。然后,变量Trg通过按键状态的异或操作来检测是否产生了单次触发,并将检测结果保存。
最后,变量Cont被更新为当前的按键状态,以便下一次检测触发方式时进行比较。这里使用变量Cont来记录键盘状态实现连续触发,在下一次轮询时,使用异或操作来检测是否继续触发。
#include "key.h"
u8 Trg; // 全局变量,单次触发
u8 Cont; // 全局变量,长按
void Key_Read(void)
{
u8 ReadData = (KEYPORT)^0xff; // 1
Trg = ReadData & (ReadData ^ Cont); // 2
Cont = ReadData; // 3
}
main.c 这里我们通过systick让程序每10ms进行一次判断是否有按键被按下,相比于之前的HAL_Delay(10);这里我们的程序运行效率是提高了的。
// 按键执行程序
__IO uint32_t keyTick = 0;
u16 key1_val = 0;
void Key_Scan(void)
{
if(uwTick - keyTick < 10) return ;
keyTick = uwTick;
Key_Read();
if(Trg & 0x01) //B1
{
//KB1被按下
}
if(Trg & 0x02) //B2
{
//KB2被按下
}
if(Trg & 0x04) //B3
{
//KB3被按下
}
if(Trg & 0x08) //B4
{
//KB4被按下
}
}
总结
希望大家可以掌握systick的妙用,掌握了他将让你的程序效率大大提高。