Measuring frequency with Arduino - c++

I am working on a small project for measuring input square wave frequency using Arduino, I did it using both timer and hardware interrupts and here is my code:
#include <TimerOne.h>
long count1=0,freq1=0;
void setup(){
attachInterrupt(5,count,RISING);
Timer1.initialize(1000000); //increments count for 1 sec and prints out count
Timer1.attachInterrupt( freq ); // attach the service routine here
Serial.begin(9600);
}
void loop(){
while(freq1)
Serial.println(freq1);
}
void count()
{
count1++;
}
void freq(){
freq1 = count1;
count1=0;
}
The problem is that output value is almost double the input frequency,
I don't know what's wrong with it. I learned about interrupts after an intensive Google search. Seems it didn't work.

There is a working example here.
It uses native ISR functions (faster) instead of arduino interrupt handlers.
Uses Timer1 for best resolution and precision.
The code is big but the part that interests you is:
The "// Setup Timer1 for precise timing" portion of void setup()
ISR(TIMER1_OVF_vect) -> for timer1 overflow counter
ISR(INT0_vect) // External Interrupt pin 2 [D2]
void PulseCaptureScheduler_callback() // Starts a capture and flags a timeout
void PrintInfoScheduler_callback() // Processes the results

Related

Can't update data through the Loop

I'm currently working on an EEG system using the Arduino. The purpose of the system is to vibrate a vibrator for .1 seconds, wait .5 seconds, and then vibrate again for .1 seconds. However from the start I want it to read the EEG (Serial.println(brain.readCSV()); Serial.println(brain.readErrors());) every .1 seconds from the start.
The problem is that it only takes one sample and just repeats it throughout the process until it cycles, instead of continuously updating through the loop.
How can I get it to continuously read the new data while the entire system is operating.
#include "Brain.h"
#include <SPI.h>
#include <Wire.h>
int n=0;
int m=0;
// Set up the brain parser, pass it the hardware serial object you want to listen on.
Brain brain(Serial);
int vib = 5;
void setup() {
// Start the hardware serial.
Serial.begin(9600);
pinMode(vib, OUTPUT);
}
void loop() {
// Expect packets about once per second.
// The .readCSV() function returns a string (well, char*) listing the most recent brain data, in the following format:
// "signal strength, attention, meditation, delta, theta, low alpha, high alpha, low beta, high beta, low gamma, high gamma"
if (brain.update()) {
Serial.println(brain.readCSV());
Serial.println(brain.readErrors());
if(brain.readSignalQuality() == 0) {
// Vibrate
digitalWrite(vib,HIGH);
Serial.println(brain.readCSV());
Serial.println(brain.readErrors());
delay(100);
while (n<500){
n=n+100;
digitalWrite(vib,LOW);
Serial.println(brain.readCSV());
Serial.println(brain.readErrors());
Serial.println(n);
delay(100);
}
digitalWrite(vib,HIGH);
Serial.println(brain.readCSV());
Serial.println(brain.readErrors());
delay(100);
while (m<10000){
m=m+100;
digitalWrite(vib,LOW);
Serial.println(brain.readCSV());
Serial.println(brain.readErrors());
Serial.println(m);
delay(100);
}
n=0;
m=0;
}
}
}
As Delta_G says in the comments, you need to be calling brain.update() each time you want new data. Looking at the source code for Brain.cpp, notice that "readErrors" just returns a variable that only changes after you run update() (and readCSV runs sprintf on a bunch of variables that also get updated in update()). This implies that readErrors and readCSV don't actually pull new data.

Arduino Nano - Why are my pins behaving the way they are?

I have a device that measures radiation, using an Elegoo Uno (knockoff Arduino brand) and an RM-60 Radiation Monitor from Aware Electronics. I have had this working for almost a year and a half as part of a high-altitude balloon payload item at my university. I am currently revisiting it, as now I want to understand and cleanup my code.
The setup goes like this:
The RM-60 has four wires. Yellow and black go to ground, red to my 5v, and the green goes to my output (More documentation can be found online).
I have a pin attached to digital 2. I had read online that pins 2 & 3 can use attachInterrputs for the Uno. But for whatever reason, setting my pinMode() to 2 won't work. I have found that when I set my pin to 8, with my actual wire connecting to digital 2, I can read it fine.
This is what I am confused about. I felt that after learning how these inputs work, I am doing it right. But it's not working. So then why, when my pin set to 8, is the device running correctly? If I am doing this wrong (or inefficiently), what tips or pointers can you give me on how to optimize/repair this?
I have my previous code, compiled and tested from almost two years ago. It works as is, but I just don't understand why. I have looked online for similar projects, as several balloon teams around the world have used RM-60s to measure radiation. Following their pin layout and program, I have been unsuccessful.
//this is taking just the necessary lines to run the geigercounter.
//using geigerPin 8, it works. But why not when I change this to 2, where my
//wire actually is?
int count;
int geigerPin = 8;
int testVar = 0;
void setup() {
Serial.begin(9600);
pinMode(geigerPin, OUTPUT);
attachInterrupt(0, test, RISING);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println(count * 6);
count = 0;
delay(10000);
}
void test() {
count++;
}
The data reads back to the Serial monitor every 10 seconds. The returned result should be the counts over ten seconds, multiplied by 6 to give us a counts-per-minute reading.
Please refer to the manual befor using any functions. The manual clearly states that your approach is not going to work.
From the Arduino Reference Manual:
attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) (recommended)
attachInterrupt(interrupt, ISR, mode) (not recommended)
attachInterrupt(pin, ISR, mode) (Not recommended. Additionally, this
syntax only works on Arduino SAMD Boards, Uno WiFi Rev2, Due, and
101.)
Example Code
const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, CHANGE);
}
void loop() {
digitalWrite(ledPin, state);
}
void blink() {
state = !state;
}

Arduino Measuring PWM with attachInterrupt()

Can someone explain the flow of this Arduino program shown below?
volatile int pwm_value = 0;
volatile int prev_time = 0;
void setup() {
Serial.begin(115200);
// when pin D2 goes high, call the rising function
attachInterrupt(0, rising, RISING);
}
void loop() { }
void rising() {
attachInterrupt(0, falling, FALLING);
prev_time = micros();
}
void falling() {
attachInterrupt(0, rising, RISING);
pwm_value = micros()-prev_time;
Serial.println(pwm_value);
I understand that PWM means looking for the length of time the signal remains high for each cycle.
In void setup(), the first rising edge of the signal will trigger the void rising(). So during void rising() the signal is at HIGH and prev_time = micros() is measuring the time of the signal at high (pulse width) right?
Then once the falling edge of the signal comes in, the attachInterrupt() function in void rising() will trigger void falling(). At this point the signal is at LOW, so micros() in void falling() is measuring the time of the signal at low? Then that will make no sense to take pwm_value = micros()-prev_time.
This will only make sense if prev_time is the measurement of the signal at LOW and micros() is the measurement of the period of the signal. Then pwm_value = micros()-prev_time is correct.
Based on my explanation, please explain to me what I am not getting.
This code will wait for a rising edge. Once the signal goes high it will store the current time in prev_time and start waiting for the signal to drop low. Once a falling edge is detected it will print the difference between prev_time and the current time which is your on-time in microseconds.
pwm_value is a misleading name. This is just a time measurement which is not related to PWM per se. PWM values are usually duty cycles. The on-time alone does not give you any information in terms of PWM. You further need the off-time or the total time to know the duty cycle.
As cleblanc mentioned in his comment using serial prints in an ISR is not very good.

C++ buzzer to play piano notes for an Arduino

unsigned long t;
boolean isHigh;
#define BUZZER_PIN 3
void setup() {
// put your setup code here, to run once:
pinMode(BUZZER_PIN, OUTPUT);
isHigh = false;
t = micros();
}
void loop() {
playNote('c');
}
void playNote(char note) {
unsigned long timeToWait;
unsigned long timeToPlayTheNote = millis();
while (timeToPlayTheNote - millis() < 1000) {
if (note == 'c') {
timeToWait = 1911;
}
if (micros() - t > timeToWait) {
if (!isHigh) {
digitalWrite(BUZZER_PIN, HIGH);
isHigh = true;
} else {
digitalWrite(BUZZER_PIN, LOW);
isHigh = false;
}
t = micros();
}
}
}
I don't know why this won't work. I used to play a frequency every 1,000 microseconds but is there any way to make this simpler as well? Also, with this method I have to do (1/f)/2 and then convert that value from seconds to microseconds and use that as the value for timeToWait.
Initialization of ˋtimeToWait` should obviously be outside of the loop.
An array could be used for timing data.
ˋt` should probably be initialized inside ˋplayNoteˋ
Alternatively, you might use an enum for delay associated to a note.
enum class notes
{
C = 1911
};
Well, all suggestion assume that you don't want to compensate for drifting offsets.
Buzzers have a fixed frequency. They don't work like speakers at all. You will get better results with a real speaker. Don't forget to put a capacitor in series with it so the speaker sees an AC signal, you can fry a speaker quite easily if you feed it a DC signal..
For best results, you should use 2 x 47uF to 100uF electrolytic capacitors back to back, with the negative poles joined together, one positive to the 'duino and the other positive pole connected to the speaker. With higher capacitance, you'll get more bass.
Why don't you use a PWM at 50% (128) and change the PWM frequency to generate the sound? You could use the Timer1 or Timer3 library for that. Letting the hardware do the work would be more presise and would free your application for other tasks, such as reading a keyboard.
https://playground.arduino.cc/Code/Timer1
Setting the PWM at 0% with an analogWrite() would cut the sound.

Arduino timed void draw() loops

I have an Arduino Uno set up to sense the light level and draw to a text file via Processing when it gets dark. I'd like to modify the Processing code to interrupt the draw loop for five seconds and then restart the draw loop. This will continuously write and overwrite the .txt file but that's not important right now.
The purpose of this excercise is to understand how to insert a break into the endless draw loop. I'm still very much a newbie to programming and am trying to wrap my head around how commands interact with eath other. Can anyone help me understand how to make this work? Eample code would be great but I'd also be happy with a conceptual description of how it's supposed to work...learn by doing and all.
I've tried putting the void draw() loop within a void loop() but it erred out. Am I on the right path?
<setup...mySerial and createWriter to path/file.txt>{
}
void draw() { //this is what needs to terminate & restart
if (mySerial.available() > 0 ) {
String value = mySerial.readString();
if ( value != null ) {
output.println( value );
}
}
}
void keyPressed and end
I believe what you're looking for is called a "state machine".
Make a variable that you can use to store a time value, then compare that to the current time to see if 5s have passed.
uint32_t last_trigger = 0; // millis() returns an unsigned, 32-bit integer
void setup()
{
Serial.begin(9600);
}
void loop()
{
if (millis() - last_trigger > 5000) { // 5000 milliseconds
last_trigger = millis(); // update last_trigger
Serial.print("last triggered at "); // report findings
Serial.print(last_trigger);
Serial.println(" milliseconds");
}
}
http://www.arduino.cc/en/Reference/Millis
If you aren't worried about really tight timing, the easy solution is to use the delay function. http://www.arduino.cc/en/Reference/Delay
The following might be a simple sketch that would do what you want. Adjust it as needed.
void setup()
{
Serial.begin(9600); // initialize serial routines
}
void loop()
{
int a = analogRead(0); // read the value of lightness
Serial.println(a); // tell processing what the value is
delay(5000); // wait for a 5 seconds
}