設置 | 登錄 | 註冊

目前共有5篇帖子。

【程序】STM32單脈衝模式的使用

1樓 巨大八爪鱼 2017-1-11 12:20
#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;
    }
}
2樓 巨大八爪鱼 2017-1-11 12:21
在本例中,只有TIM1_UP_IRQHandler中斷以及TIM1_TRG_COM_IRQHandler中的TI中斷可以觸發。COM中斷無法觸發由PA9上的按鍵觸發。
3樓 巨大八爪鱼 2017-1-11 12:24
實驗現象是:最開始PC13上的LED指示燈是熄滅的(輸出了高電平),數碼管最左端顯示00。按下按鍵PA9後(使PA9輸入低電平),數碼管最左端顯示06,右端開始計數。到了20時LED亮。到了50時回到00,LED滅,最左端變回00,定時器停止工作。
4樓 巨大八爪鱼 2017-1-11 13:29
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個時鐘周期,反應較慢。
5樓 巨大八爪鱼 2017-1-11 13:30
換句話說,啟用了OC1FE加速功能之後,脈衝的產生時間將和輸出比較中斷觸發的時間不一致。

內容轉換:

回覆帖子
內容:
用戶名: 您目前是匿名發表。
驗證碼:
看不清?換一張
©2010-2025 Purasbar Ver3.0 [手機版] [桌面版]
除非另有聲明,本站採用知識共享署名-相同方式共享 3.0 Unported許可協議進行許可。