STM32窗口看门狗使用?(WWDG) 上午搞定RTC之后,开始弄IWDG和WWDG,IWDG比较容易,配置也很简单,参考ST的代码就能很快搞定.但是WWDG就不行了,搞了很久都不行,按ST的库做,在keil上仿真也不行,主要原因就是WWDG->CR寄存器中的计数值不会减少! 其他配置也都正确了,WWDG->CR就是不减少,我不知道是不是PCLK1的时钟没有,但是从keil的仿真可以看到PCLK1的时钟是36M,没道理没有,很是郁闷,不知道哪位朋友用过STM32的WWDG没有?请指教! 多谢先. 我用的是STM32F103RBT6. 主函数: #include "stm32f10x_lib.h" #include "sys.h" #include "led.h" #include "delay.h" #include "wwdg.h" int main(void)//GPIO { //u32 temp; Stm32_Clock_Init();//系统时钟设置 led_init(); //DBGMCU->CR=0X00000000; delay_init(72);//72M系统时钟 //delay_ms(300); wwdg_init(); //配置并使能IWDG //temp=DBGMCU->CR; while (1) { LED0_SET(0); //WWDG->CR&=~(1<<6); delay_us(500000);//在这里系统重启 } } wwdg.h代码: #ifndef __WWDG_H #define __WWDG_H //看门狗定时器中断配置 void NVIC_WWDGConfiguration(void) { NVIC_InitTypeDef NVIC_InitStructure; #ifdef VECT_TAB_RAM NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); #else /* VECT_TAB_FLASH */ NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); #endif NVIC_InitStructure.NVIC_IRQChannel =WWDG_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 1; NVIC_Init(&NVIC_InitStructure); } void wwdg_init(void) { NVIC_WWDGConfiguration(); RCC->APB1ENR|=1<<11; //窗口看门狗时钟使能. WWDG->CFR|=1<<8; //CLKww=PCLK1/4096/8=244Hz WWDG->CFR|=1<<7; WWDG->CFR&=0X380; WWDG->CFR|=65; //窗口值设置为65 WWDG->CR=0X7F; //计数值设定为0X7F WWDG->CR|=1<<7; //开启看门狗 WWDG->SR&=0XFFFFFFFE;//清除EWIF位 WWDG->CFR|=1<<9; //提前唤醒中断 } //串口看门狗中断 void WWDG_IRQHandler(void) { WWDG_SetCounter(0x7F); WWDG_ClearFlag(); } #endif sys.h中的代码: #ifndef __SYS_H #define __SYS_H #include "stm32f10x_lib.h" //系统时钟初始化 //使用外部8M晶振,PLL到72M频率 //正点原子@SCUT //2008/12/04 #define uint unsigned int #define uchar unsigned char /* #define CLOCK 72/8 //时钟=72M //us延时函数 void delay_us(unsigned int us) { u8n; while(us--)for(n=0;n<CLOCK;n++); } //ms延时函数 void delay_ms(unsigned int ms) { while(ms--)delay_us(1000); } */ //把所有时钟寄存器复位 void RCC_RESETInit(void) { RCC->APB2RSTR = 0XFFFFFFFF;//外设复位 RCC->APB1RSTR = 0XFFFFFFFF; RCC->APB2RSTR = 0X00000000;//复位恢复 RCC->APB1RSTR = 0X00000000; RCC->AHBENR = 0x00000014; //flash时钟,闪存时钟使能.DMA时钟关闭 RCC->APB2ENR = 0x00000000; //外设时钟关闭. RCC->APB1ENR = 0x00000000; RCC->CR |= 0x00000001; //使能内部高速时钟HSION RCC->CFGR &= 0xF8FF0000; //复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0] RCC->CR &= 0xFEF6FFFF; //复位HSEON,CSSON,PLLON RCC->CR &= 0xFFFBFFFF; //复位HSEBYP RCC->CFGR &= 0xFF80FFFF; //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE RCC->CIR = 0x00000000; //关闭所有中断 } //外部8M,则得到72M的系统时钟 void Stm32_Clock_Init(void) { unsigned char temp="0"; u8timeout="0"; RCC_RESETInit(); RCC->CR|=0x00010000; //外部高速时钟使能HSEON timeout=0; while(!(RCC->CR>>17)&&timeout<200)timeout++;//等待外部时钟就绪 //0-24M等待0;24-48M 等待1;48-72M等待2;(非常重要!) FLASH->ACR|=0x32;//FLASH 2个延时周期 RCC->CFGR|=0X001D2400;//APB1/2=DIV2;AHB=DIV1;PLL=9*CLK;HSE作为PLL时钟源 RCC->CR|=0x01000000; //PLLON timeout=0; while(!(RCC->CR>>25)&&timeout<200)timeout++;//等待PLL锁定 RCC->CFGR|=0x00000002;//PLL作为系统时钟 while(temp!=0x02&&timeout<200) //等待PLL作为系统时钟设置成功 { temp=RCC->CFGR>>2; timeout++; temp&=0x03; } } #endif delay.h中的代码: #ifndef __DELAY_H #define __DELAY_H //使用SysTick的普通计数模式对延迟进行管理 //包括delay_us,delay_ms //正点原子@SCUT //2008/12/13 static u8 fac_us=0;//us延时倍乘数 static u16 fac_ms=0;//ms延时倍乘数 //初始化延迟函数 void delay_init(u8 SYSCLK) { SysTick->CTRL&=0xfffffffb;//选择内部时钟 HCLK/8 fac_us=SYSCLK/8; fac_ms=(u16)fac_us*1000; } //延时Nms //注意Nms的范围 //Nms<=0xffffff*8/SYSCLK //对72M条件下,Nms<=1864 void delay_ms(u16 nms) { SysTick->LOAD=(u32)nms*fac_ms; //时间加载 SysTick->CTRL|=0x01; //开始倒数 while(!(SysTick->CTRL&(1<<16))); //等待时间到达 SysTick->CTRL&=0XFFFFFFFE; //关闭计数器 SysTick->VAL=0X00000000; //清空计数器 } //延时us void delay_us(u32 Nus) { SysTick->LOAD=Nus*fac_us; //时间加载 SysTick->CTRL|=0x01; //开始倒数 while(!(SysTick->CTRL&(1<<16)));//等待时间到达 SysTick->CTRL=0X00000000; //关闭计数器 SysTick->VAL=0X00000000; //清空计数器 } #endif WWDG了解及疑惑 void, 时钟 本帖最后由 冬夜冰城 于 2011-2-13 21:00 编辑 一、主函数: int main(void) { #ifdef DEBUG debug(); #endif //配置系统时钟 RCC_Configuration(); GPIO_Configuration(); EXTI_Configuration(); NVIC_Configuration(); if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET) { GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_SET); /*可以清除的复位标志位有: RCC_FLAG_PINRST, RCC_FLAG_PORRST, RCC_FLAG_SFTRST, RCC_FLAG_IWDGRST, RCC_FLAG_WWDGRST, RCC_FLAG_LPWRRST */ RCC_ClearFlag(); } else { GPIO_WriteBit(GPIOB,GPIO_Pin_15,Bit_RESET); } WWDG_Configuration(); /*Infinite loop */ while (1); } 二、窗口看门狗初始化函数 void WWDG_Configuration(void) { /* 开启窗口看门狗时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); // /* Deinitialize the WWDG registers将外设 WWDG寄存器重设为缺省值 */ // 从其底层函数可以看出,初始化关闭窗口看门狗时钟 // WWDG_DeInit(); /*Set WWDG prescaler to 8 设置 WWDG 预分频值即PCLK1/4096/8=1098.6 */ WWDG_SetPrescaler(WWDG_Prescaler_8); /*Set WWDG window value to 0x41指定的窗口值,该参数取值必须在0x40 与 0x7F之间。 */ WWDG_SetWindowValue(0x41); /*Enable WWDG and set counter value to 0x7F 使能窗口看门狗,并把看门狗计数器的值设为0x7f*/ WWDG_Enable(0x7f); /*Clear EWI flag 清除早期唤醒中断标志位 */ WWDG_ClearFlag(); /*Enable WWDG Early wakeup interrupt 使能 WWDG 早期唤醒中断(EWI) */ WWDG_EnableIT(); } 三、中断处理函数 void WWDG_IRQHandler(void) { /*Set WWDG counter value to 0x70 设置计数器值为0x7f*/ WWDG_SetCounter(0x7f); /* Clear EWI flag清除早期唤醒中断标志位 */ WWDG_ClearFlag(); /*闪烁PB14*/ GPIO_WriteBit(GPIOB,GPIO_Pin_14,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_14))); } 四、外中断设置函数等省略 五、问题及解决 1.遇到问题为 当复位后存在标志位使PB15点亮,点亮后清除标志位但标志位一直存在2. 为什么开启窗口看门狗时钟,再关闭时看门狗还正常运行 即先写: RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); 后写: WWDG_DeInit();(其底层函数为 RCC_APB1PeriphResetCmd(RCC_APB1Periph_WWDG,ENABLE); RCC_APB1PeriphResetCmd(RCC_APB1Periph_WWDG, DISABLE);) 解决:把 WWDG_Enable(0x7f); WWDG_ClearFlag(); WWDG_EnableIT();顺序写反了。
|