蓝桥杯嵌入式systick的妙用

334 阅读4分钟

@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的妙用,掌握了他将让你的程序效率大大提高。