巨大八爪鱼
武林盟主 二十一級
|
#include <stm32f10x.h>
#define _BV(n) (1 << (n))
uint8_t n = 0; uint8_t seg8[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90};
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); else GPIOA->BRR = _BV(0); GPIOC->BSRR = _BV(15); data <<= 1; } }
void ParOut(void) { GPIOC->BRR = _BV(14); GPIOC->BSRR = _BV(14); }
void seg_scan(uint8_t i) { while (i--) { SerIn(seg8[n % 100 / 10]); SerIn(_BV(7)); ParOut(); delay(); SerIn(seg8[n % 10]); SerIn(_BV(6)); ParOut(); delay(); SerIn(seg8[TIM1->CNT % 10000 / 1000]); SerIn(_BV(1)); ParOut(); delay(); SerIn(seg8[TIM1->CNT % 1000 / 100]); SerIn(_BV(0)); ParOut(); delay(); } }
int main(void) { RCC->APB2ENR = _BV(2) | _BV(4) | _BV(11); // 开启PA、PC和TIM1时钟, 不需要开启AFIO的时钟 GPIOA->CRH = 0x0000008b; // PA9设为输入, PA8设为复用50MHz推挽输出 GPIOA->CRL = 0x00000003; // PA0设为50MHz推挽输出 GPIOC->CRH = 0x33000000; // PC14~15设为50MHz推挽输出 GPIOA->BSRR = _BV(9); // PA9输入带上拉, 即悬空时输入高电平
TIM1->ARR = 5099; TIM1->PSC = 65535; TIM1->CCR1 = 2000; // 输出比较值 TIM1->CCMR1 = 0xf160; // CC2S=01(IC2=>TI2, 通道2设为输入), IC2F=1111(硬件消抖), OC1M=110(通道1选PWM模式1) TIM1->BDTR = 0x8000; // MOE=1(允许通道输出) TIM1->CCER = 0x21; // CC2P=1(TI2下降沿触发), CC1E=1(开通道1输出) TIM1->SMCR = 0x66; // TS=110(设置TRGI为TI2(PA9)), SMS=110(trigger mode) // 开中断 NVIC->ISER[0] = _BV(25) | _BV(26); TIM1->DIER = 0x61; // TIE=1, COMIE=1, UIE=1 // 刷新寄存器 TIM1->CR1 = 0x0c; // OPM=1, URS=1 TIM1->EGR = 0x01; // UG=1 TIM1->CR1 &= ~_BV(2); // URS=0 //TIM1->EGR = 0x20; // COMG=1, 软件触发COM事件, 数码管最高位变为5 while (1) { seg_scan(1); } }
void TIM1_UP_IRQHandler(void) { TIM1->SR &= ~_BV(0); // UIF=0 n = 0; }
void TIM1_TRG_COM_IRQHandler(void) { if (TIM1->SR & _BV(5)) { TIM1->SR &= ~_BV(5); // COMIF=0 n = 50 + n % 10; } else if (TIM1->SR & _BV(6)) { TIM1->SR &= ~_BV(6); // TIF=0 n = n - n % 10 + 6; } }
|
巨大八爪鱼
武林盟主 二十一級
|
在本例中,只有TIM1_UP_IRQHandler中断以及TIM1_TRG_COM_IRQHandler中的TI中断可以触发。COM中断无法触发由PA9上的按键触发。
|
巨大八爪鱼
武林盟主 二十一級
|
实验现象是:最开始PC13上的LED指示灯是熄灭的(输出了高电平),数码管最左端显示00。按下按键PA9后(使PA9输入低电平),数码管最左端显示06,右端开始计数。到了20时LED亮。到了50时回到00,LED灭,最左端变回00,定时器停止工作。
|
巨大八爪鱼
武林盟主 二十一級
|
CCMR1寄存器中还有一个加速位OC1FE。如果将该为置1,那么定时器将忽略CCR1的值,按键按下时立即改变OC2的电平,输出脉冲,然后到了CNT=CCR1的时候才触发输出比较中断TIM1_CC_IRQHandler。也就是相当于不改变中断的触发时间,将脉冲的产生延迟时间(t=CCR1)完全去掉(变为t=3个时钟周期, 接近于0)。 TIM1->CCMR1 |= _BV(2); // OC1FE=1 如果不使用该位的功能,而是将CCR1设为0,那么其延迟时间t为5个时钟周期,反应较慢。
|
巨大八爪鱼
武林盟主 二十一級
|
换句话说,启用了OC1FE加速功能之后,脉冲的产生时间将和输出比较中断触发的时间不一致。
|