第四章Hanker TM4C123 外设应用
4.5 TM4C123 的看门狗
4.51 原理分析:
在实际的MCU 应用系统中,由于常常会受到来自外界的某些干扰,有可能(对规范的设计概率极小)造成程序的跑飞而陷入死循环,从而导致整个系统的陷入停滞状态并且不会自动恢复到可控的工作状态。所以出于对MCU 运行的安全考虑,便引入了一种专门的复位监控电路,俗称看门狗(WatchDog)。
看门狗电路所起的作用是一旦MCU 运行出现故障,就强制对MCU 进行硬件复位,使整个系统重新处于可控状态(要想精确恢复到故障之前的运行状态从技术上讲难度大成本高,而复位是最简单且可靠的处理手段)。
现在大部分MCU 都集成了看门狗的功能。在TM4C123 系列CORTEX M4 里集成有硬件的看门狗定时器模块。看门狗定时器在到达超时值时会产生不可屏蔽的中断或复位。当系统由于软件错误而无法响应或外部器件不能以期望的方式响应时,使用看门狗定时器可重新获得控制。
最实用的看门狗就是用在:当系统跑飞后,产生一个中断复位,使系统重新复位运行。为了防止在程序跑飞时意外修改看门狗模块的配置,特意引入了一个锁定寄存器。在配置看门狗定时器之后,只要写入锁定寄存器一个不是0x1ACCE551 的任何数值,看门狗模块的所有配置都会被锁定,拒绝软件修改。因此以后要修改看门狗模块的配置,包括清除中断状态(即喂狗操作),都必须要首先解锁。解锁方法是向锁定寄存器写入数值0x1ACCE551。这是个很特别的数字,程序跑飞本身已是罕见的事件,而在一旦发生此罕见事件的情况下又恰好会把这个特别的数字写入锁定寄存器更是不可能。因此可以保证中断复位的产生。
但是,正常情况下,程序跑飞是小概率事件,大家如果遇到程序跑飞的情况,应该首先考虑是否是软件编程错误或者硬件的设计错误,这才是跑飞情况下的大概率事件。
4.52 硬件设计:
如图所示:我们采用QF-TM4C123 开发板板上的1 个LED 作为实验用。
4.53 软件设计:.
软件设计时首先都是设置外设,看门狗设置需要实用下面几个语句,看门狗可以在第一次超时产生一个中断,第二次超时喂狗。当32 位计数器在使能后倒计数到0 状态时,看门狗定时器模块产生第一个超时信号,并产生中断触发信号。在发生了第一个超时事件后,32 位计数器自动重装并重新递减计数。如果没有清除第一个超时中断状态,则当计数器再次递减到0 时,且复位功能已使能,则看门狗定时器会向处理器发出复位信号。
我们下面来编写这样一个功能函数来验证看门狗的功效:
程序正常运行时,可以设置任何运行状态,比如串口输出,这里没有设置,并喂狗。当按键按下时,触发GPIO 按键中断,模拟出现故障,处理器进入死循环,看门狗定时器产生第一个超时信号,进入看门狗中断服务程序,LED2 不断闪烁,直到看门狗定时器产生第二次超时信号,导致系统复位,系统再次正常运行,正常任何恢复.
那么首先我们建立工程项目如下图所示:
其中lcd_320X240_ili932x.c 文件为液晶触摸屏的驱动文件,如果不使用液晶屏的话
就可以不加入,要使用的时候还必须结合图形驱动库文件一起使用。
Main 函数就是我们用户编写的代码,由于我们使用了库函数编写,所以要加入外设驱动库封装.lib 文件,这里面封装了所有的外设驱动,下面我们在下面文件夹找到
driverlib/watchdog.c 查找下面几个要使用的函数:
1.WatchdogEnable( )
功能
使能看门狗定时器
原型
- void WatchdogEnable(unsigned long ulBase)
复制代码参数
ulBase:看门狗定时器模块的基址,取值WATCHDOG_BASE
返回
无
2.WatchdogReloadSet( )
功能
设置看门狗定时器的重装值
原型
- void WatchdogReloadSet(unsigned long ulBase, unsigned long ulLoadVal)
复制代码参数
ulBase:看门狗定时器模块的基址,取值WATCHDOG_BASE
ulLoadVal:32 位装载值
返回
无
3.WatchdogIntEnable( )
功能
使能看门狗定时器中断
原型
- void WatchdogIntEnable(unsigned long ulBase)
复制代码参数
ulBase:看门狗定时器模块的基址,取值WATCHDOG_BASE
返回
无
4.WatchdogLock( )
功能
使能看门狗定时器的锁定机制
原型
- void WatchdogLock(unsigned long ulBase)
复制代码参数
ulBase:看门狗定时器模块的基址,取值WATCHDOG_BASE
返回
无
更多函数请查看外设驱动函数PDF
程序基本设置步骤可以归纳如下:
1. 使能看门狗中断
2.设置看门狗定时器的重载值
3.使能看门狗定时器的复位功能
4.使能看门狗定时器的中断
5.使能看门狗定时器的锁定机制
上面五步设置成功后就可以开始运行看门狗了。程序如下:
这里面需要详细介绍下:
- 01. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- 02. //-----------------------------------------------------------------------------
- 03. /
- 04. //-----------------------------------------------------------------------------
- 05. // 文件名: watchdog.c
- 06. // 作者: 青风
- 07. // ARM 内核: Cortex-M4
- 08. // 使用芯片: LM4F232H5QD
- 09. // 开发环境: KEIL
- 10. // 版本记录: V1.00 2012-1-26 14:30
- 11. // 功能说明:
- 12. //函数功能说明:
- 13. //-----------------------------------------------------------------------------
- 14. //*****************************************************************************
- 15. #include "inc/hw_types.h" //定义常用的宏
- 16. #include "inc/hw_memmap.h" //定义功能存储映射
- 17. #include "inc/hw_ints.h"
- 18. #include "grlib/grlib.h"
- 19. #include "driverlib/debug.h"
- 20. #include "drivers/lcd_320x240_ili932x.h"
- 21. #include "driverlib/sysctl.h"
- 22. #include "driverlib/gpio.h"
- 23. #include "driverlib/pin_map.h"
- 24. #include "driverlib/fpu.h"
- 25. #include "driverlib/interrupt.h" //定义中断分配数
- 26. #include "driverlib/systick.h"
- 27. #include "driverlib/watchdog.h"
- 28.
- 29. #define KEY GPIO_PIN_0 // 定义KEY PG0
- 30. #define LED2 GPIO_PIN_7 // 定义LED2 PC7
- 31. //-----------------------------------------------------------------------------
- 32. // 子函数功能说明: 使程序进入死循环
- 33. //-----------------------------------------------------------------------------
- 34. void INT_PortG(void)
- 35. {
- 36. while(1);
- 37. }
- 38. //-----------------------------------------------------------------------------
- 39. // 子函数功能说明: 简单的延时函数
- 40. //-----------------------------------------------------------------------------
- 41. void delay (unsigned long ulTime)
- 42. {
- 43. while (--ulTime != 0);
- 44. }
- 45. //-----------------------------------------------------------------------------
- 46. // 子函数功能说明: 反转LED 灯
- 47. //-----------------------------------------------------------------------------
- 48. void Watchdog_Timer (void)
- 49. {
- 50. while(1){
- 51. GPIOPinWrite(GPIO_PORTC_BASE,LED2,~GPIOPinRead(GPIO_PORTC_BASE,LED2));
- 52. delay(100000);
- 53. }
- 54. }
- 55. //-----------------------------------------------------------------------------
- 56. // 主函数
- 57. //-----------------------------------------------------------------------------
- 58. int main (void)
- 59. {
- 60. tContext sContext;
- 61. tRectangle sRect;
- 62. FPUEnable(); //FPU 使能
- 63. FPULazyStackingEnable(); //使能FPU 堆栈
- 64. SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_XTAL_16MHZ |
- 65. SYSCTL_OSC_MAIN); //系统时钟设置
- 66. lcd_ili932x_init(); //初始化LCD 驱动
- 67. GrContextInit(&sContext, &g_sLcdDisplay);//初始化图形库
- 68. lcd_backlight_on();
- 69. lcd_ili932x_flush(&sContext);
- 70. sRect.sXMin = 0;
- 71. sRect.sYMin = 0;
- 72. sRect.sXMax = GrContextDpyWidthGet(&sContext) - 1;
- 73. sRect.sYMax = 23;
- 74. GrContextForegroundSet(&sContext, ClrDarkBlue);
- 75. GrRectFill(&sContext, &sRect); // 填充蓝色方块
- 76. GrContextForegroundSet(&sContext, ClrWhite);
- 77. GrRectDraw(&sContext, &sRect); // 加白色框框
- 78. GrContextFontSet(&sContext, &g_sFontCm20);
- 79. GrStringDrawCentered(&sContext, "watchdog", -1,
- 80. GrContextDpyWidthGet(&sContext) / 2, 10, 0); // 显示KEY 中断实验标志
- 81. GrContextFontSet(&sContext, &g_sFontCm30);
- 82. GrStringDrawCentered(&sContext, "watchdog START!", -1,
- 83. GrContextDpyWidthGet(&sContext) / 2,
- 84. ((GrContextDpyHeightGet(&sContext) - 20) / 2),
- 85. 0);
- 86. // 显示提示实验开始
- 87. SysCtlPeripheralEnable(SYSCTL_PERIPH_WDOG); // 使能看门狗定时器
- 88. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG); // 使能GPIO G 口
- 89. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); // 使能GPIO C 口
- 90. GPIOPadConfigSet(GPIO_PORTG_BASE, KEY, GPIO_STRENGTH_2MA,
- GPIO_PIN_TYPE_STD_WPU);
- 91. GPIODirModeSet(GPIO_PORTG_BASE, KEY, GPIO_DIR_MODE_IN); /
- 92. / 设置连接KEY 为输入
- 93. GPIOPadConfigSet(GPIO_PORTC_BASE, LED2, GPIO_STRENGTH_2MA,
- 94. GPIO_PIN_TYPE_STD_WPU);
- 95. GPIODirModeSet(GPIO_PORTC_BASE, LED2, GPIO_DIR_MODE_OUT);
- 96. // 设置连接LED2 为输出
- 97. IntPrioritySet(INT_WATCHDOG,0x00); // 设置看门狗中断优先级为高
- 98. IntPrioritySet(INT_GPIOG,0x40); // 设置GPIO F 口的中断优先级为低
- 99. GPIOIntTypeSet(GPIO_PORTG_BASE, KEY, GPIO_LOW_LEVEL);
- 100. // 设置KEY 中断触发为IO 口下降沿触发发
- 101. GPIOPinIntEnable(GPIO_PORTG_BASE, KEY); //使能KEY 中断
- 102. IntEnable(INT_GPIOG); // 使能GPIO F 口中断
- 103. IntEnable(INT_WATCHDOG); // 使能看门狗中断
- 104. WatchdogReloadSet(WATCHDOG_BASE, 6000000);
- 105. // 设置看门狗定时器的重载值
- 106. WatchdogResetEnable(WATCHDOG_BASE);
- 107. // 使能看门狗定时器的复位功能
- 108. WatchdogEnable(WATCHDOG_BASE); // 使能看门狗定时器的中断
- 109. WatchdogLock(WATCHDOG_BASE);
- 110. // 使能看门狗定时器的锁定机制
- 111. while (1){
- 112. delay(500000); // 延时
- 113. WatchdogIntClear(WATCHDOG_BASE);//清除看门狗的中断标志、"喂狗"
- 114. }
- 115.
- 116.}
- 117.
复制代码本代码用了两个中断,一个是中断模拟故障,一个是看门狗中断,因此需要在startup.s 文件中进行声明:
下载成功后出现下面现象:当按键按下时,触发GPIO 按键中断,模拟出现故障,处理器进入死循环,看门狗定时器产生第一个超时信号,进入看门狗中断服务程序,LED2不断闪烁,直到看门狗定时器产生第二次超时信号,导致系统复位,系统再次正常运行,正常任何恢复