Timer interrupts on Arduino game not working - arduino

I have a ping pong game and I am trying to add a 60 second timer to it.
So that if the round is not finished within 60 seconds it would end automatically.
The purpose is to count without using millis()
I tried to implement this but it didn't seem to be working.
So I tried to print out the seconds in the serial monitor and it just constantly shows
0000000000000000000000000
What is the issue here?
volatile uint16_t counter = 0;
volatile uint16_t seconds = 0;
void setup()
{
//timer1 for overflow interrupt
noInterrupts();
TCCR1A = 0; //initialize timer1
TCCR1B = 0;
TCCR1B |= 0b00000100; //256 prescaler
TIMSK1 |= 0b00000001; //enable overflow interrupt
interrupts();
}
ISR(TIMER1_OVF_vect) //timer overflow ISR: update counter
{
counter++;
if (counter == 62500)
{
counter = 0;
seconds++;
}
}
void loop()
{
Serial.print(seconds);
game = update();
lcd.clear();
render();
I included the parts of the code which are directly related to the issue.
Help would be appreciated very much!

Related

Arduino send bad signal to interrupt pin

I have connected coin hopper and coin acceptor to one arduino uno, coin acceptor connected to pin 2, coin hopper to pin 3 - sensor and pin 7 - relay. When coin hopper switch relay, it is executing coininterrupt
for coin hopper I am using this script link
coin acceptor script: link
I need this 2 scripts working on 1 arduino
my code:
#define SENSOR 3
#define RELAY 7
#define ACCEPTOR 2
volatile boolean insert = false;
int pulse=0,count;
char sen;
int temp=0;
unsigned long int timer;
void setup()
{
Serial.begin(9600);
pinMode(SENSOR,INPUT_PULLUP);
pinMode(RELAY,OUTPUT);
sen=digitalRead(SENSOR);
digitalWrite(RELAY, HIGH);
attachInterrupt(digitalPinToInterrupt(ACCEPTOR), coinInterrupt, RISING);
}
void loop()
{
if (insert) {
insert = false;
Serial.println("coin");
delay(1000);
}
if(Serial.available())
{
timer=millis();
// temp is amount to dispense send to arduino
temp=Serial.parseInt();
if(temp>0){
digitalWrite(RELAY,LOW);}
}
sen=(sen<<1)|digitalRead(SENSOR);
// if hopper sensor read drop coin
if(sen==1)
{
timer=millis();
pulse++;
sen&=0x03;
Serial.println("out 1");
//if dispensed coins equal with coins to dispense stop engine
if(pulse==temp)
{
digitalWrite(RELAY,HIGH);
pulse=0;
temp=0;
}
}
// if amount dispensed is not equal with amount to dispense and engine running, stop
if((digitalRead(RELAY)==LOW)&(millis()-timer>2000))
{
digitalWrite(RELAY,HIGH);
pulse=0;
temp=0;
}
}
void coinInterrupt() {
insert = true;
}
I was trying to change pins (arduino uno support interrupts on pin 2 and 3 only) but problem still appears so I guess there is issue in the code
your sketch does not run in this state :
first fix errors :
declare insert as volatile
remove cpulse (not used anywhere)
change 'if()' to (I suppose) 'if (insert) ....'
remove stuff with 'sen' var : simply use if(digitalRead(SENSOR)) or if(!digitalRead(SENSOR))
except if you need to store relay state.
use logical operators like || or && unless you really need bitwise operations
example of result sketch :
#define SENSOR 3
#define RELAY 7
volatile boolean insert = false;
byte amountToDispense = 0;
int pulse = 0;
int temp = 0;
unsigned long int timer;
void setup()
{
Serial.begin(9600);
pinMode(SENSOR, INPUT_PULLUP);
pinMode(RELAY, OUTPUT);
digitalWrite(RELAY, HIGH);
attachInterrupt(digitalPinToInterrupt(2), coinInterrupt, RISING);
}
void loop()
{
if (insert ) {
insert = false;
Serial.println("coin");
delay(1000);
}
if (Serial.available())
{
timer = millis();
temp = Serial.parseInt();
if (temp > 0) {
//amountToDispense = Serial.read() - 48;
digitalWrite(RELAY, LOW);
}
}
if (digitalRead(SENSOR))
{
timer = millis();
pulse++;
Serial.println("out 1");
if (pulse >= temp)
{
digitalWrite(RELAY, HIGH);
pulse = 0;
temp = 0;
}
}
if (!digitalRead(RELAY) && (millis() - timer > 2000))
{
digitalWrite(RELAY, HIGH);
pulse = 0;
temp = 0;
}
}
void coinInterrupt() {
insert = true;
}
What is this supposed to do?
sen=(sen<<1)|digitalRead(SENSOR);
You init sen with digitalRead(SENSOR);
Assuming that pin is LOW when you start the sketch and turns HIGH, sen will become 1.
Next you do sen &= 0x03 so sen is still 1.
Again sen=(sen<<1)|digitalRead(SENSOR); , sen will either be 2 or 3.
Next loop run sen=(sen<<1)|digitalRead(SENSOR); sen is now 4 or 6. and so on...
I don't have time to think about what you want to achieve but this is definitely a problem as you'll only enter if (sen == 1) once and never again.
If this is not sufficient you should probably improve your post as it is unclear what arduino sends bad signal to interrup pin is supposed to mean. That doesn't make sense. Explain the expected behaviour of your program and how it behaves instead. add more comments so it becomes clear what you intend to do with each block of code so we don't have to interpret

I'm having trouble implementing the Atmega328 timer into my arduino networking

I am trying to implement error correction over an r/f communication between two arduinos. I tried adding a timer to it, in order to create a packet resend, but whenever it gets past the first send, it starts printing garbage ad infinity instead of doing the timer interrupt.
I tried messing around with the inside loop conditions some as well as trying to figure out what was wrong with the timer, but I couldn't figure it out. The problem seems to happen right around the first serial print, which is strange, because that part of the code is mostly unchanged.
(packets is a structure of two ints)
#include <ELECHOUSE_CC1101.h>
#include "packets.h"
// These examples are from the Electronics Cookbook by Simon Monk
// Connections (for an Arduino Uno)
// Arduino CC1101
// GND GND
// 3.3V VCC
// 10 CSN/SS **** Must be level shifted to 3.3V
// 11 SI/MOSI **** Must be level shifted to 3.3V
// 12 SO/MISO
// 13 SCK **** Must be level shifted to 3.3V
// 2 GD0
const int n = 61;
unsigned short int sequence = 0;
byte buffer[n] = "";
void setup() {
Serial.begin(9600);
Serial.println("Set line ending to New Line in Serial Monitor.");
Serial.println("Enter Message");
ELECHOUSE_cc1101.Init(F_433); // set frequency - F_433, F_868, F_965 MHz
// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 0xFFFF; // Max value for overflow for now
TCCR1B |= (1 << CS12); // 256 prescaler
interrupts(); // enable all interrupts
}
Packet pckt, recieve;
ISR(TIMER1_OVR_vect){ // timer compare interrupt service routine
//Resend packet
ELECHOUSE_cc1101.SendData(buffer, pckt.data + pckt.seqNum);
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
buffer[len] = '\0';
recieve.seqNum = buffer[n];
Serial.println("Interrupt");
}
void loop() {
if (Serial.available()) {
pckt.data = Serial.readBytesUntil('\n', buffer, n);
pckt.seqNum = sequence;
buffer[pckt.data] = '\0';
buffer[n-1] = pckt.seqNum;
Serial.println((char *)buffer);
ELECHOUSE_cc1101.SendData(buffer, pckt.data + pckt.seqNum);
TCNT1 = 0; // clear timer
TIMSK1 |= (1 << TOIE0); // enable timer compare interrupt
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
while (recieve.seqNum <= sequence) {
}
TIMSK1 &= ~(1 << TOIE0); // turn off the timer interrupt
}
}
Sending data takes too long for interrupts. You should keep calls to send and receive buffers of data within the loop() function call tree. For example, sending a 12 bytes message via UART at 9600 bauds can take up to about 12ms.
You can use the timer interrupt to decrement a timeout counter, as is usually done on micro controllers, or use the millis() function to handle timings, as is easily done on Arduino.
I suggest you use the millis() function to compute timeouts.
example:
/* ... */
// I could not figure out what you were trying to do with
// pckt.seqNum.... Putting it at the end of the buffer
// makes no sense, so I've left it out.
// Moreover, its size is 2, so placing it at buffer[n-1] overflows the buffer...
enum machineState {
waitingForSerial,
waitingForResponse,
};
unsigned int time_sent; // Always use unsigned for variables holding millis()
// can use unsigned char for timeouts of 255
// milliseconds or less. unsigned int is good for about
// 65.535 seconds or less.
machineState state = waitingForSerial;
void loop()
{
switch(state)
{
case waitingForSerial:
pckt.data = Serial.readBytesUntil('\n', buffer, sizeof(buffer));
if (pckt.data > 0)
{
++pckt.seqNum;
Serial.write(buffer, pckt.data);
ELECHOUSE_cc1101.SetReceive();
ELECHOUSE_cc1101.SendData(buffer, pckt.data);
time_sent = millis();
state = waitingForResponse;
}
break;
case waitingForResponse:
if (ELECHOUSE_cc1101.CheckReceiveFlag())
{
auto len = ELECHOUSE_cc1101.ReceiveData(buffer)) // can use C++17 with duinos!!!
Serial.print("cc1101: ");
Serial.write(buffer, len);
state = waitingForSerial; // wait for another command from PC
}
// 1 second timeout, note the cast and subtraction, this is to avoid any
// issues with rollover of the millis() timestamp.
else if ((unsigned int)millis() - time_sent > 1000)
{
// resend ... stays stuck this way.
Serial.println("Retrying :(");
ELECHOUSE_cc1101.SendData(buffer, pckt.data);
time_sent = millis();
}
break;
default:
state = waitingForSerial;
Serial.println("unhandled state");
break;
}
}

Using All Interrupt Vector Of A Timer

Purpose
I'm doing some timer experiment on atmega328.
I'm attempting to use every interrupt (except OVF).
Trying to make timer1 act likes 3 individual timers.
This might comes in handy when ran out of timer.
According to manual,there are 4 interrupt vectors related to timer1.
Timer1 Interrupt Vectors
My idea is making TCNT1 keep counting from 0 to 65535.
Then set the desired compare value in OCR1A,OCR1B and ICR1 registers.
When interrupts, manually add value to registers, so next interrupt will be trigger in same duration.
I wrote some codes to verify and the result seems to be ideal.
I'm considering that is this a proper way to use a timer?
or this may cause some bugs,error or efficiency issue?
Thanks!
Codes
int A_Ticks = 15624; //64us*(15624+1) = 1000ms
int B_Ticks = 23436; //1500ms
int ICR_Ticks = 31248; //2000ms
void setup()
{
Serial.begin(115200);
TCCR1A = 0x00;
TCCR1B = 0x00;
TCCR1B|= _BV(WGM13); //enable TIMER1_CAPT_vect
TCCR1B|= _BV(WGM12); //enable CTC
TCCR1B |= _BV(CS12); //prescaler = CPU clock/1024
TCCR1B &= ~_BV(CS11); //per tick = 64us
TCCR1B |= _BV(CS10);
OCR1A = A_Ticks;
OCR1B = B_Ticks;
ICR1 = ICR_Ticks;
char oldSREG = SREG;
noInterrupts();
TIMSK1 |= _BV(OCIE1A); // enable timer interrupt
TIMSK1 |= _BV(OCIE1B);
TIMSK1 |= _BV(ICIE1);
TIMSK1 |= _BV(TOIE1);
TCNT1=0;
SREG = oldSREG;
}
void loop()
{
delay(100);
}
ISR (TIMER1_COMPA_vect)
{
Serial.print(millis());
Serial.println(":COMPA");
OCR1A+=A_Ticks; //add value manually
}
ISR (TIMER1_COMPB_vect)
{
Serial.print(millis());
Serial.println(":COMPB");
OCR1B+=B_Ticks; //add value manually
}
ISR (TIMER1_OVF_vect)
{
Serial.print(millis());
Serial.println(":OVF_vect");
}
ISR (TIMER1_CAPT_vect)
{
//When interrupt into TIMER1_CAPT_vect
//TCNT will be clear to 0 due to CTC is on
//manually set it to value of ICR1 to make TCNT keep counting
TCNT1=ICR1;
ICR1+=ICR_Ticks; //add value manually
Serial.print(millis());
Serial.println(":CAPT_vect");
}
Result
999:COMPA
1499:COMPB
1999:CAPT_vect
1999:COMPA
2999:COMPA
2999:COMPB
3999:CAPT_vect
3999:COMPA
4194:OVF_vect
4499:COMPB
4999:COMPA
5999:CAPT_vect
5999:COMPA
5999:COMPB
6999:COMPA
7498:COMPB
7999:CAPT_vect
7999:COMPA
8388:OVF_vect

How to disable then re-enable a watchdog interrupt for Arduino?

I'm attempting to use a watchdog interrupt as a timer to sleep for a certain period of time with my Arduino. My problem lies in the fact that, on wake-up, I need to conduct operations that will take longer than 8 seconds.
Currently, my Arduino will sleep for 1 minute, using successive interrupts by the watchdog to wake it up and place it back into sleep. After 1 minute, however, I begin to conduct operations that take longer than 8 seconds and the watchdog interrupt times out.
I want to shut off the watchdog timer, conduct operations, then re-enable it and return to sleeping.
Here is my code:
#include "Adafruit_FONA.h"
#include <avr/sleep.h>
#include <avr/power.h>
#include <avr/wdt.h>
#define FONA_RX 10
#define FONA_TX 9
#define FONA_RST 4
#define LED_PIN 8
// this is a large buffer for replies
char replybuffer[255];
char *SMSnumber = "6015962842";
char stack[128] = {'c'};
//Value for watchdog timer interrupt.
volatile int f_wdt = 1;
int seconds = 0;
int minutes = 1;
int hours = 0;
int interval = ((hours*60*60) + (minutes*60) + (seconds))/8;
int timerCounter = 0;
//Setup for pulse sensor.
volatile int Signal; // holds the incoming raw data
int pulsePin = 0; //Pin to read at analog 0 for the pulse.
volatile int IBI = 600; // int that holds the time interval between beats! Must be seeded!
volatile boolean Pulse = false; // "True" when User's live heartbeat is detected. "False" when not a "live beat".
volatile int BPM; // int that holds raw Analog in 0. updated every 2mS
volatile boolean QS = false; // becomes true when Arduoino finds a beat.
unsigned long lastTime; // used to time the Pulse Sensor samples
unsigned long thisTime; // used to time the Pulse Sensor samples
//ISR for watchdog timer.
ISR(WDT_vect)
{
if(f_wdt == 0)
{
f_wdt=1;
timerCounter++;
}
else
{
Serial.println("WDT Overrun!!!");
}
}
// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
// Hardware serial is also possible!
//HardwareSerial *fonaSerial = &Serial;
// Use this for FONA 800 and 808s
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
delay(3000);
digitalWrite(LED_PIN, LOW);
while (!Serial);
Serial.begin(115200);
setupGsm();
setupWdt();
}
void loop()
{
if(f_wdt == 1)
{
if (timerCounter == interval)
{
WDTCSR |= _BV(WDTON);
Serial.println(F("Tried to stop the watchdog."));
delay(20000);
//Reset timer.
timerCounter = 0;
WDTCSR |= _BV(WDIE);
Serial.println(F("Tried to re-enable watchdog."));
}
/* Don't forget to clear the flag. */
f_wdt = 0;
/* Re-enter sleep mode. */
enterSleep();
}
else
{
/* Do nothing. */
}
}
void setupGsm()
{
fonaSerial->begin(4800);
while (! fona.begin(*fonaSerial)) {
Serial.println(F("Couldn't find FONA"));
delay(1000);
}
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
delay(500);
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
delay(500);
digitalWrite(LED_PIN, HIGH);
}
void enterSleep(void)
{
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
/* Now enter sleep mode. */
sleep_mode();
/* The program will continue from here after the WDT timeout*/
sleep_disable(); /* First thing to do is disable sleep. */
/* Re-enable the peripherals. */
power_all_enable();
}
void setupWdt()
{
/*** Setup the WDT ***/
/* Clear the reset flag. */
MCUSR &= ~(1<<WDRF);
/* In order to change WDE or the prescaler, we need to
* set WDCE (This will allow updates for 4 clock cycles).
*/
WDTCSR |= (1<<WDCE) | (1<<WDE);
/* set new watchdog timeout prescaler value */
WDTCSR = 1<<WDP0 | 1<<WDP3; /* 8.0 seconds */
/* Enable the WD interrupt (note no reset). */
WDTCSR |= _BV(WDIE);
}
In the void loop() function, I'm attempting to turn off the watchdog using WDTCSR |= _BV(WDTON); however my compiler complains that WDTON is not decalared in its scope.
Rather than directly accessing the controller's registers from your code, use wdt_enable() and wdt_disable() from the avr/wdt.h library to start and stop the watchdog timer.
Also, for the sake of system reliability, it might be better to actually keep the watchdog timer running (not disabling it), and add periodic calls to wdt_reset() inside long loops and functions to prevent inappropriate system resets.
For instance, you can replace the delay(20000); line in your code with a loop that repeats 20 times the statements: delay(1000); wdt_reset();

Ignore interrupt within time range arduino (lowpass filter)

I'm trying to attach interrupts to the rising edge of a signal (PWM). However, the signal is somewhat noisy when it's HIGH which causes the code to register another interrupt when it should not. I obviously tried to fix this in my circuit but that's not quite working so I moved to the software part.
The question is how I can filter out interrupts within a given frequency range? I need to apply a lowpass filter so that the interrupts do not get triggered when the signal is HIGH. My idea was detach the interrupt for a given amount of time or simply ignore the interrupt if it happens within a certain time range.
I'm just not sure how to achieve this.
This is my code:
unsigned long tsend = 0;
unsigned long techo = 0;
const int SEND = 2;
const int ECHO = 3;
unsigned long telapsed = 0;
unsigned long treal = 0;
void setup() {
Serial.begin(115200);
Serial.println("Start");
pinMode(SEND, INPUT);
pinMode(ECHO, INPUT);
attachInterrupt(digitalPinToInterrupt(SEND), time_send, RISING);
attachInterrupt(digitalPinToInterrupt(ECHO), time_echo, RISING);
}
void loop() {
telapsed = techo - tsend;
if (telapsed > 100 && telapsed < 10000000) {
treal = telapsed;
Serial.println(treal);
}
}
void time_send() {
tsend = micros();
}
void time_echo() {
techo = micros();
}
Below is the signal (yellow) which has a lot of noise. I need to ignore the interrupts when the signal is HIGH. Here is an image of the PWM Signal
I would try the following:
#define DEBOUNCE_TIME 100
void time_send() {
static long last = micros() ;
if (last-tsend > DEBOUNCE_TIME)
tsend = last;
}
void time_echo() {
static long last = micros() ;
if (last-techo > DEBOUNCE_TIME)
techo = last;
}
And adjust DEBOUNCE_TIME until I get a satisfactory result.
const byte intrpt_pin = 18;
volatile unsigned int count = 0;
#define DEBOUNCE_TIME 5000
void isr()
{
cli();
delayMicroseconds(DEBOUNCE_TIME);
sei();
count++;
}
void setup()
{
pinMode(intrpt_pin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(intrpt_pin), isr, FALLING);
}
void loop()
{
}
cli() : Disables all interrupts by clearing the global interrupt mask.
sei() : Enables interrupts by setting the global interrupt mask.
So, basically this program will ignore all the interrupt that occurs between these two lines, that is for DEBOUNCE_TIME.
Check your your interrupt bouncing time and adjust DEBOUNCE_TIME accordingly for the best result.

Resources