本帖最后由 hbzjt2011 于 2021-1-5 22:28 编辑
#申请原创# SysTick俗称嘀嗒定时器,是Cortex内核自带的组件,它是一个24位的递减计数器,利用SysTick实现软定时器结合回调任务函数可以实现简单任务调度。本次演示例子中利用两个软定时器实现了LED灯循环亮灭和按键扫描两个任务。首先将软定时器程序源文件soft_timer.c和soft_timer.h加入工程目中的driver文件夹。soft_timer.c
#include "soft_timer.h"
static struct soft_timer* soft_timer_list;
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] reset the soft_timer_list.
* @retval None.
*/
void soft_timer_list_reset(void)
{
soft_timer_list = TIMER_NULL;
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] add a timer to the software timer list.
* @param timer---------pointer to the timer you want to add.
* @param call_back-----the call back function when the timer is over.
* @param time_count-----the timer count.
* @retval None.
*/
void add_timer(struct soft_timer* timer,void(*call_back)(void),unsigned int time_count)
{
struct soft_timer* p;
p = soft_timer_list;
if(p==TIMER_NULL) //if the soft_timer_list have no timer
{
p = timer;
p->flag = TIMER_FLAG_SUSPEND;
p->tick_count = time_count;
p->time_over_proc = call_back;
p->next = TIMER_NULL;
soft_timer_list = p;
}
else
{
p = soft_timer_list;
while(p->next!=TIMER_NULL)
{
p = p->next;
}
p->next = timer;
p->next->flag = TIMER_FLAG_SUSPEND;
p->next->tick_count = time_count;
p->next->time_over_proc = call_back;
p->next->next = TIMER_NULL;
}
}
/**
* @brief remove a timer from the software timer list.
* @retval None.
*/
void remove_timer(struct soft_timer* timer)
{
struct soft_timer* t;
for(t = soft_timer_list; t != TIMER_NULL; t = t->next)
{
if(t->next==timer)
{
t->next = timer->next;
break;
}
}
}
/**
* @brief start or continue a timer
* @retval None.
*/
void start_timer(struct soft_timer* timer)
{
timer->flag = TIMER_FLAG_RUN ;
}
/**
* @brief stop a timer without calling back
* @retval None.
*/
void stop_timer(struct soft_timer* timer)
{
timer->flag = TIMER_FLAG_STOP;
timer->tick_count = 0;
}
/**
* @brief stop a timer with calling back
* @retval None.
*/
void stop_timer_with_call(struct soft_timer* timer)
{
if(timer->flag == TIMER_FLAG_RUN)
timer->tick_count = 0;
else if(timer->flag == TIMER_FLAG_SUSPEND)
{
timer->flag = TIMER_FLAG_RUN;
timer->tick_count = 0;
}
}
/**
* @brief suspend a timer
* @retval None.
*/
void suspend_timer(struct soft_timer* timer)
{
if(timer->flag == TIMER_FLAG_RUN)
timer->flag = TIMER_FLAG_SUSPEND;
}
/**
* @brief reload the tick_count for a timer
* @retval None.
*/
void reload_timer(struct soft_timer* timer,unsigned int time_count)
{
timer->flag = TIMER_FLAG_SUSPEND;
timer->tick_count = time_count;
}
/**
* @brief shoulde be called periodicly by the hardware timer ISR
* @retval None.
*/
void timer_periodic_refresh(void)
{
struct soft_timer* t;
for(t = soft_timer_list; t != TIMER_NULL; t = t->next)
{
if(t->flag==TIMER_FLAG_RUN)
{
if(t->tick_count > 0)
-- t->tick_count;
else
{
stop_timer(t);
t->time_over_proc();
}
}
}
}
soft_timer.h
#ifndef __SOFT_TIMER_H__
#define __SOFT_TIMER_H__
struct soft_timer{
int flag; //run flag, which can be SUSPEND,RUN,STOP
unsigned int tick_count; //left ticks to be run
void (*time_over_proc)(void); //timer over callback function
struct soft_timer* next;
};
#define TIMER_FLAG_SUSPEND 0
#define TIMER_FLAG_RUN 1
#define TIMER_FLAG_STOP 2
#define TIMER_NULL ((struct soft_timer*)0)
void soft_timer_list_reset(void);
void add_timer(struct soft_timer* timer,void(*call_back)(void),unsigned int time_count);
void remove_timer(struct soft_timer* timer);
void start_timer(struct soft_timer* timer);
void stop_timer(struct soft_timer* timer);
void stop_timer_with_call(struct soft_timer* timer);
void suspend_timer(struct soft_timer* timer);
void reload_timer(struct soft_timer* timer,unsigned int time_count);
void timer_periodic_refresh(void);
#endif /*__SOFT_TIMER_H__*/
然后在main.c程序中配置Systick的周期和中断优先级:
void hw_timer_init(void)
{
ald_systick_interval_select(SYSTICK_INTERVAL_10MS); //10 ms
NVIC_SetPriority (SysTick_IRQn, 1); //NVIC config
}
同时再irq.c文件中的系统嘀嗒定时器中断处理函数中添加软定时器刷新函数:
void SysTick_Handler(void)
{
ald_inc_tick();
timer_periodic_refresh();
return;
}
然后再程序运行开始后初始化定时器,同时复位定时器列表,添加软定时器1和软定时器2,同时在定时器1回调函数中添加按键扫描处理函数,在定时器2回调函数中添加LED灯处理函数,编译下载即可实现两个定时器任务循环调度运行。时间片可以通过定时器创建时设定。工程文件目录如下:
key.c
#include "main.h"
//////////////////////////////////////////////////////////////////////////////////
//开发板
//按键输入 驱动代码
//////////////////////////////////////////////////////////////////////////////////
//按键初始化函数
void KEY_Init(void)
{
gpio_init_t x;
x.mode = GPIO_MODE_INPUT;
x.odos = GPIO_PUSH_PULL;
x.pupd = GPIO_FLOATING;
x.podrv = GPIO_OUT_DRIVE_6;
x.nodrv = GPIO_OUT_DRIVE_6;
x.flt = GPIO_FILTER_DISABLE;
x.type = GPIO_TYPE_CMOS;
x.func = GPIO_FUNC_1;
ald_gpio_init(BSP_KEY1_PORT, BSP_KEY1_PIN, &x);
ald_gpio_init(BSP_KEY2_PORT, BSP_KEY2_PIN, &x);
ald_gpio_init(BSP_KEY3_PORT, BSP_KEY3_PIN, &x);
ald_gpio_init(BSP_KEY4_PORT, BSP_KEY4_PIN, &x);
ald_gpio_init(BSP_KEY5_PORT, BSP_KEY5_PIN, &x);
}
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//返回值:
//0,没有任何按键按下
//KEY1_PRES,KEY1按下
//WKUP_PRES,WK_UP按下
//KEY3_PRES,KEY3按下
//KEY4_PRES,KEY4按下
uint8_t KEY_Scan(uint8_t mode)
{
static uint8_t key_up=1;//按键按松开标志
if(mode)key_up=1; //支持连按
if(key_up&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0||KEY5==0))
{
//delay_ms(10);//去抖动
key_up=0;
if(KEY1==0)return KEY1_PRES;
else if(KEY2==0)return KEY2_PRES;
else if(KEY3==0)return KEY3_PRES;
else if(KEY4==0)return KEY4_PRES;
else if(KEY5==0)return KEY5_PRES;
}else if(KEY1==1&&KEY3==1&&KEY4==1&&KEY2==1&&KEY5==1)key_up=1;
return 0;// 无按键按下
}
key.h
#ifndef __KEY_H
#define __KEY_H
//////////////////////////////////////////////////////////////////////////////////
//开发板
//按键驱动代码
//////////////////////////////////////////////////////////////////////////////////
/* KEY1 ---> UP
* KEY2 ---> DOWN
* KEY3 ---> MID
* KEY4 ---> LEFT
* KEY5 ---> RIGHT
*/
#define BSP_KEY_MAX 5
#define BSP_KEY1_PORT GPIOB
#define BSP_KEY1_PIN GPIO_PIN_2
#define BSP_KEY2_PORT GPIOB
#define BSP_KEY2_PIN GPIO_PIN_12
#define BSP_KEY3_PORT GPIOC
#define BSP_KEY3_PIN GPIO_PIN_10
#define BSP_KEY4_PORT GPIOC
#define BSP_KEY4_PIN GPIO_PIN_11
#define BSP_KEY5_PORT GPIOC
#define BSP_KEY5_PIN GPIO_PIN_12
#define KEY1 ald_gpio_read_pin(BSP_KEY1_PORT, BSP_KEY1_PIN)//读取按键1
#define KEY2 ald_gpio_read_pin(BSP_KEY2_PORT, BSP_KEY2_PIN)//读取按键2
#define KEY3 ald_gpio_read_pin(BSP_KEY3_PORT, BSP_KEY3_PIN)//读取按键3
#define KEY4 ald_gpio_read_pin(BSP_KEY4_PORT, BSP_KEY4_PIN)//读取按键4
#define KEY5 ald_gpio_read_pin(BSP_KEY5_PORT, BSP_KEY5_PIN)//读取按键5
#define KEY1_PRES 1 //KEY1
#define KEY2_PRES 2 //KEY2
#define KEY3_PRES 3 //KEY3
#define KEY4_PRES 4 //KEY4
#define KEY5_PRES 5 //KEY5
void KEY_Init(void);//IO初始化
uint8_t KEY_Scan(uint8_t mode); //按键扫描函数
#endif
main.c
#include "main.h"
/** @addtogroup Projects_Templates_ALD
* @{
*/
/** @addtogroup Templates
* @{
*/
extern uart_handle_t h_uart;
uint8_t tx_buf[32];
uint8_t count = 0;
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)
{
ald_systick_interval_select(SYSTICK_INTERVAL_10MS); //10 ms
NVIC_SetPriority (SysTick_IRQn, 1); //NVIC config
}
//按键扫描函数
void KeyScan(void)
{
uint8_t t;
t=KEY_Scan(0); //得到键值
switch(t)
{
case KEY1_PRES:
sprintf((char *)tx_buf, "KEY1 Clicked!\n");
ald_uart_send(&h_uart, tx_buf, sizeof("KEY1 Clicked!\n"), 1000);
break;
case KEY2_PRES:
sprintf((char *)tx_buf, "KEY2 Clicked!\n");
ald_uart_send(&h_uart, tx_buf, sizeof("KEY2 Clicked!\n"), 1000);
break;
case KEY3_PRES:
sprintf((char *)tx_buf, "KEY3 Clicked!\n");
ald_uart_send(&h_uart, tx_buf, sizeof("KEY3 Clicked!\n"), 1000);
break;
case KEY4_PRES:
sprintf((char *)tx_buf, "KEY4 Clicked!\n");
ald_uart_send(&h_uart, tx_buf, sizeof("KEY4 Clicked!\n"), 1000);
break;
case KEY5_PRES:
sprintf((char *)tx_buf, "KEY5 Clicked!\n");
ald_uart_send(&h_uart, tx_buf, sizeof("KEY5 Clicked!\n"), 1000);
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)
{
ald_gpio_write_pin(LED1_PORT, LED1_PIN, 0);
ald_gpio_write_pin(LED2_PORT, LED2_PIN, 1);
}else if(count==2)
{
count = 0;
ald_gpio_write_pin(LED1_PORT, LED1_PIN, 1);
ald_gpio_write_pin(LED2_PORT, LED2_PIN, 0);
}
}
/**
* @brief This is main function.
* Detect running time.
* @retval Status
*/
int main()
{
/* Initialize ALD */
ald_cmu_init();
/* Configure system clock */
ald_cmu_pll1_config(CMU_PLL1_INPUT_HOSC_3, CMU_PLL1_OUTPUT_72M);
ald_cmu_clock_config(CMU_CLOCK_PLL1, 72000000);
/* Enable peripheral */
ald_cmu_perh_clock_config(CMU_PERH_GPIO, ENABLE);
ald_cmu_perh_clock_config(CMU_PERH_UART0, ENABLE);
/* Initialize tx_buf */
memset(tx_buf, 0x55, sizeof(tx_buf));
///* Initialize uart_usb */
uart_usb_init();
/* Initialize led */
led_pin_init();
KEY_Init(); //初始化与按键连接的硬件接口
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_e("Soft Timer Test Using SysTick\r\n");
printf_e("1、KeyScan\r\n");
printf_e("2、LED\r\n");
while (1) {
#if 0
/* Send a message */
sprintf((char *)tx_buf, "es32 uart test!\n");
ald_uart_send(&h_uart, tx_buf, sizeof("es32 uart test!\n"), 1000);
ald_gpio_write_pin(LED1_PORT, LED1_PIN, 0);
ald_gpio_write_pin(LED2_PORT, LED2_PIN, 0);
ald_delay_ms(500);
ald_gpio_write_pin(LED1_PORT, LED1_PIN, 1);
ald_gpio_write_pin(LED2_PORT, LED2_PIN, 1);
ald_delay_ms(500);
#endif
ald_delay_ms(500);
}
}
程序编译无误下载后,即可看到LED灯循环亮灭,按下开发板上的五向按键串口进行相应的打印输出。
@21小跑堂
|
共1人点赞
|