| 
            
            
             
              #include <stm32f10x.h>
  uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e}; uint16_t num = 0; uint8_t value = 0;
  void delay(void) {     uint16_t i;     for (i = 0; i < 20000; i++); }
  void ser_in(uint8_t data) {     uint8_t i;     for (i = 0; i < 8; i++)     {         GPIOB->BRR = GPIO_BRR_BR9; // SCLK=PB9         if (data & 0x80)             GPIOB->BSRR = GPIO_BSRR_BS7; // DIO=PB7         else             GPIOB->BRR = GPIO_BRR_BR7;         data <<= 1;         GPIOB->BSRR = GPIO_BSRR_BS9;     } }
  void par_out(void) {     GPIOB->BRR = GPIO_BRR_BR8; // RCLK=PB8     GPIOB->BSRR = GPIO_BSRR_BS8; }
  void seg_scan(void) {     uint8_t i;     uint16_t numbuf = num;     for (i = 0; i <= 4; i++)     {         ser_in(seg8[numbuf % 10]);         ser_in(1 << i);         par_out();         delay();         numbuf /= 10;     }          numbuf = value;     for (i = 6; i <= 7; i++)     {         ser_in(seg8[numbuf % 10]);         ser_in(1 << i);         par_out();         delay();         numbuf /= 10;     } }
  int main(void) {     RCC->APB1ENR = RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;     PWR->CR |= PWR_CR_DBP; // 允许写入后备寄存器          // 上电复位: PORRSTF=PINRSTF=1     // 复位键复位: PINRSTF=1     if (RCC->CSR & RCC_CSR_PORRSTF)         num = 1970; // 通电时写入初值     else         num = BKP->DR1; // 复位时读取寄存器值     if (RCC->CSR & RCC_CSR_PINRSTF)         BKP->DR1 = num + 1; // 每次复位都把寄存器的值加1     if (RCC->CSR & RCC_CSR_WWDGRSTF)         BKP->DR1 = num - 1; // 如果是看门狗复位则减去1     RCC->CSR |= RCC_CSR_RMVF; // 清除复位标志信息          /* 配置GPIO口*/     RCC->APB2ENR = RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN;     GPIOB->CRL = 0x30000000;     GPIOB->CRH = 0x00000033;     GPIOC->CRL = 0x00000080; // PC1设为带电阻输入     GPIOC->BSRR = GPIO_BSRR_BS1; // PC1带上拉电阻输入          /* 配置WWDG */     RCC->APB1ENR |= RCC_APB1ENR_WWDGEN; // 开WWDG时钟, 随后WWDG进入free-running(空转)状态     //WWDG->CFR |= WWDG_CFR_EWI | WWDG_CFR_WDGTB; // WDGTB=11, 8分频     WWDG->CFR = WWDG_CFR_EWI | WWDG_CFR_WDGTB | WWDG_CFR_W6 | 20; // T[5:0]降到20后才准喂狗     NVIC_EnableIRQ(WWDG_IRQn); // 开EWI中断     while ((WWDG->CR & WWDG_CR_T) > (WWDG_CFR_W6 | 20)); // 等待正在空转的WWDG离开窗口区, 进入允许喂狗的区间(T<0x40时喂狗不会触发EWI中断), 防止value变量被置成1     WWDG->CR = WWDG_CR_WDGA | WWDG_CR_T6 | 35; // T6恒为1, T[5:0]的范围: 35~0, 喂狗时间: 32.768ms, WDGA=1启动看门狗     // 只有当T[5:0]在20~0时才允许喂狗          while (1)     {         seg_scan(); // 在WWDG允许的时间内只能执行一次, 否则会超时         if (GPIOC->IDR & GPIO_IDR_IDR1) // 如果PC1键按住不放(低电平), 则不喂狗             WWDG->CR = WWDG_CR_WDGA | WWDG_CR_T6 | 35; // T[5:0]=35     } }
  // 当T=0x40(即T[5:0]=0)时触发此中断, 离复位还有最后910us的时间 // 此时T6仍为1, 只要及时喂狗仍可视为正常工作而无需复位 void WWDG_IRQHandler(void) {     WWDG->SR &= ~WWDG_SR_EWIF;     value = (value + 1) % 100;     //WWDG->CR = WWDG_CR_WDGA | WWDG_CR_T6 | 35; // 在中断中阻止Reset          // 该中断必须在T从0x40跳变到0x39期间的910us之内完成     // 否则将无法执行完毕而提前触发Reset }              
                       |