#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
}