【不使用自定义的_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;
}