在平时我们针对裸机进行开发不使用RTOS的时候,有时候需要使用到简单的线程调度,如果使用硬件定时器实现的话,可能会受到硬件本身定时器资源的限制,这时候我们可以使用SysTick实现软件定时器。
软件定时器是用程序模拟出来的定时器,可以由一个硬件定时器模拟出成千上万个软件定时器,这样程序在需要使用较多定时器的时候就不会受限于硬件资源的不足,这是软件定时器的一个优点,即数量不受限制。
SysTick俗称嘀嗒定时器,是Cortex内核自带的组件,它是一个24位的递减计数器,用户仅需掌握ARM的CMSIS软件提供的一个函数SysTick_Config即可,原代码如下:
/* ################################## SysTick function ############################################ */
/** \ingroup CMSIS_Core_FunctionInterface
\defgroup CMSIS_Core_SysTickFunctions SysTick Functions
\brief Functions that configure the System.
@{
*/
#if (__Vendor_SysTickConfig == 0)
/** \brief System Tick Configuration
The function initializes the System Timer and its interrupt, and starts the System Tick Timer.
Counter is in free running mode to generate periodic interrupts.
\param [in] ticks Number of ticks between two interrupts.
\return 0 Function succeeded.
\return 1 Function failed.
\note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
must contain a vendor-specific implementation of this function.
*/
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = ticks - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
函数的形参表示内核时钟多少个周期后触发一次Systick定时中断,比如形参配置为如下数值。 -- SystemCoreClock / 1000 表示定时频率为 1000Hz, 也就是定时周期为 1ms。 -- SystemCoreClock / 500 表示定时频率为 500Hz, 也就是定时周期为 2ms。 -- SystemCoreClock / 2000 表示定时频率为 2000Hz, 也就是定时周期为 500us。
本次实验中使用软定时器实现了两个线程调度函数,其中第一个线程实现了按键扫描的功能,第二个线程实现了板载LED流水灯的功能,main函数如下:
#include "delay.h"
#include "sys.h"
#include "led.h"
#include "key.h"
#include "uart.h"
#include "soft_timer.h"
//变量定义
uint8_t count = 0;
extern u32 SystemCoreClock;
struct soft_timer test_timer1,test_timer2; //creat 2 soft timers
void timer1_call_back(void); //call back functions when timer over
void timer2_call_back(void);
void hw_timer_init(void)
{
SysTick_Config(SystemCoreClock / 100); //10 ms
NVIC_SetPriority (SysTick_IRQn, 1); //NVIC config
}
//按键扫描函数
void KeyScan(void)
{
uint8_t t;
t=KEY_Scan(0); //得到键值
switch(t)
{
case KEY1_PRES: //K1默认不连PC13,默认连接reset复位按键,所以按下K1会复位
printf("KEY1 Clicked!\r\n");
break;
case WKUP_PRES:
printf("KEY2 Clicked!\r\n");
break;
case KEY3_PRES:
printf("KEY3 Clicked!\r\n");
break;
case KEY4_PRES:
printf("KEY4 Clicked!\r\n");
break;
default:
break;
}
}
void timer1_call_back(void)
{
reload_timer(&test_timer1,10); //
start_timer(&test_timer1); //should be restart because of one shot software timer.
//按键扫描
KeyScan();
}
void timer2_call_back(void)
{
reload_timer(&test_timer2,30);
start_timer(&test_timer2);
count++;
if(count==1)
{
LED1_ON();
LED2_OFF();
LED3_OFF();
LED4_OFF();
}else if(count==2)
{
LED1_OFF();
LED2_ON();
LED3_OFF();
LED4_OFF();
}else if(count==3)
{
LED1_OFF();
LED2_OFF();
LED3_ON();
LED4_OFF();
}else if(count==4)
{
count = 0;
LED1_OFF();
LED2_OFF();
LED3_OFF();
LED4_ON();
}
}
/********************************************************************************************************
**函数信息 :main(void)
**功能描述 :
**输入参数 :无
**输出参数 :无
********************************************************************************************************/
int main(void)
{
delay_init();
LED_Init(); //初始化与LED连接的硬件接口
KEY_Init(); //初始化与按键连接的硬件接口
uart_initwBaudRate(9600); //串口初始化
hw_timer_init();
soft_timer_list_reset();
add_timer(&test_timer1,timer1_call_back,60); //
start_timer(&test_timer1);
add_timer(&test_timer2,timer2_call_back,30); //
start_timer(&test_timer2);
//打印欢迎信息
printf("Soft Timer Test Using SysTick\r\n");
printf("1、KeyScan\r\n");
printf("2、LED\r\n");
while(1)
{
}
}
该工程中已经将软件定时器编写成了驱动文件,便于移植和使用,主要文件为soft_timer.c和soft_timer.h文件,在Keil工程中添加源文件后的目录如下:
使用时需要在SysTick中断处理函数中添加软定时器刷新函数:
接下来使用时进行硬件定时器初始化和中断优先级配置和:
最后就是软件定时器的创建和回调函数编写:
本实验最后实现了LED流水灯和按键扫描两个线程的调度:
本工程完整源码如下:
此部分内容已被设置为付费内容,您可以在支付 2 元 人民币后浏览本楼层全部付费内容。点击购买
本楼层付费信息已有1人购买 |