Cara memperbarui variabel dalam ISR menggunakan Pengatur Waktu

8

Saya mencoba memeriksa frekuensi Timer3 menggunakan penghitung. Nilai penghitung, dinyatakan sebagai volatile, bertambah dalam ISR dan setiap detik jumlahnya ditampilkan dalam loop utama dan nilai reset ke nol.

Timer telah diatur dengan benar. (Jika saya memilih timer 3Hz saya bisa melihat led berkedip)

Masalah

Penghitung tidak bertambah. Berikut hasilnya:

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

KODE

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 Timer ini digunakan untuk membaca nilai anlog dari accelerometer dan menyimpannya dalam array float. Tetapi pada saat ini saya terjebak pada masalah pembaruan ini.

SOLUSI 1 Terima kasih untuk 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++;
}

SOLUSI 2 Terima kasih kepada 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++;
}
UserK
sumber
Dan jika Anda menghapus tanda komentar pada digitalWritebaris Anda melihat LED berkedip sekali per detik (setiap 0,66)?
Ricardo
Ya, Jika saya batalkan komentar digitalWritedan atur OCR3B = 5;led berkedip kira-kira pada frekuensi itu.
UserK
Maka itu adalah misteri. Sudahkah Anda mencoba mengomentari bagian cont = 0;dalam loop? Lalu apa yang terjadi?
Ricardo
1
Coba tambah frekuensinya. Saya pikir pernyataan if Anda mungkin membersihkan counter lebih sering daripada interupsi, entah bagaimana. Tetapi kemudian Anda akan melihat lebih banyak yang ada di output. Biarkan juga jika berjalan lebih lama (katakan 1 menit) dan rekatkan hasilnya. Juga, ketika Anda memperbarui pertanyaan, biarkan output lama sehingga pertanyaan Anda masuk akal (tanpa riwayat edit).
Ricardo
1
Saya menduga bahwa rutin interupsi dipanggil hanya sekali dan kemudian dinonaktifkan. Saya pernah membaca bahwa interupsi dinonaktifkan ketika kode interupsi berjalan, dan dalam beberapa kasus Anda harus mengaktifkannya kembali, tetapi saya benar-benar tidak yakin apakah itu masalahnya. Semoga seseorang yang lebih berpengetahuan akan datang untuk menyelamatkan kita ...
Ricardo

Jawaban:

5

Dalam mode CTC bagian atas adalah OCR3A, bukan OCR3B!

Setelah itu TIMSK3 |= (1 << OCIE3B);juga harus diubah menjadi TIMSK3 |= (1 << OCIE3A);, dan ISR(TIMER3_COMPB_vect)menjadiISR(TIMER3_COMPA_vect)

Untuk 3Hz, OCR3Aharus 5208, bukan 20.

Secara teknis TCCR3B |= (1 << WGM12);seharusnyaTCCR3B |= (1 << WGM32);

Gerben
sumber
Dengan konfigurasi Anda penghitung tidak diperbarui dan setiap detik kalimat "Pengaturan selesai", (ditulis dalam fungsi pengaturan ()!) Ditampilkan. Perilaku yang sangat aneh.
UserK
Dipecahkan menggunakan TIMSK3 |= (1 << OCIE3B);. Gerben terima kasih! Harap modifikasi jawaban Anda dan saya akan menerimanya sebagai solusi.
UserK
1
Saya lupa menyebutkan Anda juga perlu mengubah vektor ISR. ISR(TIMER3_COMPB_vect)seharusnya ISR(TIMER3_COMPA_vect). Jika ISR tidak ditentukan, AVR akan mereset sendiri, seperti yang Anda alami. Senang Anda berhasil.
Gerben
3

Tampaknya jawaban saya untuk pertanyaan ini sebelumnya tidak lengkap, terima kasih telah menunjukkan bahwa mode CTC hanya berfungsi dengan OCR3A Gerben. Saya minta maaf karena tidak menguji jawaban sebelum mengirimnya.

Mengingat informasi hanya dalam pertanyaan ini, jawaban Gerben lengkap, tetapi karena pertanyaan Anda yang lain menyiratkan bahwa Anda tidak dapat menggunakan OCR3A karena perpustakaan Servo saya akan menambahkan sedikit. (Saya juga mengedit jawaban itu)

Anda dapat meniru perilaku mode CTC dengan mengatur TCNT3 ke 0 dalam rutinitas interupsi Anda. Ingatlah untuk menghapus baris yang mengaktifkan mode CTC dalam kode Anda.

Saya telah menguji kode Anda dengan ISR ini:

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

dan konfigurasi pengatur waktu ini

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);

Ini mungkin sedikit kurang akurat pada frekuensi tinggi daripada CTC, saya tidak yakin, tetapi pada 3Hz itu bekerja dengan sempurna. Perhatikan bahwa 5208 adalah nilai OCR yang benar, bukan 20 (sekali lagi terima kasih kepada Gerben).

BrettAM
sumber
Saya sudah mencoba kode Anda tetapi penghitungnya tidak bertambah. Saya telah menambahkan TCNT3=0;di ISR ​​() dan menghapus //TCCR3B |= (1 << WGM32);di setup () seperti yang Anda katakan. Saya juga sudah mencoba berkomentar cont=0;tapi tidak ada yang berubah
UserK
1
Pastikan kode cocok dengan apa yang diposting dalam pertanyaan dengan cara lain. Coba ubah loop Anda menjadi adil println(cont); delay(1000);. Anda juga masih termasuk bit dengan cli () dan TCCR3A dll yang benar?
BrettAM
Ok terima kasih. Pada 800 Hz masih akurat!
UserK