时钟不息工作不止,systic时钟应用
a) 目的:使用系统时钟来进行两项实验——周期执行代码与精确定时延迟。
b) 初始化函数定义:
void SysTick_Configuration(void);
c) 初始化函数调用:
SysTick_Configuration();
d) 初始化函数:
void SysTick_Configuration(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//时钟除8
SysTick_SetReload(250000); //计数周期长度
SysTick_CounterCmd(SysTick_Counter_Enable); //启动计时器
SysTick_ITConfig(ENABLE); //打开中断
}
e) 在NVIC的初始化函数里面增加以下代码打开相关中断:
NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中断等级设置,一般设置的高一些会少受其他影响
f) 在stm32f10x_it.c文件中找到void SysTickHandler 函数
void SysTickHandler(void)
{
执行代码
}
g) 简单应用:精确延迟函数,因为systic中断往往被用来执行周期循环代码,所以一些例程中使用其中断的启动和禁止来编写的精确延时函数实际上不实用,我自己编写了精确计时函数反而代码更精简,思路更简单。思路是调用后,变量清零,然后使用时钟来的曾变量,不断比较变量与延迟的数值,相等则退出函数。代码和步骤如下:
i. 定义通用变量:u16 Tic_Val=0; //变量用于精确计时
ii. 在stm32f10x_it.c文件中相应定义:
extern u16 Tic_Val;//在本文件引用MAIN.c定义的精确计时变量
iii. 定义函数名称:void Tic_Delay(u16 Tic_Count);//精确延迟函数
iv. 精确延时函数:
void Tic_Delay(u16 Tic_Count) //精确延时函数
{ Tic_Val=0; //变量清零
while(Tic_Val != Tic_Count){printf("");}//计时
}
v. 在stm32f10x_it.c文件中void SysTickHandler 函数里面添加
Tic_Val++;//变量递增
vi. 调用代码:Tic_Delay(10); //精确延时
vii. 疑问:如果去掉计时行那个没用的printf("");函数将停止工作,这个现象很奇怪
C语言功底问题。是的,那个“注意事项”最后的疑问的原因就是这个
Tic_Val应该改为vu16
while(Tic_Val != Tic_Count){printf("");}//计时
就可以改为:
while(Tic_Val != Tic_Count); //检查变量是否计数到位
STM32笔记之十三:恶搞,两只看门狗
a) 目的:
了解两种看门狗(我叫它:系统运行故障探测器和独立系统故障探测器,新手往往被这个并不形象的象形名称搞糊涂)之间的区别和基本用法。
b) 相同:
都是用来探测系统故障,通过编写代码定时发送故障清零信号(高手们都管这个代码叫做“喂狗”),告诉它系统运行正常。一旦系统故障,程序清零代码(“喂狗”)无法执行,其计数器就会计数不止,直到记到零并发生故障中断(狗饿了开始叫唤),控制CPU重启整个系统(不行啦,开始咬人了,快跑……)。
c) 区别:
独立看门狗Iwdg——我的理解是独立于系统之外,因为有独立时钟,所以不受系统影响的系统故障探测器。(这条狗是借来的,见谁偷懒它都咬!)主要用于监视硬件错误。
窗口看门狗wwdg——我的理解是系统内部的故障探测器,时钟与系统相同。如果系统时钟不走了,这个狗也就失去作用了。(这条狗是老板娘养的,老板不干活儿他不管!)主要用于监视软件错误。
d) 初始化函数定义:鉴于两只狗作用差不多,使用过程也差不多初始化函数栓一起了,用的时候根据情况删减。
void WDG_Configuration(void);
e) 初始化函数调用:
WDG_Configuration();
f) 初始化函数
void WDG_Configuration() //看门狗初始化
{
//软件看门狗初始化
WWDG_SetPrescaler(WWDG_Prescaler_8); //时钟8分频4ms
// (PCLK1/4096)/8= 244 Hz (~4 ms)
WWDG_SetWindowValue(65); //计数器数值
WWDG_Enable(127); //启动计数器,设置喂狗时间
// WWDG timeout = ~4 ms * 64 = 262 ms
WWDG_ClearFlag(); //清除标志位
WWDG_EnableIT(); //启动中断
//独立看门狗初始化
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//启动寄存器读写
IWDG_SetPrescaler(IWDG_Prescaler_32);//40K时钟32分频
IWDG_SetReload(349); //计数器数值
IWDG_ReloadCounter(); //重启计数器
IWDG_Enable(); //启动看门狗
}
g) RCC初始化:只有软件看门狗需要时钟初始化,独立看门狗有自己的时钟不需要但是需要systic工作相关设置。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
h) 独立看门狗使用systic的中断来喂狗,所以添加systic的中断打开代码就行了。软件看门狗需要在NVIC打开中断添加如下代码:
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQChannel; //通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //占先中断等级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应中断优先级
NVIC_Init(&NVIC_InitStructure); //打开中断
i) 中断程序,软件看门狗在自己的中断中喂狗,独立看门狗需要使用systic的定时中断来喂狗。以下两个程序都在stm32f10x_it.c文件中。
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(0x7F); //更新计数值
WWDG_ClearFlag(); //清除标志位
}
void SysTickHandler(void)
{ IWDG_ReloadCounter(); //重启计数器(喂狗)
}
j) 注意事项:
i. 有狗平常没事情可以不理,但是千万别忘了喂它,否则死都不知道怎么死的!
ii. 初始化程序的调用一定要在systic的初始化之后。
iii. 独立看门狗需要systic中断来喂,但是systic做别的用处不能只做这件事,所以我写了如下几句代码,可以不影响systic的其他应用,其他systic周期代码也可参考:
第一步:在stm32f10x_it.c中定义变量
int Tic_IWDG; //喂狗循环程序的频率判断变量
第二步:将SysTickHandler中喂狗代码改为下面:
Tic_IWDG++; //变量递增
if(Tic_IWDG>=100) //每100个systic周期喂狗
{ IWDG_ReloadCounter();//重启计数器(喂狗)
Tic_IWDG=0; //变量清零
}