zoukankan      html  css  js  c++  java
  • 独立看门狗 IWDG

    一,独立看门狗

    二,独立看门狗的时钟源

    独立看门狗拥有自己的时钟源,不依赖PLL时钟输出的分频信号,能够独立运行,这样子的好处就是PLL假如受到干扰,

    导致运行异常,独立的看门狗还能正常地进行工作,如果没有正常的喂狗动作,就复位CPU。

    三、程序设计

    1.     添加复位检测代码,有助于观察当前工作的可靠性

     

       /* Check if the system has resumed from IWDG reset,检查当前复位是否有独立看门狗导致 */
             if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
             {
                       /* IWDGRST flag set */
                       printf("iwdt reset cpu
    ");
     
                       /* Clear reset flags */
                       RCC_ClearFlag();
             }
             else
             {
                       /* IWDGRST flag is not set */
                       printf("normal reset cpu
    ");
     
             }

    2.

    /* Enable write access to IWDG_PR and IWDG_RLR registers,独立看门狗是受到保护的,现在进行解锁动作 */
             IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
     
             /* IWDG counter clock: LSI/256 ,设置看门狗的时钟 = 32KHz / 256 =125Hz */
             IWDG_SetPrescaler(IWDG_Prescaler_256);
     
             /* 设置看门狗的超时时间,也就是设置它的计数值
             当前看门狗的时钟为125Hz,然后设置超时时间为1秒,那么重载值为125
             当前看门狗的时钟为125Hz,然后设置超时时间为2秒,那么重载值为250
             */   
             IWDG_SetReload(125);
     
             /* Reload IWDG counter,重载独立看门狗的计数值,说白了就是喂狗 */
             IWDG_ReloadCounter();
     
             /* Enable IWDG (the LSI oscillator will be enabled by hardware),使能独立看门狗 */
             IWDG_Enable();

     

    3.     喂狗技巧

    1.在裸机代码实现喂狗,放在定时器里面,因为定时器与看门狗是使用不同的时钟源,允许这么做!

    2.     如果有实时的操作系统的加持,可以在任务里面添加喂狗动作,如果操作系统崩溃了,能够检测到软件的错误,触发CPU的复位。

      

    在定时器中断服务函数当中,添加喂狗动作!

     

    #include "stm32f4xx.h"
    #include "stm32f4xx_gpio.h"
    #include "stm32f4xx_rcc.h"
    #include "stm32f4xx_usart.h"
    #include "stdio.h"
    
    static GPIO_InitTypeDef      GPIO_InitStructure;
    static USART_InitTypeDef     USART_InitStructure;
    static NVIC_InitTypeDef     NVIC_InitStructure;           
    
    void delay_us(uint32_t nus)
    {        
        uint32_t temp;             
        SysTick->LOAD =SystemCoreClock/8/1000000*nus;     //时间加载               
        SysTick->VAL  =0x00;                            //清空计数器
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;         //使能滴答定时器开始倒数      
        do
        {
            temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));            //等待时间到达   
        SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;         //关闭计数器
        SysTick->VAL =0X00;                               //清空计数器 
    }
    
    void delay_ms(uint16_t nms)
    {                     
        uint32_t temp;           
        SysTick->LOAD=SystemCoreClock/8/1000*nms;        //时间加载(SysTick->LOAD为24bit)
        SysTick->VAL =0x00;                               //清空计数器
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;        //能滴答定时器开始倒数 
        do
        {
            temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));            //等待时间到达   
        SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;        //关闭计数器
        SysTick->VAL =0X00;                               //清空计数器              
    } 
    
    void LED_Init(void)
    {         
      
        //使能GPIOE,GPIOF时钟
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE | RCC_AHB1Periph_GPIOF, ENABLE);            
    
        //GPIOF9,F10初始化设置 
        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9 | GPIO_Pin_10;        //LED0和LED1对应IO口
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;                    //普通输出模式,
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                    //推挽输出,驱动LED需要电流驱动
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;                //100MHz
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;                    //上拉
        GPIO_Init(GPIOF, &GPIO_InitStructure);                            //初始化GPIOF,把配置的数据写入寄存器                        
    
    
        //GPIOE13,PE14初始化设置 
        GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_13 | GPIO_Pin_14;        //LED2和LED3对应IO口
        GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_OUT;                    //普通输出模式
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                    //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;                //100MHz
        GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;                    //上拉
        GPIO_Init(GPIOE, &GPIO_InitStructure);                            //初始化GPIOE,把配置的数据写入寄存器
    
        GPIO_SetBits(GPIOF,GPIO_Pin_9  | GPIO_Pin_10);                    //GPIOF9,PF10设置高,灯灭
        GPIO_SetBits(GPIOE,GPIO_Pin_13 | GPIO_Pin_14);        
    }
    
    
    void USART1_Init(uint32_t baud)
    {
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);                             //使能GPIOA时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);                            //使能USART1时钟
     
        //串口1对应引脚复用映射
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);                         //GPIOA9复用为USART1
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);                         //GPIOA10复用为USART1
        
        //USART1端口配置
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;                         //GPIOA9与GPIOA10
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                                    //复用功能
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                //速度50MHz
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                                     //推挽复用输出
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                                     //上拉
        GPIO_Init(GPIOA,&GPIO_InitStructure);                                             //初始化PA9,PA10
    
        //USART1 初始化设置
        USART_InitStructure.USART_BaudRate = baud;                                        //波特率设置
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;                        //字长为8位数据格式
        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);                                         //初始化串口1
        
        USART_Cmd(USART1, ENABLE);                                                      //使能串口1 
        
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                    //开启相关中断
    
        //Usart1 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                                //串口1中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;                            //抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;                                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                    //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);                                                    //根据指定的参数初始化VIC寄存器
    }
    
    //重定义fputc
    int fputc(int ch,FILE *f)
    {
        USART_SendData(USART1,ch);
        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    
        return ch;
    }
    
    void usart1_send_bytes(uint8_t *pbuf,uint32_t len)
    {
        while(len--)
        {
            USART_SendData(USART1,*pbuf++);
            while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
        }
    }
    
    void usart1_send_str(char *pbuf)
    {
        while(pbuf && *pbuf)
        {
            USART_SendData(USART1,*pbuf++);
            while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
        }
    }
    
    int main(void)
    { 
     
        LED_Init();        
    
        //系统定时器初始化,时钟源来自HCLK,且进行8分频,
        //系统定时器时钟频率=168MHz/8=21MHz
        SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
            
        //设置中断优先级分组2
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
        
        //串口1,波特率115200bps,开启接收中断
        USART1_Init(115200);
        
        /* Check if the system has resumed from IWDG reset,检查当前复位是否有独立看门狗导致 */
        if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
        {
            /* IWDGRST flag set */
            printf("iwdt reset cpu
    ");
    
            /* Clear reset flags */
            RCC_ClearFlag();
        }
        else
        {
            /* IWDGRST flag is not set */
            printf("normal reset cpu
    ");
    
        }
        
            
    
        /* Enable write access to IWDG_PR and IWDG_RLR registers,独立看门狗是受到保护的,现在进行解锁动作 */
        IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    
        /* IWDG counter clock: LSI/256 ,设置看门狗的时钟 = 32KHz / 256 =125Hz */
        IWDG_SetPrescaler(IWDG_Prescaler_256);
    
        /* 设置看门狗的超时时间,也就是设置它的计数值
        当前看门狗的时钟为125Hz,然后设置超时时间为1秒,那么重载值为125
        当前看门狗的时钟为125Hz,然后设置超时时间为2秒,那么重载值为250
        */   
        IWDG_SetReload(125);
    
        /* Reload IWDG counter,重载独立看门狗的计数值,说白了就是喂狗 */
        IWDG_ReloadCounter();
    
        /* Enable IWDG (the LSI oscillator will be enabled by hardware),使能独立看门狗 */
        IWDG_Enable();
        
        while(1)
        {
            
            //重载计数值,就是喂狗,就是不让计数值变为0
            IWDG_ReloadCounter();  
    
        }
    }
    
    
    void USART1_IRQHandler(void)                                //串口1中断服务程序
    {
        uint8_t d;
    
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)      //接收中断
        {
            //接收数据
            d = USART_ReceiveData(USART1);                        
            
            //发送数据
            usart1_send_bytes(&d,1);
                 
        } 
    
    } 

    ---恢复内容结束---

  • 相关阅读:
    归并排序(Merge Sort)
    AtCoder AGC035D Add and Remove (状压DP)
    AtCoder AGC034D Manhattan Max Matching (费用流)
    AtCoder AGC033F Adding Edges (图论)
    AtCoder AGC031F Walk on Graph (图论、数论)
    AtCoder AGC031E Snuke the Phantom Thief (费用流)
    AtCoder AGC029F Construction of a Tree (二分图匹配)
    AtCoder AGC029E Wandering TKHS
    AtCoder AGC039F Min Product Sum (容斥原理、组合计数、DP)
    AtCoder AGC035E Develop (DP、图论、计数)
  • 原文地址:https://www.cnblogs.com/xiangtingshen/p/10963552.html
Copyright © 2011-2022 走看看