設置 | 登錄 | 註冊

目前共有4篇帖子。

【程序】STM32定時器1對外部輸入信號(PA9下降沿)進行計數,帶消抖

1樓 巨大八爪鱼 2016-12-26 23:24
#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++;
}

2樓 巨大八爪鱼 2016-12-26 23:25
數碼管顯示格式:-03 033
其中符號代表計數器正在向下計數,03表示定時器當前的計數值,033表示定時器中斷觸發的個數
3樓 巨大八爪鱼 2016-12-26 23:27
本程序採用的計數方式是:先向上後向下,也就是Center-aligned mode。
計數值的變化範圍是-10~-1(向下計數), 0~9(向上計數),符號改變一次就觸發一次定時器中斷。
4樓 巨大八爪鱼 2016-12-30 21:21
【模式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);
}

內容轉換:

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