| 
            
            
             
              #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;
  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;     } }
  void seg_off(void) {     ser_in(0xff);     ser_in(0x00);     par_out(); }
  int main(void) {     uint8_t i;     RCC->APB1ENR = RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN;     PWR->CR |= PWR_CR_DBP; // 允许写入后备寄存器          // 上电复位: PORRSTF=PINRSTF=1     // 复位键复位: PINRSTF=1     if (RCC->CSR & RCC_CSR_PORRSTF)         BKP->DR1 = num = 1970; // 通电时写入初值     else         num = BKP->DR1; // 复位时读取寄存器值     if (RCC->CSR & RCC_CSR_IWDGRSTF)         BKP->DR1 = --num; // 如果是看门狗复位, 则减去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, PC13设为带电阻输入     GPIOC->CRH = 0x00800000;     GPIOC->BSRR = GPIO_BSRR_BS1 | GPIO_BSRR_BS13; // PC1, PC13带上拉电阻输入          // 普通睡眠模式下可以用定时器中断来喂狗     // 停止模式和待机模式下只能通过RTC闹钟中断来喂狗, 因为定时器在这两个模式下不可用     RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;     TIM6->ARR = 9499; // 0.95s喂一次狗     TIM6->PSC = 7199;     TIM6->DIER = TIM_DIER_UIE;     TIM6->CR1 = TIM_CR1_URS;     TIM6->EGR = TIM_EGR_UG;     NVIC_EnableIRQ(TIM6_IRQn);     // 对于待机模式, 反正唤醒后RAM数据要丢失     // 不如在待机之前先通过软件将系统复位一次, 将看门狗关闭     // 复位后判断是否待机的标志可以保存在备用寄存器里面          // 配置外部中断     RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;     AFIO->EXTICR[0] = AFIO_EXTICR1_EXTI1_PC;     AFIO->EXTICR[3] = AFIO_EXTICR4_EXTI13_PC;     EXTI->IMR |= EXTI_IMR_MR1 | EXTI_IMR_MR13;     EXTI->FTSR |= EXTI_FTSR_TR1 | EXTI_FTSR_TR13;     NVIC_EnableIRQ(EXTI1_IRQn);     NVIC_EnableIRQ(EXTI15_10_IRQn);          // 配置独立看门狗     IWDG->KR = 0x5555; // 开始配置     IWDG->PR = 3; // 32分频, f=40kHz/32=1250Hz->0.8ms     IWDG->RLR = 1250; // 定时时间: 1250*0.8ms=1s, 1250=0x4e2     // 写入后不需要等待PVU, RVU标志位清零     IWDG->KR = 0xcccc; // 启动看门狗     IWDG->KR = 0xaaaa; // 导入上述配置          while (1)     {         for (i = 0; i < 20; i++)             seg_scan();                  IWDG->KR = 0xaaaa; // 非睡眠模式时在这里喂狗     } }
  // 按键PC1: 进入睡眠模式 void EXTI1_IRQHandler(void) {     EXTI->PR |= EXTI_PR_PR1;     seg_off(); // 熄灭数码管     TIM6->CR1 |= TIM_CR1_CEN; // 开定时器6     IWDG->KR = 0xaaaa; // 先喂一次狗     SCB->SCR |= SCB_SCR_SLEEPONEXIT; // 退出中断时自动执行_WFI() }
  // 按键PC13: 退出睡眠模式 void EXTI15_10_IRQHandler(void) {     EXTI->PR |= EXTI_PR_PR13;     TIM6->CR1 &= ~TIM_CR1_CEN; // 关定时器6, 停止用中断喂狗     SCB->SCR &= ~SCB_SCR_SLEEPONEXIT; // 退出这个中断时不进入睡眠模式 }
  // 睡眠模式时用于喂狗的中断 void TIM6_IRQHandler(void) {     TIM6->SR &= ~TIM_SR_UIF;     IWDG->KR = 0xaaaa;     // 由于SLEEPONEXIT=1, 因此退出这个中断函数时仍会自动进入睡眠模式 }              
                       |