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;
}
Related
So I am trying to create a program that runs various light sequences using an Arduino board. I am not very familiar with C++ so I feel that my lack of syntax knowledge is preventing me from accomplishing my goal.
My idea is to have various light sequences that are played depending on what button is pressed on an infrared remote. The amount of time that a light is on or off may or may not be the same as that of another light. Unfortunately, the sequences do not seem to be working which indicates that the issue is likely with the toggleLight function.
I also wanted there to be a button that allows the user to pause the sequence (no matter where along the sequence it is). And once the button is pressed again, then the sequence continues where it left off. I read something about an interrupter and sleep mode using C++ but I am unfamiliar with this so it is not included in my code.
The rest of my goals I have included within my code. I created an object "light" because I was trying to create the sequence without using the delay function as the interrupt does not work well with the delay function (as far as I am aware). Then I am able to call the function toggleLight on the specific light object. However, as I previously stated the sequences are not working.
I am more familiar with OOP languages so perhaps creating an object is not the best for Arduino. If anyone has any ideas for how I can accomplish my goal it would be much appreciated.
unsigned long previousMillis = 0;
unsigned long currentMillis = millis();
//sets up the Infrared receiver for the remote controller
const int RECV_PIN = 1;
IRrecv irrecv(RECV_PIN);
decode_results results;
//Sets up the LED's pin number and light status
class light{
private:
int _pinNumber;
byte _Lstatus;
public:
//function that creates the objects with the parameters
light(int pinNum, byte Lstat){
_pinNumber = pinNum;
_Lstatus = Lstat;}
void toggleLight(long interval){
//ensures that the "interval" amount of time has passed between the last LED blink
if ((currentMillis - previousMillis) >= interval) {
// if the LED is off turn it on and vice-versa:
if (_Lstatus == LOW) {
_Lstatus = HIGH;
} else if (_Lstatus == HIGH) {
_Lstatus = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(_pinNumber, _Lstatus);
// save the last time you blinked the LED
previousMillis = currentMillis;
}
}
};
//creating four light objects with the pins and initial status of off.
light J1(13, LOW);
light J2(11, LOW);
light P1(12, LOW);
light P2(10, LOW);
void setup()
{
pinMode(13, OUTPUT);
pinMode(12, OUTPUT);
pinMode(11, OUTPUT);
pinMode(10, OUTPUT);
}
//Sequence 1 is a mock sequence. It will probably be longer and the intervals would not all be 1000
void seq1(){
currentMillis = millis();
J1.toggleLight(1000);
P1.toggleLight(1000);
J1.toggleLight(1000);
P1.toggleLight(1000);
J2.toggleLight(1000);
P2.toggleLight(1000);
}
void seq2(){
currentMillis = millis(); //I found that placing currentMillis = millis() here allows the lights to at least turn on
J1.toggleLight(2000);
J1.toggleLight(10);
P1.toggleLight(1000);
P1.toggleLight(0);
J2.toggleLight(1500);
J2.toggleLight(1);
P2.toggleLight(2000);
P2.toggleLight(1);
}
void loop()
{
/* So once i get the sequences working, my idea is to have different sequences play
depending on what button on the remote is pressed. However, first I want to get the sequences and
interrupter
For now I have just tried running sequence #2 but it does not work.. Neither does Sequence #1. */
seq2();
//I MADE THESE LINES OF CODE COMMENTS FOR NOW. UNTIL I GET THE REST OF THE PROGRAM WORKING
/*if (irrecv.decode(&results))
{
switch (results.value) {
case : 0xf00000 // When button #1 sequence one plays
seq1();
break;
case : 0xf00000 // when button #2 is pressed, sequence two plays
seq2();
break;
*/
}
I can see that you haven't yet got around to understanding the flow of code inside the Arduino. Here's a quick tutorial to get you up and running.
Basically, your code is not being processed sequentially. So when the processor is moving through seq() and gets to the first if statement in 'J1.toggleLight(2000);' and finds that the condition is not met (i.e. the 2000 milliseconds have not yet passed,) it immediately moves on to the second line in seq(). The issue with this is that when it does meet the condition at the second line it will reset the 'previousMillis' value which all the lights depend on.
Thus you should dedicate a clock for each light by moving in 'previousMillis' into the class as a member.
class light{
private:
int _pinNumber;
byte _Lstatus;
unsigned long previousMillis = 0;
This way each light will be able to keep track of its own time without conflicting with the other lights. This will lead to your lights flickering at a frequency of 1/interval which I doubt is what you want.(it wont even do that with each light getting toggled twice in the seq() functions. Try removing the second calls and see hat happens) This brings me to the second issue.
The second issue is with the way you set up your sequences. Since you want to the lights to operate sequentially you'll need to find the accumulated time which crosses out the chance of using a class, unless you're willing to implement a scheduling mechanism that takes account the interval and arrangement of each instance. Seems a bit impractical imo.
I think you should ditch the class and use a simple function that that accepts the eight values that each sequence requires. Then you could utilize if statements to manipulate the states of the lights.
I hope the answer made some sense.
Good luck.
Im trying to generate a knock knock detector using Arduino and a Piezo Buzzer. The one used in this proyect is the same as in this picture
Using this code
const int outputPin = 8; // led indicator connected to digital pin
const int knockSensor = A0; // the piezo is connected to an analog pin
const int thresholdHIGH =150; // threshold value to decide when the detected knock is hard (HIGH)
const int thresholdLOW = 120; // threshold value to decide when the detected knock is gentle (LOW)
const int secretKnockLength = 4; //How many knocks are in your secret knock
/* This is the secret knock sequence
* 0 represents a LOW or quiet knock
* 1 represents a HIGH or loud knock
* The sequence can be as long as you like, but longer codes increase the difficulty of matching */
const int secretKnock[secretKnockLength] = {0, 0, 1, 0};
int secretCounter = 0; //this tracks the correct knocks and allows you to move through the sequence
int sensorReading = 0; // variable to store the value read from the sensor pin
void setup() {
//Set the output pin as an OUTPUT
pinMode(outputPin, OUTPUT);
//analogWrite(knockSensor, LOW);
//Begin Serial Communication.
Serial.begin(9600);
}
void loop() {
// read the piezo sensor and store the value in the variable sensorReading:
sensorReading = analogRead(knockSensor);
Serial.print ("Valor del Sensor: ");
Serial.println(sensorReading);
// First determine is knock if Hard (HIGH) or Gentle (LOW)
//Hard knock (HIGH) is detected
if (sensorReading >= thresholdHIGH) {
//Check to see if a Hard Knock matches the Secret Knock in the correct sequence.
if (secretKnock[secretCounter] == 1) {
//The Knock was correct, iterate the counter.
secretCounter++;
Serial.println("Correct");
} else {
//The Knock was incorrect, reset the counter
secretCounter = 0;
Serial.println("Fail");
digitalWrite(outputPin, LOW);
}//close if
//Allow some time to pass before sampling again to ensure a clear signal.
delay(100);
//Gentle knock (LOW) is detected
} else if (sensorReading >= thresholdLOW) {
//Check to see if a Gentle Knock matches the Secret Knock in the correct sequence.
if (secretKnock[secretCounter] == 0) {
//The Knock was correct, iterate the counter.
secretCounter++;
Serial.println("Correct");
} else {
//The Knock was incorrect, reset the counter.
secretCounter = 0;
Serial.println("Fail");
}//close if
//Allow some time to pass before sampling again to ensure a clear signal.
delay(100);
}//close if else
//Check for successful entry of the code, by seeing if the entire array has been walked through.
if (secretCounter == (secretKnockLength) ) {
Serial.println("Welcome");
//if the sececret knock is correct, illuminate the LED for a couple seconds
digitalWrite(outputPin, HIGH);
//Reset the secret counter to 0.
secretCounter = 0;
}//close success check
}//close loop".
My problem is the buzzer is detecting nothing. I dont know if this is because the buzzer is not the correct one or something else.
Any idea?
If the problem is that the buzzer isn't making any noise, then you should be using the tone() function in your code. (https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/)
Your code compiles successfully, so if that's not your issue, then there's probably something wrong with your project's wiring.
To detect knocking, you need to use piezo without driver circuit.
according to Arduino tutorial said that avoid piezo with plastic housing.
You should use piezo that look like metal disc like this
(image from sparkfun)
Note : piezo with plastic housing might contain drive circuit or not piezo at all (it might be magnetic buzzer)
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
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
}
I am trying to implement a simple timer1 example that I saw on YouTube: http://youtu.be/Tj6xGtwOlB4?t=22m7s . The example was in c++ for stand alone ATMEGA328 chip and I am trying to get it to work on the Arduino UNO. Here is my working code:
void setup() {
//initialize port for LED
DDRB = 0b11111111; //initialize port B as output (really only care about 5th bit)
PORTB = 0b00000000; //set ouput values to zero
TCCR1A = 0; //clear control register A (not sure that I need this)
TCCR1B |= 1<<CS10; //no prescaler, turns on CS10 bit of TCCR1B
}
void loop() {
if (TCNT1 >= 255){
TCNT1 = 0; //resets timer to zero
PORTB ^=1<<PINB5; //1<<PINB5 is same as 0b00100000, so this toggles bit five of port b which is pin 13 (red led) on Arduino
}
}
Everything is working, but TCNT1 will only count up to 255. If I set the value in the if-statement to anything higher, the code in the if statement is never executed. Timer1 should be a 16-bit timer, so it does not make sense why the count stops at 255. Is arduino doing something behind the scenes to mess this up? It seems to work just fine in the example on youtube (without arduino).
First of all.... Why do you set the registers? Arduino's only benefit is that it wraps up some functions, so why not use it? Instead of
DDRB = 0b11111111;
PORTB = 0b00000000;
...
PORTB ^=1<<PINB5;
use simply
int myoutpin = XXXX; // Put here the number of the ARDUINO pin you want to use as output
...
pinMode(myoutpin, OUTPUT);
...
digitalWrite(myoutpin, !digitalRead(myoutpin));
I think that probably there are some similar functions for the timer too..
As for your question, I tried this code:
// the setup routine runs once when you press reset:
void setup() {
TCCR1A = 0; //clear control register A (not sure that I need this)
TCCR1B |= 1<<CS10; //no prescaler, turns on CS10 bit of TCCR1B
Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
if (TCNT1 >= 12000){
TCNT1 = 0; //resets timer to zero
Serial.println("Timer hit");
}
}
in a simulator and it works well; I should try it with a real Arduino, but I haven't any at the moment... As soon as i get one I'll try to use it
I've encountered the same problem, in the Atmel documentation, I found that other pins influence the counter mode. That is, the pins: WGM13,WGM12,WGM11,WGM10 are 0,1,0,0 respectively, the counter will be in CTC mode, meaning that it will count up to the value of OCR1A instead of (2^16-1) which might be the case in your code.
WGM11,WGM10 are bits 1,0 in TCCR1A and WGM13,WGM12 are bits 4,3 in TCCR1B so setting them to zero should do the job.
I had some thing like this with one of my code. I could not able to find the exact reason for the issue. At last I remove both setup and loop function an replace those with c code.
Then it work fine. If you need those function then start code by clear both TCCR1A and TCCR1B register. I hope this is happened due to Arduino IDE not sure. But it works.