完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
以单片机为核心的微型计算机系统中,单片机经常会受到来自外界电磁场的干扰。
造成程序跑飞,只是程序的正常运行状态被打断而进入死循环,从而使单片机控制的系统无法正常工作。看门狗就是一种专门用于检测单片机程序运行状态的硬件结构。 stm32也是如此。 stm32 的独立看门狗由内部专门的40Khz低速时钟驱动,即使主时钟发生故障时,它也仍然有效。这里需要注意的是独立看门狗的时钟是一个内部时钟,所以不是准确的40Khz,而是在30~60Khz之间的一个可变化的时钟,看门狗的时钟对时间的要求不是很精确,所以时钟有偏差可以接受。 本例直接操作寄存器实现验证独立看门狗的复位功能,设定一个800ms的喂狗时间,在主函数中实现LED闪烁,如果设定一个1s的延时,则触发独立看门狗复位,LED常亮。 库函数实现当外部中断发生(按下PA0按键),长时间不喂狗,引发独立看门狗复位时,向外用串口输出复位提示。 直接操作寄存器 使用独立看门狗,需要了解一下寄存器: 键值寄存器:(IWDG_KR) 低16位有效的寄存器,只写寄存器,读出值恒为0x0000. 软件必须以一定的间隔写入0xAAAA,否则,当计数器为0时,看门狗会产生复位。 写入0x5555表示允许访问IWDG_PR和IWDG_RLR寄存器。 写入0xCCCC,启动看门狗工作。 预分频寄存器:(IWDG_PR) 第三位有效寄存器,用于设置看门狗的分频系数,最低为4,最高位256. 通过设置PR[2:0]:位来选择计数器时钟的预分频因子。要改变预分频因子,IWDG_SR寄存器的PVU位必须为0。 000: 预分频因子=4 100: 预分频因子=64 001: 预分频因子=8 101: 预分频因子=128 010: 预分频因子=16 110: 预分频因子=256 011: 预分频因子=32 111: 预分频因子=256 重装载寄存器:(IWDG_RLR) 低12位有效,RL[11:0]。用于定义看门狗计数器的重装载值。 每当向IWDG_KR寄存器写入0xAAAA时,重装载值会被传送到计数器中。随后计数器从这个值开始递减计数。看门狗超时周期可通过此重装载值和时钟预分频值来计算。 只有当IWDG_SR寄存器中的RVU位为0时,才能对此寄存器进行修改。 状态寄存器:(IWDG_SR) 只有低两位有效。都由硬件置’1’和 清’0’。 RVU[1]: 看门狗计数器重装载值更新 PVU[0]: 看门狗预分频值更新 代码如下: User/main.c #include 《stm32f10x_lib.h》 #include “system.h” #include “wdg.h” #define LED1 PAout(4)#define LED2 PAout(5)void Gpio_Init(void);int main(void){ Rcc_Init(9); //系统时钟设置 Gpio_Init(); Iwdg_Init(3,1000); //设定为800ms内喂狗 while(1){ LED1 = !LED1; delay(100000); //延时100ms后喂狗,LED闪烁 //delay(1000000); //延时1000ms,引发独立看门狗复位,LED不闪烁 Iwdg_Feed(); //喂狗 } }void Gpio_Init(void){ RCC-》APB2ENR|=1《《2; //使能PORTA时钟 GPIOA-》CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出 GPIOA-》CRL|=0x33334444; } Library/wdg.c (此文件包含了独立看门狗和窗口看门狗的驱动函数) #include 《stm32f10x_lib.h》#include “wdg.h”/******************************************** * *本文件包含窗口看门狗和独立看门口的相关函数 * *********************************************/u8 Wwdg_Cnt = 0x7F; //计数器值,默认为最大值127//独立看门狗初始化//参数说明:// pre:分频数(0~7),相应分频因子为4*(2^pre)// rlr:低12位有[11:0]// 喂狗时间计算: T = (4*(2^pre)*rlr)/40;(ms) void Iwdg_Init(u8 pre,u16 rlr){ IWDG -》KR = 0x5555; //使能对PR RLR寄存器的写操作 IWDG -》PR = pre; //设置分频数 IWDG -》RLR = rlr; //设定重装值 IWDG -》KR = 0xAAAA; //装载RLR值到看门狗计数器,即喂狗 IWDG -》KR = 0xCCCC; //启动看门狗}//独立看门狗喂狗void Iwdg_Feed(){ IWDG -》 KR = 0xAAAA; //喂狗}//窗口看门狗初始化//参数说明: // cnt 计数器的值,最大 127,0x7F// w_cnt 窗口值,最大 127,0x7F// pre 预分频器的时基值,低两位有效;实际时钟为: PLCK1/4096/2^pre//需要再主函数中开启中断 WWDG_IRQChannel//设定喂狗时间范围必须在:(WWDG时钟为PCLK1,36Mhz)// Tmax =(4096*2^pre*(cnt-63)/36) (us)// Tmin =(4096*2^pre*(cnt-w_cnt)/36) (us)//超出次时间喂狗复位void Wwdg_Init(u8 cnt,u8 w_cnt,u8 pre){ u8 Cnt_Max = 0x7f; //计数器最大值 Wwdg_Cnt = Cnt_Max&cnt; //设定计数器的值,防止溢出 RCC-》APB1ENR |= 1《《11; WWDG -》 CFR |= pre 《《7; //设定预分频器的时基,实际分频值我 WWDG -》 CFR |= 1《《9; //使能中断 WWDG -》 CFR &= 0xFF80; //初始化低七位,即窗口值清0 WWDG -》 CFR |= w_cnt; // 设定窗口值 WWDG -》 CR |= Wwdg_Cnt|(1《《7); //设定计数器值,并激活开门狗}//窗口看门狗喂狗void Wwdg_Feed(){ WWDG-》CR |= (Wwdg_Cnt&0x7F); } Library/wdg.h #include 《stm32f10x_lib.h》void Iwdg_Init(u8 pre,u16 rlr);void Iwdg_Feed(void);void Wwdg_Init(u8 cnt,u8 w_cnt,u8);void Wwdg_Feed(void); 需要注意的是 独立看门狗没有响应的中断。 库函数操作 main.c #include “stm32f10x.h”#include “stdio.h”#define PRINTF_ON 1void RCC_Configuration(void);void GPIO_Configuration(void);void NVIC_Configuration(void);void USART_Configuration(void);void IWDG_Configuration(void);void EXTI_Configuration(void);vu32 DelayTime;int main(void){ RCC_Configuration(); GPIO_Configuration(); NVIC_Configuration(); USART_Configuration(); EXTI_Configuration(); IWDG_Configuration(); while(1){ if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) == SET) { printf(“rn The Stm32 has been reset by IWDG 。rn”); RCC_ClearFlag(); } //do sth. here DelayTime = 100000; while(--DelayTime); // 延时17ms IWDG_ReloadCounter(); //80ms不喂狗复位 GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(1- GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4))); } }void EXTI_Configuration(void){ EXTI_InitTypeDef EXTI_InitStructure; EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);}void GPIO_Configuration(void){ GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOA , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA , &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA , &GPIO_InitStructure); }void IWDG_Configuration(void){ RCC_LSICmd(ENABLE); //打开LSI while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==RESET); IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); IWDG_SetPrescaler(IWDG_Prescaler_32); IWDG_SetReload(100); //80ms ,max 0xFFF 0~4095 IWDG_ReloadCounter(); IWDG_Enable();}void RCC_Configuration(void){ /* 定义枚举类型变量 HSEStartUpStatus */ ErrorStatus HSEStartUpStatus; /* 复位系统时钟设置*/ RCC_DeInit(); /* 开启HSE*/ RCC_HSEConfig(RCC_HSE_ON); /* 等待HSE起振并稳定*/ HSEStartUpStatus = RCC_WaitForHSEStartUp(); /* 判断HSE起是否振成功,是则进入if()内部 */ if(HSEStartUpStatus == SUCCESS) { /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */ RCC_HCLKConfig(RCC_SYSCLK_Div1); /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */ RCC_PCLK2Config(RCC_HCLK_Div1); /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */ RCC_PCLK1Config(RCC_HCLK_Div2); /* 设置FLASH延时周期数为2 */ FLASH_SetLatency(FLASH_Latency_2); /* 使能FLASH预取缓存 */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* 使能PLL */ RCC_PLLCmd(ENABLE); /* 等待PLL输出稳定 */ while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); /* 选择SYSCLK时钟源为PLL */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* 等待PLL成为SYSCLK时钟源 */ while(RCC_GetSYSCLKSource() != 0x08); } /* 打开APB2总线上的GPIOA时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE); //RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP|RCC_APB1Periph_WWDG, ENABLE); } void USART_Configuration(void){ USART_InitTypeDef USART_InitStructure; USART_ClockInitTypeDef USART_ClockInitStructure; USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge; USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; USART_ClockInit(USART1 , &USART_ClockInitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; USART_Init(USART1,&USART_InitStructure); USART_Cmd(USART1,ENABLE);}void NVIC_Configuration(void){ NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}#if PRINTF_ONint fputc(int ch,FILE *f){ USART_SendData(USART1,(u8) ch); while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET); return ch;}#endif |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1777 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1080 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1678 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
595浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
554浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 11:54 , Processed in 0.649091 second(s), Total 46, Slave 39 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号