|
【程序】STM32定時器1對外部輸入信號(PA9下降沿)進行計數,帶消抖 |
一派掌门 二十级 |
#include <stm32f10x.h>
#define _BV(n) (1 << (n))
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 = _BV(15); if (data & 0x80) GPIOC->BSRR = _BV(13); else GPIOC->BRR = _BV(13); GPIOC->BSRR = _BV(15); data <<= 1; } }
void ParOut(void) { GPIOC->BRR = _BV(14); GPIOC->BSRR = _BV(14); }
int main(void) { RCC->APB2ENR = _BV(2) | _BV(4) | _BV(11); // 開啟PA、PC和TIM1時鐘 GPIOA->CRH = 0x00000080; // PA9設為輸入 GPIOA->BSRR = _BV(9); // PA9為帶上拉的輸入 GPIOC->CRH = 0x33300000; // PC13~15設為輸出
TIM1->ARR = 10; TIM1->DIER = 0x01; // UIE=1 NVIC->ISER[0] = _BV(25); // 允許執行定時器1中斷服務函數, 編號為25 // 配置外部時鐘輸入 TIM1->CCMR1 = 0xf100; // IC2F=1111, CC2S=01 TIM1->CCER = _BV(5); // 下降沿觸發 TIM1->SMCR = 0x67; // SMS=111, TS=110 // 刷新寄存器 TIM1->CR1 = 0x54; // URS=1 TIM1->EGR = 0x01; // UG=1 // 開始計數 TIM1->CR1 = 0x351; // CKD=10, CEN=1 while (1) { SerIn(seg8[num % 10]); SerIn(_BV(0)); ParOut(); delay(); SerIn(seg8[num % 100 / 10]); SerIn(_BV(1)); ParOut(); delay(); SerIn(seg8[num / 100]); SerIn(_BV(2)); ParOut(); delay(); if (TIM1->CR1 & _BV(4)) { SerIn(0xbf); SerIn(_BV(6)); ParOut(); } delay(); SerIn(seg8[TIM1->CNT % 100 / 10]); SerIn(_BV(5)); ParOut(); delay(); SerIn(seg8[TIM1->CNT % 10]); SerIn(_BV(4)); ParOut(); delay(); } }
// 定時器中斷函數 void TIM1_UP_IRQHandler(void) { TIM1->SR &= ~_BV(0); // Status register (UIF: Update interrupt flag = 0) num++; }
|
一派掌门 二十级 |
數碼管顯示格式:-03 033 其中符號代表計數器正在向下計數,03表示定時器當前的計數值,033表示定時器中斷觸發的個數
|
|
一派掌门 二十级 |
本程序採用的計數方式是:先向上後向下,也就是Center-aligned mode。 計數值的變化範圍是-10~-1(向下計數), 0~9(向上計數),符號改變一次就觸發一次定時器中斷。
|
|
一派掌门 二十级 |
【模式2】 #include <stm32f10x.h>
#define _BV(n) (1 << (n))
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 = _BV(15); if (data & 0x80) GPIOA->BSRR = _BV(0); // 之前的PC13信號線轉移到了PA0上,因為使用了上面接的LED else GPIOA->BRR = _BV(0); GPIOC->BSRR = _BV(15); data <<= 1; } }
void ParOut(void) { GPIOC->BRR = _BV(14); GPIOC->BSRR = _BV(14); }
int main(void) { RCC->APB2ENR = _BV(2) | _BV(4) | _BV(11); // 開啟PA、PC和TIM1時鐘 GPIOA->CRH = 0x00080000; // PA12設為輸入 GPIOA->CRL = 0x00000003; GPIOA->BSRR = _BV(12); // PA12為帶上拉的輸入 GPIOC->CRH = 0x33300000; // PC13~15設為輸出 GPIOC->BSRR = _BV(13);
TIM1->ARR = 10; TIM1->DIER = 0x41; // UIE=1, TIE=1 NVIC->ISER[0] = _BV(25) | _BV(26); // 配置外部時鐘輸入 TIM1->SMCR = 0xcf00; // ETP=1(下降沿觸發), ECE=1 // 刷新寄存器 TIM1->CR1 = 0x54; // URS=1 TIM1->EGR = 0x01; // UG=1 // 開始計數 TIM1->CR1 = 0x351; // CKD=10, CEN=1 while (1) { // 顯示觸發的中斷個數 SerIn(seg8[num % 10]); SerIn(_BV(0)); ParOut(); delay(); SerIn(seg8[num % 100 / 10]); SerIn(_BV(1)); ParOut(); delay(); SerIn(seg8[num / 100]); SerIn(_BV(2)); ParOut(); delay(); if (TIM1->CR1 & _BV(4)) // 顯示計數方向 { SerIn(0xbf); SerIn(_BV(6)); ParOut(); } delay(); // 顯示計數值 SerIn(seg8[TIM1->CNT % 100 / 10]); SerIn(_BV(5)); ParOut(); delay(); SerIn(seg8[TIM1->CNT % 10]); SerIn(_BV(4)); ParOut(); delay(); } }
// 定時器中斷函數 void TIM1_UP_IRQHandler(void) { TIM1->SR &= ~_BV(0); // Status register (UIF: Update interrupt flag = 0) num++; }
// 在模式2下無法觸發這個中斷! void TIM1_TRG_COM_IRQHandler(void) { TIM1->SR &= ~_BV(6); GPIOC->ODR ^= _BV(13); }
|
|