【不使用自定義的_BV宏,而是直接寫出各設置位名稱的程序】
#include <stm32f10x.h>
uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
uint8_t num = 0;
void delay(void)
{
    uint32_t i;
    for (i = 0; i < 20000; i++);
}
void SerIn(uint8_t data)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        GPIOC->BRR = GPIO_BRR_BR15;
        if (data & 0x80)
            GPIOA->BSRR = GPIO_BSRR_BS0;
        else
            GPIOA->BRR = GPIO_BRR_BR0;
        GPIOC->BSRR = GPIO_BSRR_BS15; // BS15=BitSet15是設為高電平, BR15=BitReset15是設為低電平, 注意區分!
        data <<= 1;
    }
}
void ParOut(void)
{
    GPIOC->BRR = GPIO_BRR_BR14;
    GPIOC->BSRR = GPIO_BSRR_BS14;
}
int main(void)
{
    // 開啟PA、PC和TIM1時鐘
    RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN | RCC_APB2ENR_TIM1EN;    
    // 每一位十六進制數代表一個端口
    // 詳情請參閱: 
https://zh.arslanbar.net/post.php?t=24435    // CNF=00: push-pull, MODE=11: 50MHz
    GPIOA->CRL = 0x00000003; // PA0設為輸出
    GPIOC->CRH = 0x33000000; // PC14~15設為輸出
    TIM1->ARR = 65535; // 計數量 (auto-reload register, 16位)
    TIM1->PSC = 999; // 1000分頻 (prescaler, 16位)
    TIM1->DIER = TIM_DIER_UIE; // 允許定時器1中斷產生
    NVIC->ISER[0] = NVIC_ISER_SETENA_25; // 允許執行定時器1中斷服務函數, 編號為25    
    // 刷新寄存器
    TIM1->CR1 |= TIM_CR1_URS; // URS=1(防止UIF置位並產生中斷)
    TIM1->EGR |= TIM_EGR_UG; // UG=1(產生一個寄存器更新事件)
    TIM1->CR1 &= ~TIM_CR1_URS; // URS=0    
    TIM1->CR1 |= TIM_CR1_CEN; // CEN=1(開啟定時器1)    
    // 數碼管藉助74HC595晶片進行動態掃描
    while (1)
    {
        SerIn(seg8[num % 10]);
        SerIn(GPIO_BSRR_BS0);
        ParOut();
        delay();        
        SerIn(seg8[num % 100 / 10]);
        SerIn(GPIO_BSRR_BS1);
        ParOut();
        delay();
    }
}
// 定時器中斷函數
void TIM1_UP_IRQHandler(void)
{
    TIM1->SR &= ~TIM_SR_UIF; // UIF=0
    num++;
    if (num >= 100)
        num = 0;
}