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