 |
【程序運行效果】

|
 |
【程序】 #include <stm32f10x.h>
inline uint32_t _BV(uint8_t n) { return (1 << n); }
// 數碼管掃描類 class Scanner { private: static const uint8_t table[]; // 數碼管字形表 void input(uint8_t data); // 74HC595串行輸入 void output(void); // 74HC595並行輸出 public: Scanner(void); // 初始化GPIO口 void delay(void); void display(uint16_t num, uint8_t start = 0, uint8_t len = 3, bool dot = false); // 動態掃描數碼管, 顯示len位數字num, 個位位於start處的數碼管 void displayAt(uint8_t pos, uint8_t num, bool dot = false, bool delay = true); // 在指定數碼管上顯示指定數字 };
const uint8_t Scanner::table[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
Scanner::Scanner(void) { RCC->APB2ENR |= RCC_APB2ENR_IOPBEN; GPIOB->CRL = 0x30000000; // PB7~9設為輸出 GPIOB->CRH = 0x00000033; }
void Scanner::delay(void) { uint16_t i; for (i = 0; i < 20000; i++); }
void Scanner::input(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 Scanner::output(void) { GPIOB->BRR = GPIO_BRR_BR8; // RCLK=>PB8 GPIOB->BSRR = GPIO_BSRR_BS8; }
void Scanner::display(uint16_t num, uint8_t start, uint8_t len, bool dot) { // 掃描方向是從右到左 uint8_t i; for (i = 0; i < len; i++) { displayAt(start + i, num % 10, dot && i == 0); num /= 10; } }
void Scanner::displayAt(uint8_t pos, uint8_t num, bool dot, bool delay) { if (dot) input(table[num] & 0x7f); else input(table[num]); input(_BV(pos)); output(); if (delay) this->delay(); }
// 串口通信類 class CommPort : public Scanner { private: uint8_t num; uint8_t seconds; public: CommPort(void); void run(void); void sendString(const char *s); // 串口發送字符串 void setNum(uint8_t num); void timeUp(void); };
CommPort::CommPort(void) : num(0), seconds(0) { RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_USART1EN; GPIOA->CRH = 0x000008b0; // PA9(TX)設為復用50MHz推輓輸出, PA10(RX)設為輸入 GPIOA->BSRR = GPIO_BSRR_BS10; // PA10帶上拉輸入 // 波特率9600=72MHz/16x, x=468.75 // 468=0x1d4, 0.75=12/16, 12=0xc USART1->BRR = 0x1d4c; USART1->CR1 |= USART_CR1_UE | USART_CR1_RE | USART_CR1_TE | USART_CR1_RXNEIE; // 打開串口, 允許發送和接收, 開接收中斷 NVIC->ISER[USART1_IRQn / 32] |= _BV(USART1_IRQn % 32); // 配置定時器 RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; TIM1->ARR = 9999; TIM1->PSC = 7199; TIM1->DIER |= TIM_DIER_UIE; NVIC->ISER[TIM1_UP_IRQn / 32] |= _BV(TIM1_UP_IRQn % 32); // 開定時器溢出中斷 TIM1->CR1 |= TIM_CR1_URS; TIM1->EGR |= TIM_EGR_UG; TIM1->CR1 &= ~TIM_CR1_URS; TIM1->CR1 |= TIM_CR1_CEN; }
void CommPort::run(void) { sendString("\nHello World!\nTimer: "); while (1) { display(num); display(seconds, 6, 2, true); // 秒數(兩位) displayAt(5, TIM1->CNT % 10000 / 1000); // 毫秒數 } }
void CommPort::sendString(const char *s) { while (*s) { while ((USART1->SR & USART_SR_TC) == 0); USART1->DR = *s++; } }
void CommPort::setNum(uint8_t num) { this->num = num; }
void CommPort::timeUp(void) { seconds++; if (seconds >= 100) seconds = 0; USART1->DR = '0' + seconds % 10; }
CommPort *pCp; // 供中斷函數用的指針
int main(void) { CommPort cp; // 兩個類的構造函數都要執行 pCp = &cp; cp.run(); return 0; }
// 注意在C++程序中中斷函數要加前綴 extern "C" void TIM1_UP_IRQHandler(void) { // 定時器溢出中斷 TIM1->SR &= ~TIM_SR_UIF; pCp->timeUp(); }
extern "C" void USART1_IRQHandler(void) { // 串口接收中斷 if (USART1->SR & USART_SR_RXNE) pCp->setNum(USART1->DR); }
|
 |
本人在測試此程序時,為了方便起見,PA9,PA10上是接的藍牙串口模塊。

|
 |
不過呢,51單片機沒法用C++編寫程序。因為編譯的時候Keil uVision5直接就失去了響應: 
|