|  | 【程序】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);
 }
 
 |