Arduino Uno Radar gun

I am currently attempting to build an Arduino Uno radar gun for a science fair project, and I believe that I have it properly built. However, I am using code that doesn’t appear to work, and I was wondering what the issue is. My problem is that it isn’t collecting and storing the data properly. What could cause this? This is the code I’m working with.

#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);




//Code was borrowed and improved upon from Arduino Forum user RussA, thanks to RussA.
// These are the counts needed for 250 msec interrupt
// using the timer prescaler settings set to 128.
const uint16_t TICK_CNT = 34286; // 65536-(16MHz/128/4Hz)  
static uint16_t freq = 0;
double sped = 0; //"speed" seems to be a reserved term

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

  noInterrupts();                     // disable all interrupts while we configure  
  // init Timer1 - 16-bit timer/counter
  TCNT1   = 0;                                  // start count at zero.        
  TCCR1B  |= _BV(CS12) | _BV(CS11) | _BV(CS10); // Increment T1 input on each positive edge 
                                                // using an external source. Table 16-5, pg 139.
  
  // init Timer2 - 8-bit timer/counter
  TCNT2   = TICK_CNT;                 // preload Timer2 to interrupt every 250 msec
  TIMSK2  = _BV(TOIE2);               // enable the Timer2 overflow interrupt 
  TCCR2B  |= _BV(CS22) | _BV(CS20);   // init clock prescaler to 128. Table 18-9, page 164.
  interrupts();                       // enable all interrupts
  
  Serial.println("Ready...");
}

ISR(TIMER1_OVF_vect) {
  // do nothing. this is just a dummy ISR in case it actually overflows.
  Serial.println("Inside Timer1 Overflow Interrupt.");
}

ISR(TIMER2_OVF_vect) {
  //Serial.print("TCNT1: ");
  //Serial.println(TCNT1);
  freq = TCNT1;
  //Serial.println(freq);
  TCNT1 = 0;
  TCNT2 = TICK_CNT;
}

void loop() {
  
  if (freq != 0) {
      freq = freq << 2;      // multiple the frequency * 4 (using leftshift 2 places). 250ms*4 = 1 sec.
      sped = freq * .03225;  // multiplying freq * 0.0325 will give speed in mph. 31Hz == 1 mph.
                             // see: http://www.microwave-solutions.com/contents/en-uk/d13_System_Design.html
      Serial.print("Freq: ");
      Serial.print(freq, DEC);
      Serial.print(" Hz, Speed: ");
      Serial.print(sped, 3);
      Serial.println(" mph");
      // Turn off the display:
 
  }
}

Thank you so much for your input, I really appreciate it.

Please explain what you mean by "it isn't collecting and storing the data properly". There's nothing in your code that would store data.

You need to make any global variable that's modified in an ISR volatile.

It's also odd that you include the LiquidCrystal library but then never actually use it.

I’m trying to collect input data from an HB100 sensor and store that data in a pop up window type thing, in order to read the input. So what would I need to actually store the data? I was thinking the .Println would do that. I’m kind of new to this. Thanks so much.

freq needs to be volatile.

TCNT2 is an 8-bit register. It's an 8-bit counter, and that's the current count.

You are writing 34286 to it, but that can't be represented in fewer than 16 bits. So the 8 high bits are being lost, and the TCNT2 is being set to whatever the low bits of that are. This can't be what was intended.

Serial.println() does not store data. It prints data to Serial. Most often it's used in combination with the Arduino IDE's Serial Monitor (Tools > Serial Monitor).

Okay, so what I need to do is declare that volatile and set TCNT 2 to 16 bits?
I made these changes

#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);




//Code was borrowed and improved upon from Arduino Forum user RussA, thanks to RussA.
// These are the counts needed for 250 msec interrupt
// using the timer prescaler settings set to 128.
const uint16_t TICK_CNT = 34286; // 65536-(16MHz/128/4Hz)  
static uint16_t freq = 0;
double sped = 0; //"speed" seems to be a reserved term
volatile static uint16_t state = LOW; //added this

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

  noInterrupts();                     // disable all interrupts while we configure  
  // init Timer1 - 16-bit timer/counter
  TCNT1   = 0;                                  // start count at zero.        
  TCCR1B  |= _BV(CS12) | _BV(CS11) | _BV(CS10); // Increment T1 input on each positive edge 
                                                // using an external source. Table 16-5, pg 139.
  
  // init Timer2 - 8-bit timer/counter
  TCNT2   = TICK_CNT;                 // preload Timer2 to interrupt every 250 msec
  TIMSK2  = _BV(TOIE2);               // enable the Timer2 overflow interrupt 
  TCCR2B  |= _BV(CS12) | _BV(CS11) | _BV(CS10);   // init clock prescaler to 128. Table 18-9, page 164. Change made here
  interrupts();                       // enable all interrupts
  
  Serial.println("Ready...");
}

ISR(TIMER1_OVF_vect) {
  // do nothing. this is just a dummy ISR in case it actually overflows.
  Serial.println("Inside Timer1 Overflow Interrupt.");
}

ISR(TIMER2_OVF_vect) {
  //Serial.print("TCNT1: ");
  //Serial.println(TCNT1);
  freq = TCNT1;
  //Serial.println(freq);
  TCNT1 = 0;
  TCNT2 = TICK_CNT;
}

void loop() {
  
  if (freq != 0) {
      freq = freq << 2;      // multiple the frequency * 4 (using leftshift 2 places). 250ms*4 = 1 sec.
      sped = freq * .03225;  // multiplying freq * 0.0325 will give speed in mph. 31Hz == 1 mph.
                             // see: http://www.microwave-solutions.com/contents/en-uk/d13_System_Design.html
      Serial.print("Freq: ");
      Serial.print(freq, DEC);
      Serial.print(" Hz, Speed: ");
      Serial.print(sped, 3);
      Serial.println(" mph");
      // Turn off the display:
 
  }
}

I keep getting this in my Serial Monitor, what does it mean?

&⸮⸮⸮mF⸮H|01"⸮ ⸮

Granti:
I made these changes

…yet you still didn’t make freq volatile after two people told you that was necessary.

Granti:
I keep getting this in my Serial Monitor, what does it mean?

&⸮⸮⸮mF⸮H|01"⸮ ⸮

It probably means you have a baud rate mismatch between the Arduino and the Serial Monitor. This line of your code causes the Arduino to communicate at 115200 baud:

Granti:

  Serial.begin(115200);

You need to set Serial Monitor to also communicate at 115200 by choosing that setting from the menu near the bottom right corner of the window.

I thought I did make it volatile? Isn't it the static uint16_t? I get an error when I try just the freq. How would i go about doing that? Also that made a big difference in my results, thank you.

You added a new volatile variable named state that is never used anywhere in the code. You did not make freq volatile.

https://www.arduino.cc/reference/en/language/variables/variable-scope--qualifiers/volatile/

Granti:
I thought I did make it volatile? Isn't it the static uint16_t? I get an error when I try just the freq. How would i go about doing that?

This is your code

[color=blue]static uint16_t[/color] freq = 0;
double sped = 0; //"speed" seems to be a reserved term
[color=red]volatile[/color] [color=blue]static uint16_t[/color] state = LOW; //added this

Do you happen to see a difference ?

(Also static is not needed for those global variables)

I'm afraid I don't, what are you getting at?

How can you think you made the freq variable volatile ?

The global variables don't need to be static.

volatile uint16_t freq=0;
or
volatile static uint16_t freq=0;

You have

static uint16_t freq=0;

This does not declare freq as volatile, and I'm unsure how you might think it does.

You also have not addressed the TCNT2 issue I mentioned before. You cannot make TCNT2 16-bit without using a different microcontroller - timer2 is an 8-bit timer; all you have available is 2 8-bit timers (0 and 2, the former of which is used for millis and delay) and a 16-bit timer.

This is not a "simple" fix (which is why I didn't tell you what to do, it's non-trivial - if you want me to figure it out, and write the code for it - I'm happy to do that.... for $50/hr) - you need to understand what they were doing here - they're setting the timer count to a value that will result in an overflow in 250ms. Unfortunately, with timer2, you can't do that - with a prescaler at the maximum of 1024, you can't get more than like 1.5ms per overflow (quick approximation).

I just don't see how this could have EVER worked on an atmega328p. On an atmega328pb, or attiny841, or atmega1284p, or atmega2560 - sure (except for the t841 - which is weird and has the second 16-bit timer as timer2, while the atmega series has timer2 as an 8-bit async timer and any additional 16-bit timers as timers 3/4/5), the code would need to be adapted to use timer3). But not an atmega328p!

It seems to me that you took code for a different processor and adapted it to the 328p without understanding the code well enough to recognize the hardware requirements of said code.

I really appreciate the help. I'm new to this, and honestly expected this to be much simpler. I'll try to figure it out. Thanks so much

ISR(TIMER1_OVF_vect) {
  // do nothing. this is just a dummy ISR in case it actually overflows.
  Serial.println("Inside Timer1 Overflow Interrupt.");
}

Don't do serial I/O in interrupt context.

Timer/Counter 1 has three control registers:
TCCR1A
TCCR1B
and
TCCR1C
You set three bits in TCCR1B and assume all the other bits are already set for you. That may not be a safe assumption.

You should also set the Interrupt Mask Register to disable the interrupts since you don't need them.

Try:

   // Count external rising edges on Timer/Counter 1 
  TCCR1A = 0;  // Waveform Generation Mode: Normal (just count)
  TCCR1B = _BV(CS12) | _BV(CS11) | _BV(CS10);  // Clock Select: External, Rising Edge
  TCCR1C = 0;
  TIMSK1 = 0;  // Turn off Timer/Counter 1 interrupts

Because Timer/Counter 2 is an 8-bit timer and the prescale factors only go to 1024, you can't get an interrupt frequency below 61.035 Hz (16 MHz / 1024 / 256). 16 MHz/1024 is 15625 Hz. You can divide that by any value from 1 to 256 but since 15625 is 5^6 the only divisors that give an integer frequency are 1, 5, 25, and 125. (15625 Hz, 3125 Hz, 625 Hz, and 125 Hz). At 125 Hz you could sample every 5 interrupts to get a sample rate of 5 Hz. That's close to 4 Hz.

Curious if this project was completed successfully. If so, would you mind sharing the code and components list? Long story short, I have a small child and speeders going by constantly and want to inform the police of speeders. Thank you!

gogogowa:
Curious if this project was completed successfully. If so, would you mind sharing the code and components list? Long story short, I have a small child and speeders going by constantly and want to inform the police of speeders. Thank you!

You might have better luck following a completed project like this one: https://www.youtube.com/watch?v=Kzsh59TM4MY