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