一个单片机控制系统开发应该需要有一个时间基准,我们现在看看定时器怎么使用。
通过手册可以看出,SWM181内部的定时器情况应该如下:
①1个24位系统滴答定时器
②4个通用32位定时器
③一个32位计数器
-----------------------------------------------------------------
按老套路来走,定时器的使用流程,一般是这样:
(1)设置定时器内部计数器的时钟源
(2)设置计数器的计数方式:自加/自减
(3)设置计数器的装载缓冲器(初值):
(4)使能溢出(自加)/置零(自减)中断
(5)使能定时器运行
-----------------------------------------------------------------
看看官方例程代码是怎么初始化系统滴答定时器的:
官方的库函数配置方法就一行代码:
SysTick_Config(SystemCoreClock/4); //每0.25秒钟触发一次中断
对应的系统滴答定时器中断代码,只需要写成以下格式便可:
void SysTick_Handler(void)
{
//代码
}
-----------------------------------------------------------------
问:上面这行代码为什么这样配置就可以得到"每0.25s触发一次中断"的效果呢?
我们需要了解系统滴答定时器的输入时钟源是什么?系统滴答定时器位于M0架构内部,跟我们这款MCU的外设设计无关,想要知道具体情况,应该翻阅M0架构的相关文档。暂且不做讨论。
我们追踪代码可以得知:
#define __HSI (24000000UL) //高速内部时钟
uint32_t SystemCoreClock = __HSI;
SysTick_Config(SystemCoreClock/4); //每0.25秒钟触发一次中断
__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 */
}
从代码可以看出,ticks就是定时器初值。
而且翻阅手册,得知:SysTick定时器是一个24位自减定时器。
我们只需要将(SystemCoreClock/4)再除以250,应该就可以将系统滴答定时器,配置为1ms触发一次中断。代码如下:
SysTick_Config(SystemCoreClock/4/250); //每1ms钟触发一次中断
中断服务程序里面放一个变量累加:
u32 gSysTick=0; //32位可以描述49天,若非项目要求,推荐使用32位,效率较高
void SysTick_Handler(void)
{
gSysTick++;
}
编写一个函数用于获取系统滴答值。
#define SysTick_t u64
SysTick_t GetSysTick(void)
{
SysTick_t temp=0;
/*关中断*/
SysTick->CTRL &= ~(1<<1);
temp = gSysTick;
/*开中断*/
SysTick->CTRL |= (1<<1);
return temp;
}
定义一下系统滴答的参数结构:
typedef struct{
SysTick_t Diff; //时间差
SysTick_t Old; //旧的滴答值
SysTick_t New; //新的滴答值
}TimeOut_t;
某些平台申请的变量,默认值非0,我们编写一个函数用于初始化这个结构。
/*--初始化软超时结构---------------------*/
void TimeOutArgsInit(TimeOut_t *tTimeOut)
{
tTimeOut->Diff = 0;
tTimeOut->New = 0;
tTimeOut->Old = 0;
}
这种结构,在使用单片机写裸机状态机程序时,非常好用。结构分明,具体后面再说。
基本框架已经定好了,忽然觉得24MHz是否有点慢了,修改工作频率,只需要修改这行代码即可。
#define SYS_CLK SYS_CLK_48MHz
然后官方的库函数会帮我们进行时钟初始化。
切记,千万不要修改下面三个宏,这三个宏,应该是定死的参数,官方库函数用的,如果变动,可能很多地方需要修改。
/*以下三个参数应该是不需要修改的,作为掩码一样使用,勿动*/
#define __HSI (24000000UL) //高速内部时钟
#define __LSI ( 32000UL) //低速内部时钟
#define __HSE (24000000UL) //高速外部时钟
我们只需要使用以上结构,就可以提供一个软定时器,工程开发就很方便了。