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