Cách cập nhật biến trong ISR bằng Bộ hẹn giờ


8

Tôi đang cố kiểm tra tần số của Timer3 bằng bộ đếm. Giá trị của bộ đếm, được khai báo là không ổn định, được tăng lên trong ISR và cứ sau mỗi giây, tổng được hiển thị trong vòng lặp chính và đặt lại giá trị về 0.

Bộ hẹn giờ đã được thiết lập chính xác. (Nếu tôi chọn bộ hẹn giờ 3Hz, tôi có thể thấy đèn led nhấp nháy)

Vấn đề

Số lượt truy cập không tăng. Đây là đầu ra:

Setup Completed
tick: 1
tick: 0
tick: 0
tick: 0

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);

  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B = 20; // 800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();

  Serial.println("Setup completed");
}

void loop()
{
  if (millis() % 1000 == 0)
  {
    Serial.print(" tick: ");
    Serial.println(cont);
    cont = 0;
  }
}

ISR(TIMER3_COMPB_vect)
{
  //digitalWrite(13, digitalRead(13) ^ 1);
  cont++;
}

EDIT Bộ hẹn giờ này được sử dụng để đọc giá trị anlog từ gia tốc kế và lưu trữ nó trong một mảng nổi. Nhưng tại thời điểm này tôi bị mắc kẹt trong vấn đề cập nhật này.

GIẢI PHÁP 1 Cảm ơn Gerben

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3A = 20; // 20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  delay(1000);
  Serial.println(cont);
  cont = 0;
}

ISR(TIMER3_COMPB_vect)
{
  cont++;
}

GIẢI PHÁP 2 Nhờ BrettM

volatile int cont = 0;

void setup()
{
  Serial.begin(9600);
  pinMode(13, OUTPUT);

  // Initialize Timer
  cli();          // disable global interrupts
  TCCR3A = 0;     // set entire TCCR3A register to 0
  TCCR3B = 0;     // same for TCCR3B

  // set compare match register to desired timer count: 800 Hz
  OCR3B =  20; //800Hz 5; // 3 Hz
  // turn on CTC mode:
  //TCCR3B |= (1 << WGM32);
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR3B |= (1 << CS30) | (1 << CS32);
  // enable timer compare interrupt:
  TIMSK3 |= (1 << OCIE3B);
  // enable global interrupts:
  sei();
  Serial.println("Setup completed");
}

void loop()
{
  Serial.println(cont); 
  cont = 0;
  delay(1000);

}

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}

Và nếu bạn không chú ý đến digitalWritedòng bạn thấy đèn LED nhấp nháy khoảng một lần mỗi giây (cứ sau 0,66 giây)?
Ricardo

Có, nếu tôi không chú ý digitalWritevà đặt OCR3B = 5;đèn led nhấp nháy ở tần số đó.
Người dùng

Sau đó, đó là một sai lầm. Bạn đã thử bình luận ra cont = 0;bên trong vòng lặp? Điều gì xảy ra sau đó?
Ricardo

1
Hãy thử tăng tần số. Tôi nghĩ rằng câu lệnh if của bạn có thể xóa bộ đếm thường xuyên hơn so với ngắt được gọi, bằng cách nào đó. Nhưng sau đó bạn sẽ thấy nhiều cái hơn trong đầu ra. Cũng để nếu chạy lâu hơn (nói 1 phút) và dán kết quả. Ngoài ra, khi bạn cập nhật câu hỏi, hãy để lại đầu ra cũ để câu hỏi của bạn có ý nghĩa (không có lịch sử chỉnh sửa).
Ricardo

1
Tôi nghi ngờ rằng thói quen ngắt chỉ được gọi một lần và sau đó nó bị vô hiệu hóa. Tôi đã đọc ở đâu đó rằng các ngắt bị vô hiệu hóa khi mã ngắt đang chạy và trong một số trường hợp bạn phải kích hoạt lại nó, nhưng tôi thực sự không chắc đó có phải là trường hợp không. Hy vọng ai đó hiểu biết hơn sẽ đến giải cứu chúng tôi ...
Ricardo

Câu trả lời:


5

Trong chế độ CTC, đỉnh là OCR3A, không OCR3B!

Sau đó TIMSK3 |= (1 << OCIE3B);cũng nên được thay đổi để TIMSK3 |= (1 << OCIE3A);, và ISR(TIMER3_COMPB_vect)đểISR(TIMER3_COMPA_vect)

Đối với 3Hz, OCR3Anên là 5208, không phải 20.

Về mặt kỹ thuật TCCR3B |= (1 << WGM12);nênTCCR3B |= (1 << WGM32);


Với cấu hình của bạn, bộ đếm không được cập nhật và cứ sau mỗi giây, câu "Thiết lập đã hoàn tất", (được ghi trong hàm setup ()!) Được hiển thị. Hành vi thực sự kỳ lạ.
Người dùng

Giải quyết bằng cách sử dụng TIMSK3 |= (1 << OCIE3B);. Cảm ơn bạn Gerben! Vui lòng sửa đổi câu trả lời của bạn và tôi sẽ chấp nhận nó như một giải pháp.
Người dùng

1
Tôi quên đề cập đến bạn cũng cần thay đổi vectơ ISR. ISR(TIMER3_COMPB_vect)nên ISR(TIMER3_COMPA_vect). Nếu ISR không được xác định, thì AVR sẽ tự thiết lập lại, giống như bạn đang gặp phải. Tôi vui vì bạn đã làm nó hoạt động.
Gerben

3

Có vẻ như câu trả lời của tôi cho câu hỏi này trước đây chưa đầy đủ, cảm ơn vì đã chỉ ra rằng chế độ CTC chỉ hoạt động với OCR3A Gerben. Tôi xin lỗi vì đã không kiểm tra câu trả lời trước khi tôi đăng nó.

Chỉ cung cấp thông tin trong câu hỏi này, câu trả lời của Gerben đã hoàn tất, nhưng vì câu hỏi khác của bạn ngụ ý rằng bạn không thể sử dụng OCR3A do thư viện Servo tôi sẽ thêm một chút. (Tôi cũng đã chỉnh sửa câu trả lời đó)

bạn có thể mô phỏng hành vi của chế độ CTC bằng cách đặt TCNT3 thành 0 trong thói quen ngắt của bạn. Nhớ xóa dòng bật chế độ CTC trong mã của bạn.

Tôi đã kiểm tra mã của bạn với ISR ​​này:

ISR(TIMER3_COMPB_vect)
{
  TCNT3 = 0;
  cont++;
}

và cấu hình này của các thanh ghi hẹn giờ

OCR3B = 5208; // 800Hz 5; // 3 Hz
// Set CS10 and CS12 bits for 1024 prescaler:
TCCR3B |= (1 << CS30) | (1 << CS32);
// enable timer compare interrupt:
TIMSK3 |= (1 << OCIE3B);

Điều này có thể kém chính xác hơn một chút ở tần số cao so với CTC, tôi không chắc, nhưng ở tần số 3Hz, nó hoạt động hoàn hảo. Lưu ý rằng 5208 là giá trị OCR chính xác, không phải 20 (một lần nữa nhờ Gerben).


Tôi đã thử mã của bạn nhưng bộ đếm không tăng. Tôi đã thêm TCNT3=0;ISR () và xóa //TCCR3B |= (1 << WGM32);trong thiết lập () như bạn đã nói. Tôi cũng đã thử bình luận về cont=0;dòng này nhưng không có gì thay đổi
UserK

1
Hãy chắc chắn rằng mã phù hợp với những gì được đăng trong câu hỏi theo mọi cách khác. Hãy thử thay đổi vòng lặp của bạn thành chỉ println(cont); delay(1000);. Ngoài ra, bạn vẫn bao gồm các bit với cli () và TCCR3A vv đúng không?
BrettAM

Được rồi cảm ơn. Ở tần số 800 Hz vẫn chính xác!
Người dùng
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.