首页 > 解决方案 > 中断 - 微控制器,Atmega 328p - 捕捉时间

问题描述

免责声明 - 在中断方面,我是个大菜鸟,所以如果您有一些错误要指出,我很高兴听到。我正在编程一个数字霍尔传感器,只要有磁铁,它就像一个开关,我想为它使用一个计时器。d10 引脚,PB2,由 5V 供电。[Atmega328p]
我想用oneround单轮的时间来计算风速,无限循环。
磁铁以小半径旋转,因此 PIN [默认开启] 将在 0.1s-1.0s 之间的任何速度关闭,然后再打开。

当我尝试打印该值时问题上升TCNT1,如果我使用 256 的预分频器,它会给出一个数字 - 仍然是随机的,但是数字。现在,如果我使用 1024 预分频器,每次出现磁铁时,它都会不断加 1。
你能告诉我我做错了什么吗?
我可以打印TCNT1为与 PIN 转回 On 点(即 360 度)的时间差吗?

我需要以毫秒为单位的时间来计算风速。


//include user/defined libraries
#include "i2cmaster.h"
#include "lcd.h"
#include "ds1621.h"
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <unistd.h>
#include <util/delay.h>

//void init_timer1();

volatile unsigned char run = 0;
volatile unsigned int oneround;


void init_timer1() {
    //______________________________// Set the Timer Mode to CTC and start timer
    TCCR1B |= (1 << WGM12);
    OCR1A = 0x3D; // Set the value that you want to count to OCR1A = 0x3D;          
    PCICR |= (1 << PCIE0);
    PCIFR |= (1 << PCIF0);
    PCMSK0 |= (1 << PCINT2);
    //________________________________________________________________________________________pray  this 1010011 1001000 1001001  1010100 works
    sei();

}
int main(void) {
    // WINDSPEED"
    DDRB &= ~(1 << DDB2); //     DIRECTION REGISTER  INOUT              D10  PCINT2 OC1B     PB2     SS   PWM  CTC
    PORTB |= (1 << PORTB2); //  OUTPUT REGISTER  hIGH
    //DDRB  = 0b11111011;         //   DIRECTION REGISTER  IN OUT
    //PORTB = 0b00000100;           //   OUTPUT REGISTER

    i2c_init(); //initialization of communication
    LCD_init(); //initialization of the LCD
    init_timer1(); // Lets count those laps baby

    while (1) {                          /*  O_O KAPUT!  */

    LCD_set_cursor(1, 1);
    printf("%u            ", oneround);
        // rest of the sensors

    }


return 0;
}                                           // Main close 

ISR(PCINT0_vect) {
    if (run == 0) {
TCCR1B &= ~(1 << CS12); // clear timer and stop

        oneround = TCNT1; 
    TIFR1 |= (1 << OCF1A) | (1 << OCF1B) | (1 << TOV1);
    TCCR1B |= (1 << CS22) | (1 << CS21) | (1 << CS20); // set prescaler to  1024   and start timer    1sec 
    run = 1;
}

else {
    run = 0;
}
}




标签: ctimerembeddedinterrupt

解决方案


首先。

TCCR1B |= (1 << CS22) | (1 << CS21) | (1 << CS20); // set prescaler to  1024   and start timer    1sec 

您正在使用 Timer2 ( CS2x) 的位名称并将它们分配给计时器 1 ( TCCR1x) 的寄存器。CS2x== CS1x,但在语义上它是一个错误。

请参阅数据表,第 15.11.2 章TCCR1B——定时器/计数器 1 控制寄存器 B ,第110页。

当所有 3 位CS12,CS11CS10置位时,定时器在 T1 引脚上的外部时钟源上工作。如果你想要 1:1024 的预分频器,那么CS11位应该是 0。

下一个。

当逻辑电平向任一方向变化时,可以触发引脚更改中断。偶尔会有小尖峰,水平可以改变两次,但中断只会触发一次。所以,不要忘记检查输入引脚上的电平。

当你写

TCCR1B &= ~(1 << CS12);

它不会停止定时器,因为它只清除 CS12 位但 CS10 和 CS11 位保留(导致定时器继续使用另一个预分频器计数)。

此外,停止计时器不会重置其值。你需要写TCNT1 = 0;来重置它。

你也不需要停止柜台。只需使用整个周期来计算差异。

volatile uint16_t prev_timer_value = 0;
volatile uint16_t oneround = 0;



ISR(PCINT0_vect) {
    if ((PINB & (1 << PINB2)) == 0) { // Low level on the pin
        uint16_t tval = TCNT1; // latch the current timer value;
        oneround = tval - prev_timer_value; // calc the difference;
        prev_timer_value = tval; // remember a new val
    }
}

// To start the timer just start it in the Normal mode 
TCCR1A = 0;
TCCR1B = (1 << CS12) | (1 << CS10); // 1:1024


推荐阅读