STM32 独立看门狗定时器IWDG复位

发布者:清新微笑最新更新时间:2016-10-11 来源: eefocus关键字:STM32  独立看门狗  定时器  IWDG复位 手机看文章 扫描二维码
随时随地手机看文章
无论是什么微控制器,一般都会有看门狗模块。对于STM32来说,它具有两个看门狗:独立看门狗(IWDG)与窗口看门狗(WWDG)。这里就先讲讲独立看门狗。
看门狗能够检测和解决有软件错误引起的故障。当一个错误导致看门狗不能及时“喂狗”,那么它就会产生一个系统复位。独立看门狗,之所以“独立”,是因为它由专门的40kHz左右的低速时钟驱动的,及即时主时钟发生故障它也仍然有效。为它提供时钟的低速时钟LSI的频率虽然号称是40KHz,但实际上并不准确,它有MCU内部RC振荡产生,频率会会在30kHz~60kHz之间变化。所以,独立看门狗不能用来精确计时。如果想要实现准确计时,那还需要对LSI进行校准。独立看门狗最适合用于那些在一个主程序之外能够完全独立工作,并且对时间要求较低的场合。
下面就来实现下独立看门狗定时器的系统复位。还是基于我自己的规范工程。
1、工程的修改
1)当然要先添加stm32f10x_iwdg.c文件到STM32F10x_StdPeriph_Driver工程组中。因为这里我们要先校准LSI时钟频率,所以还要添加stm32f103_tim.c文件以便校验LSI时钟。
2)打开stm32f10x_conf.c文件,将其中原先屏蔽着的:#include "stm32f10x_iwdg.h" 与 #include "stm32f10x_tim.h"这两句话的屏蔽去掉。
3)新建IWDGRReset.c和IWDGReset.h两个文件,分别保存在BSP文件下的src与inc中,并将IWDGReset.c文件添加到BSP工作组中。
 
2、IWDGRReset.c和IWDGReset.h两个文件代码的编写
前面曾经说过,独立看门狗定时器的计数值不准确,因为它的时钟源是低速时钟LSI,所以在初始化独立看门狗定时器之前,需要先校准下LSI。校验LSI的步骤如下:
1)打开TIM5,设置通道4为输入捕获模式
2)设置AFIO_MAPR的TIM5_CH4_IREMAP位为‘1’,在内部吧LSI连接到TIM5的通道4.
3)通过TIM5的捕获/比较4事件或者中断来测量LSI的时钟频率。
所以在初始化独立看门狗定时器之前,需要配置下TIM5,将它的CH4配置成输入捕获,代码如下:

/*************************************************************
Function : IWDGReset_TIM5_Init
Description: 初始化TIM5,用来校准LSI时钟
Input : none
return : none
*************************************************************/
static void IWDGReset_TIM5_Init(void)
{
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);//打开TIM5时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);//打开AFIO时钟,引脚重映射一定要时,一定要有这句话
TIM_PrescalerConfig(TIM5, 0, TIM_PSCReloadMode_Immediate);//不对TIM5之中进行分频,所以TIM5这时候的时钟是72M
GPIO_PinRemapConfig(GPIO_Remap_TIM5CH4_LSI, ENABLE);//在内部吧LSI连接到TIM4的CH4上,用CH4来测量LSI时钟频率

TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;//TIM5的CH4
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//检测上升沿
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//管脚与寄存器直接对应
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV8;//输入捕获8预分频,即检测到8个上升沿才生成中断标志
TIM_ICInitStructure.TIM_ICFilter = 0;//不滤波
TIM_ICInit(TIM5, &TIM_ICInitStructure);//初始化TIM5的CH4

TIM_ITConfig(TIM5, TIM_IT_CC4, ENABLE);//打开CH4中断源
TIM5->SR = 0;//清除TIM5的所有标志位
TIM_Cmd(TIM5, ENABLE);//打开TIM5

NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;//设置TIM5的中断优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

首先要将TIM5的时钟打开。除此之外还要将AFIO的时钟打开,这个很重要,要不然就TIM5的引脚重映射就没有效果了。接下去就要将TIM5的CH4重映射到LSI上,也就是上面的GPIO_PinRemapConfig(GPIO_Remap_TIM5CH4_LSI, ENABLE)语句。再下去则要将TIM5的CH4配置成输入捕获,上升沿捕获,8预分频,不滤波。这里对CH4输入捕获进行8与分频是有目的,LSI的时钟频率在30kHz~60kHz,所以如果不分频的话,CH4的计数值变化范围为:(72M/30k)=1200~(72M/60k)=2400,它的变化才1200左右,相对于16为计数值而言只是小数目,这样计算出来的LSI频率误差就很大;而如果进行8预分频,CH4捕获到8次上升沿才产生中断标志位,也就是说让CH4采集8个周期,CH4的计数值变化范围为:9600~19200,变化有将近10000了,然后将计算出的频率处除与8,就是LSI的频率了,这样计算出LSI的频率误差就小了。接下去打开TIM5,打开CH4的苏茹捕获中断,同时清除TIM5所有的标志位。最后配置下TIM5的中断优先级为1。
TIM5配置好了,就要开始校准LSI时钟了,代码如下:

u32 LsiFreq = 40000; //LSI时钟频率默认为40kHz
extern u16 CaptureNumber; //捕获次数

/*************************************************************
Function : IWDGReset_LSICalibration
Description: 校准LSI时钟频率
Input : none
return : none
*************************************************************/
static void IWDGReset_LSICalibration(void)
{
RCC_LSICmd(ENABLE);//打开LSI时钟
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET); //等待LSI时钟稳定

IWDGReset_TIM5_Init();//初始化TIM5
while(CaptureNumber != 2);//等待检测到LSI的2个上升沿
PRINTF("LSI freq: %dHz\r\n", LsiFreq);//将测量的LSI频率打印出来

TIM_ITConfig(TIM5, TIM_IT_CC4, DISABLE);//关闭CH4中断源
}

要校准LSI时钟,首先当然是先将LSI时钟打开,让内部的RC振荡器开始工作,等到振荡稳定后,再配置TIM5的CH4开始校准LSI。计算LSI频率的代码在stm32f10x_it.c的TIM5中断服务程序中,我之后再讲。等待知道捕获计数值CaptureNumber(在stm32f10x_it.c中定义)等于2,表示LSI的频率LsiFreq(默认情况下位40k)已经计算出来了。接下去将计算出来的LSI频率打印出来。最后在关闭TIM5 CH4的输入捕获中断。
接下去,就开始讲独立看门狗的初始化了,代码如下:

/*************************************************************
Function : IWDGReset_Init
Description: 独立看门狗初始化
Input : none
return : none
*************************************************************/
void IWDGReset_Init(void)
{
IWDGReset_LSICalibration(); //打开LSI,并校准LSI时钟

IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//允许访问IWDG相关寄存器
IWDG_SetPrescaler(IWDG_Prescaler_32); //32分频
IWDG_SetReload(LsiFreq/128); //设置看门狗喂狗时间为250ms,装载值=0.25/(LsiFreq/32)=LsiFreq/128
IWDG_Enable(); //打开IWDG
}/*************************************************************
Function : IWDGReset_Init
Description: 独立看门狗初始化
Input : none
return : none
*************************************************************/
void IWDGReset_Init(void)
{
IWDGReset_LSICalibration();//打开LSI,并校准LSI时钟

IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//允许访问IWDG相关寄存器
IWDG_SetPrescaler(IWDG_Prescaler_32);//32分频
IWDG_SetReload(LsiFreq/128);//设置看门狗喂狗时间为250ms,装载值=0.25/(LsiFreq/32)=LsiFreq/128
IWDG_Enable();//打开IWDG
}

这里先调用刚编写好的IWDGReset_LSICalibration()函数校准下LSI时钟,然后就可以开始配置看门狗了。调用库函数IWDG_WriteAccessCmd()让它允许范围IWDG的相关寄存器,再调用IWDG_SetPrescaler()设置32预分频,分频之后的频率为LsiFreq/32,再下去则要设置看门狗的超时时间了,调用IWDG_SetReload()函数来设置,看门狗的转载值设定(因为IWDG为12位计数器,所以最大的转载值为4095)可以使用公式:转载值=超时时间/(LsiFreq/32),上面代码中,我设定超时时间为250ms,所以要设定的看门狗转载值=0.25s/(LsiFreq/32)=LsiFreq/128。最后再打开独立看门狗。
接下去在编写IWDGReset.h的程序,程序非常简单,只是声明下独立看门狗的小初始化函数,代码如下:

#ifndef __IWDGRESET_H__
#define __IWDGRESET_H__
#include "stm32f10x.h"

void IWDGReset_Init(void);

#endif

 
3、stm32f10x_it.c的修改
需要在stm32f10x_it.c文件中添加TIM5的中断服务函数,代码如下:

u16 CaptureNumber = 0;
extern u32 LsiFreq;
/*************************************************************
Function : TIM5_IRQHandler
Description: TIM5中断服务程序
Input : none
return : none
*************************************************************/
void TIM5_IRQHandler(void)
{
static u16 capture = 0;
static u16 IC1ReadValue1 = 0, IC1ReadValue2 = 0;
if (TIM_GetITStatus(TIM5, TIM_IT_CC4) != RESET)
{
if(CaptureNumber == 0)//第一次捕获到上升沿
{
IC1ReadValue1 = TIM_GetCapture4(TIM5);//获取当前计数值
}
else if(CaptureNumber == 1)//第二次捕获到上升沿
{
IC1ReadValue2 = TIM_GetCapture4(TIM5);//获取当前计数值

if (IC1ReadValue2 > IC1ReadValue1)//没有超过最大计数值
{
capture = (IC1ReadValue2 - IC1ReadValue1);//计算两个上升沿之间的计数值
}
else//超过了最大计数值
{
capture = ((0xFFFF - IC1ReadValue1) + IC1ReadValue2);//计算两个上升沿之间的计数值
}
LsiFreq = (uint32_t) SystemCoreClock / capture;
LsiFreq *= 8;//计算LSI频率=72M/capture*8 (乘上8是因为TIM5的CH4 8预分频)
}
CaptureNumber++;//捕获上升沿次数自增

TIM_ClearITPendingBit(TIM5, TIM_IT_CC4);//清除标志位
}
}

在这段代码中,计算出了LSI的时钟频率,它的思路是这样的:通过计算两次上升沿之间计数值差,进而计算出LSI的频率。由于之前配置CH4为8分频,这里的第一次检测到上升沿实际上是检测到了LSI时钟的第8个上升沿;这里的第二次检测到上升沿实际上是检测到LSI时钟的第16个上升沿。然后保存这两次检测到上升沿之间的计数值,分别用变量IC1ReadValue1和IC1ReadValue2保存,接着计算他们之间的差值。这里有两种情况:一种是,IC1ReadValue1IC1ReadValue2,这说明计数值已经溢出一次了,所以要用((0xFFFF - IC1ReadValue1) + IC1ReadValue2);这个计算公式计算得到,并保存在capture中。得到计数值差值后,才能计算LSI频率。调用公式:LsiFreq=SystemCoreClock/capture=72M/capture,这里得到的LsiFreq是8个周期所对应频率,所以实际上LSI时钟频率LsiFreq还要乘于8,即LsiFreq *=8这才是LSI的真实频率。
 
4、main函数的编写
main函数的代码很简单,如下:

/*************************************************************
Function : main
Description: main入口
Input : none
return : none
*************************************************************/
int main(void)
{
BSP_Init();
PRINTF("\nmain() is running!\r\n");
IWDGReset_Init();
while(1)
{
LED1_Toggle(); //LED闪烁
Delay_ms(200); //延时大改250ms以上,就会看门狗复位
IWDG_ReloadCounter();//喂狗
}
}

调用IWDGReset_Init()初始化独立看门狗,然后在while(1)中每次延时200ms后就调用喂狗函数IWDG_ReloadCounter()来重新转载下看门狗的转载值。
 
5、测试
依上见面的mian函数代码,每次都及时喂狗,程序只会执行一次而一直不会复位,在串口调试软件输出的信息中可以看到,如下图所示:
STM32 独立看门狗定时器IWDG复位 - ziye334 - ziye334的博客
 在将main函数中的延时改成Delay_ms(300),这样的话,看门 狗复无法及时喂狗,到时一直复位,如下图所示:
STM32 独立看门狗定时器IWDG复位 - ziye334 - ziye334的博客
 
下面在做做其他实验,看不看CH4的预分频对LSI频率的影响。
将配置TIM5 CH4的代码中的CH4d的8预分频改成不分频,即改成:

TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;

同时在stm32f10x_it.c中,将LsiFreq *= 8;这就话屏蔽掉,然后编译下载,有如下现象:
STM32 独立看门狗定时器IWDG复位 - ziye334 - ziye334的博客
 可以发现修改后的LSI时钟频率为53097Hz,跟原先的43920Hz相差甚大。要问哪个准确,当然是43920Hz比较准确了,所以在编写程序的时候,最好要将TIM5的CH4进行8分频。

关键字:STM32  独立看门狗  定时器  IWDG复位 引用地址:STM32 独立看门狗定时器IWDG复位

上一篇:STM32窗口看门狗WWDG复位
下一篇:STM32 备份寄存器操作

推荐阅读最新更新时间:2024-03-16 15:14

基于STM32闭环张力控制系统设计
张力控制系统广泛应用于印刷等轻工业领域中,在收取和放卷材料时,为保证生产的质量及效率,保持恒定的张力是很重要的。在印刷过程中或者是印刷完成之后,最后的一道工序一般就是将加工物卷绕成筒状。在这一过程中,卷绕的好坏将是决定产品质量的关键,卷得太紧,容易使材料变形、拉断,卷得太松又容易使材料不紧凑,不利于搬运和运输,因而为了达到使卷绕紧凑,保证产品的质量,都要求在卷绕过程中,在材料上建立一定的张力,并保持张力为恒定值。有时恒定的张力值与材料卷绕的直径必须保持对应关系,因为不同材料的柔韧度也各不相同,而当以固定张力卷绕比较柔的材料时,内层材料就会被外层压至变形。为了避免这种情况的发生,系统需要测量出卷绕材料的直径,实时控制材料受到的张
[单片机]
基于<font color='red'>STM32</font>闭环张力控制系统设计
STM32通过FSMC读写FPGA
硬件平台:icore板(STM32F103VC + EP4C6E22C8) STM32F103VC是100管脚的,FSMC引脚定义: 地址仅有A19-23 A16-18 共8根地址线,数据线有16根,控制信号RD、WR、NE1 FPGA挂在BANK1的第一区(NE1,还可以有NE2、3、4) 这样可以在FPGA内定义8个寄存器(仅解析A16-18三根地址线) /*********************************************************** 据此定义如下STM32与FPGA间通信用的寄存器 ************************************************
[单片机]
STM32的入门总结和学习步骤
一、入门总结 1.1为什么要把时间花在“犹豫”上? 每当我们在入门之前(ARM是这样,DSP也一样),总会有很多疑问,会有很多顾虑。我们渴望知道学习STM32前景如何?需要啥基础?难不难?适不适合我?但是什么时候能心潮澎湃地、相当着急地开始学STM32?日子在一天一天过去!你开始行动了吗?没有行动的思索,永远都不可能入门!把这些时间用来看书吧,效果能好一万倍。 大家可能是从51单片机过来的,回想一下,我们之前学单片机时如何入门呢?实际上都是先看书(理论),再玩板子(实践)。严格地说,应该是模仿实验。熟悉之后才会自己写程序代码实现某个功能。因此,如果你正在咨询STM32;如果你正对STM32心潮澎湃;如果你想入门STM32;
[单片机]
<font color='red'>STM32</font>的入门总结和学习步骤
stm32 GPIO的8种工作模式
上图的最右端为I/O引脚,左端的器件位于芯片内部。I/O并联了两个用于保护的二极管。 注:部分图片内容来自《STM32库开发实战指南》
[单片机]
<font color='red'>stm32</font> GPIO的8种工作模式
初学者如何处理STM32创建工程时stm32_eval.h的问题
环境:win10-MDK:5.15-固件库:3.5.0 1.先说对初学者来讲的解决办法 删除main.c中的所有定义和函数。只写上main(){},其他的什么都不用加。并在最后另起一行。(不另起一行会提示“without a newline”的警告。)不知道和Linux里用GCC编译程序的no newline是不是一个原因。因为文件最后表示连接下一行,而如果文件最后一行行尾有,被包含的下一个源文件会被连接。但要是最后一行用的是空行,就可以避免这种情况了。 C99原文: Each instance of a backslash character ()immediately followed by a new-line
[单片机]
初学者如何处理<font color='red'>STM32</font>创建工程时stm32_eval.h的问题
STM32-自学笔记(2.ARMCortex-M3内核构架)
Cortex-M3 的CPU:32位CPU cpu的两种运行模式:线程模式(Thread)和处理模式(Handler)。 cpu不处理异常事件时,会运行在线程(Thread)模式下。而当cpu需要处理一个异常事件时,就会切换到处理(Handler)模式下。 此外 Cortex-M3的cpu还有两种处理代码的方式:私有模式和非私有模式。 私有模式下,cpu可以执行所有指令。 非私有模式下,部分指令是被禁止执行的(xPSR寄存器操作的MRS和MSR指令)。同时也不能对cpu的系统控制区中的寄存器进行进行操作。 另外,堆栈的使用也是可以设置的,主堆栈在线程模式和处理模式下都可以使用。通过设置,Handler模式也可以使用进程堆
[单片机]
STM32驱动MAX6675读取K型热电偶温度
MAX6675 进行热电偶冷端补偿和数字化 K 型热电偶信号。输出 12 位分辨率、 SPI 兼容、只读的数据。转换器的精度为 0.25℃,最高可读+1024℃,如果使用数据的 8LSB 则温度范围为 0℃到+700℃。 MAX6675模块的原理图: 从网上看到max6675模块并不便宜,正好手头又有MAX6675的芯片于是自己便根据原理图在洞洞板上搭建了一个测试模块 测试结果:将测得的温度信息通过串口1输出到上位机显示 max6675模块部分的测试代码: #include stm32f10x.h #include usart.h #include delay.h #include max6675.h
[单片机]
<font color='red'>STM32</font>驱动MAX6675读取K型热电偶温度
基于STM32的二维滑台不规则轨迹精密控制
在现代工业控制中步进电机的控制是滑台控制的执行机构。区别于其他控制电机的最大特点是,它是通过输入脉冲信号来进行控制的,即电机的总转动角度由输入脉冲数决定,而电机转速由脉冲信号的频率决定。 在很多情况下需要让步进电机控制滑台运动非常精确的距离,且运行轨迹是不规则的,运行时速度需可调。本文首先介绍系统的硬件电路原理;分析了控制滑台运行不规则轨迹的计算方法;在此基础上提出了用定时器中断的方法精确控制PWM数量;介绍了具体的软件实现方法并分析了系统测试结果。 1 系统硬件设计 本论文基于机车牵引梁数控磨削设备的电控设计,此设备用来磨削一个带弧线的六边形物体,因此要求设计两维滑台的电控部分,以精密控制磨削头的运行轨迹,经分析此轨迹呈不规则
[单片机]
基于<font color='red'>STM32</font>的二维滑台不规则轨迹精密控制
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved