#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, 因此退出這個中斷函數時仍會自動進入睡眠模式 }
|