Arduino analogWrite() causes program to freeze - arduino

I am writing some Arduino code that is meant to control my 3D printed robot at a basic level. Everything works fine until the value that I analogWrite() to ledPin (pin 11 on the Nano) is no longer 0. The purpose of this bit of code is to fade some leds ON/OFF based on ambient lighting without using delay() function that pauses the program.
The code here determines whether the ambient light is below threshold, wheter 4 milliseconds have passed and whether the LEDs are at their target brightness yet, then increments/decrements the value to analogWrite() accordingly. It's when this value (lightVal) increases that the whole program freezes and remains in the state it was just before freezing. (The robot becomes unresponsive and serial data stops getting sent.) The moment I comment out the analogWrite(), the freeze does not occur.
timer = millis();
aLightVal = analogRead(LDR);
aLightVal = map(aLightVal, 0, 600, 0, 100);
//Check to see if the ambient light is below threshold
//If LED is not yet at target brightness, fade every 4 milliseconds
if (aLightVal < 40){
if (timer - currentTime > 4){
if (lightVal < 255){
lightVal++;
currentTime = timer;
}
}
}
if (aLightVal >= 40){
if (timer - currentTime > 4){
if (lightVal > 0){
lightVal--;
currentTime = timer;
}
}
}
analogWrite(ledPin, lightVal);
Serial.println(aLightVal);
I am using the Servo.h as well as the Ultrasonic.h libraries in the program if that helps?
I initialised the variables as follows:
const int LDR = A1;
const int ledPin = 11;
unsigned long timer = 0;
unsigned long currentTime = 0;
int aLightVal;
int lightVal = 0;
Any advice? Please let me know, I would really appreciate it!

Related

Arduino Interrupt getting triggered more than once - Working with Hall Sensor for RPM

I am working with an hall sensor for counting the RPM of my wheel. I am using following sensor :
My code as follows :
int hall_pin = 3; // digital pin
float hall_threshold = 5.0;
float count = 0;
void setup() {
pinMode(hall_pin,INPUT);// put your setup code here, to run once:
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(hall_pin),hall_ISR,RISING);
}
void loop() {
count = 0.0;
float start = micros();
while(1){
if(count >= hall_threshold){
break;
}
}
float end_time = micros();
float time_passed = (end_time - start)/1000000.0; // in seconds
float rpm = (count/time_passed)*60.0;
Serial.println(rpm);
delay(10000);
}
void hall_ISR()
{
count+=1.0;
}
I am using digital pin 3 to read from sensor and count the number of times it detects magnetic field using interrupt. Since the sensor outputs 1 on detecting, I have used a RISING interrupt. Once the count is greater than 5 then the control comes out of the infinite loop and calculates the RPM. The problem is this interrupt is getting triggered multiple times. I have tried using detachInterrupt(hall_pin) but it is not working. I also tried to decrease the sensitivity of hall sensor using the trimmer provided.
I am sure the problem is not with the sensor, it is with the interrupt, I guess. Where am I going wrong?
Any help is very much appreciated!
Thank you.

Creating an oscillating tone using Arduino, ATTiny85 and a simple buzzer

First a bit of background. I am attempting to make an LED glow and a buzzer produce a tone that sweeps smoothly up and down in frequency, like an air raid siren. I am using an Arduino Uno, connected to an ATTiny85 chip operating at 8hz clock speed. An SPDN contact switch is used to provide input on 4, while 0 and 1 go out to the positive legs of the buzzer and LED respectively. Suitable resistors are being used to limit current, which is 5v from the Arduino board.
Now, my problem. I can produce a constant tone at any frequency I like. I can produce a tone that goes back and forth between two tones like a UK police siren (Dee-Daa-Dee-Daa etc) but I am unable to generate a smooth transition between two tones. The LED works as expected.
What I actually observe is a single tone that does not vary. Once or twice I've managed to produce a tone that varies, but randomly within the given range rather than smoothly.
I am not using the tone() Arduino command and would prefer not to, as it is not best suited for what I am trying to accomplish.
Here is my code:
const float pi2 = 6.28318530717;
const int buzzer = 0;
const int light = 1;
const int button = 4;
// Set up the pins as input and output
void setup() {
pinMode(buzzer, OUTPUT);
pinMode(light, OUTPUT);
pinMode(button, INPUT);
}
bool buzzerState = LOW;
float nextFlip = 0;
// Generates a sine wave for the given uptime, with a period and offset (in milliseconds).
float sineWave(float uptime, float period, float offset, float minimum, float maximum) {
float s = sin(((uptime + offset) * pi2) / period);
// Normalise the result between minimum and maximum
return (s + 1) / 2 * (maximum - minimum) + minimum;
}
// Returns the time between buzzer inversions based on a given system uptime.
float frequency(float uptime) {
return sineWave(uptime, 5000, 0, 1, 10);
}
// Main loop
void loop() {
// Check button state and turn the light on or off
bool buttonDown = digitalRead(button);
digitalWrite(light, buttonDown);
// Check to see if it's time for the next buzzer inversion
float m = micros();
if (!buttonDown || m < nextFlip) return;
// Get the inverse of the current buzzer state
if (buzzerState == HIGH) {
buzzerState = LOW;
} else {
buzzerState = HIGH;
}
// Write the new buzzer state
digitalWrite(buzzer, buzzerState);
// Decide when the next inversion will occur
nextFlip = m + frequency(m);
}
Silly mistake! I finally noticed: I'm reading micros() where I meant to read millis() - in other words, it was oscillating, just a thousand times faster than I intended it to! Multiplying all values up by a factor of 1000 in the sine wave function produced a lovely oscillation.

pinball targets - wont reset

Im an artist, not a programmer. But i'm making a pinball game with an Arduino, and I do not have a programmer, so I'm learning what I can to make this work.
I'm trying to write a code that does this:
- 3 targets (buttons) that when hit, they give points, and light an LED.
- If the same button is hit a second time, it will still give points, and the LED stays lit.
- If ALL 3 lights are lit at the same time, there is a bonus score given, and ALL 3 lights turn off.
I tried using the Arduino forums but the best advice I could get out of them was "Go learn to code."
I have been told to learn about 'arrays' and I have tried but I'm having some serious trouble wrapping my head around it. If it is possible to do this with just 'IF' and 'ELSE' statements I would really prefer to do things the long and inefficient way.
Here is my current code. Currently I have 4 lights on my breadboard. Light #4 (D) is lit right away for debug reasons. Each of the other 3 lights (ABC) will light when their button is pushed. When All 3 lights are lit, (D) light will go out, but (ABC) remain lit. I need them to go out when (D) does. and I don't know why they wont. I know the code recognizes that all 3 are HIGH. Because (D) goes LOW. I don't know why (ABC) won't go LOW as well.
// 3 TARGET SCORE FUNCTION.
// WHEN A TARGET IS HIT IT LIGHTS UP AND PROVIDES POINTS.
// IF A TARGET IS HIT AGAIN WHILE IT IS ALREADY LIT, IT STILL SCORES POINTS AND STAYS LIT.
// WHEN ALL 3 TARGETS ARE LIT THEY FLASH AND PROVIDE A JACKPOT
// WHEN JACKPOT IS PROVIDED ALL LIGHTS TURN OFF. READY TO BE ACTIVATED AGAIN.
int dropButtonA = 2; // the number of the input pin
int dropButtonB = 3;
int dropButtonC = 4;
int dropLightA = 11; // the number of the output pin
int dropLightB = 12;
int dropLightC = 13;
int dropLightD = 10;
int stateA = LOW; // the current state of the output pin
int stateB = LOW;
int stateC = LOW;
int stateD = LOW;
int readingA; // the current reading from the input pin
int readingB;
int readingC;
int previousA = LOW; // the previous reading from the input pin
int previousB = LOW;
int previousC = LOW;
long time = 0; // the last time the output pin was toggled
long debounce = 200; // the debounce time, increase if the output flickers
void setup()
{
pinMode(dropButtonA, INPUT);
pinMode(dropButtonB, INPUT);
pinMode(dropButtonC, INPUT);
pinMode(dropLightA, OUTPUT);
pinMode(dropLightB, OUTPUT);
pinMode(dropLightC, OUTPUT);
pinMode(dropLightD, OUTPUT);
}
void loop()
{
//droptarget_01//
readingA = digitalRead(dropButtonA);
if (readingA == HIGH && previousA == LOW && millis() - time > debounce) {
stateA = HIGH;
time = millis();
}
digitalWrite(dropLightA, stateA);
previousA = readingA;
//droptarget_02//
readingB = digitalRead(dropButtonB);
if (readingB == HIGH && previousB == LOW && millis() - time > debounce) {
stateB = HIGH;
time = millis();
}
digitalWrite(dropLightB, stateB);
previousB = readingB;
//droptarget_03//
readingC = digitalRead(dropButtonC);
if (readingC == HIGH && previousC == LOW && millis() - time > debounce) {
stateC = HIGH;
time = millis();
}
digitalWrite(dropLightC, stateC);
previousC = readingC;
//RESET TARGETS - BONUS SCORE
if (digitalRead(dropLightA)==HIGH && digitalRead(dropLightB)==HIGH && digitalRead(dropLightC)==HIGH)
{
digitalWrite(dropLightA, LOW);
digitalWrite(dropLightB, LOW);
digitalWrite(dropLightC, LOW);
digitalWrite(dropLightD, LOW);
}
else
{
digitalWrite(dropLightD, HIGH);
}
}
The problem is that the variable named "stateX" does not change when ABC goes LOW. You need to add these statements to the "//RESET TARGETS - BONUS SCORE" loop when the condition is true:
stateA = LOW;
stateB = LOW;
stateC = LOW;
stateD = LOW;
IMHO you do not need to use arrays when there are only four items- clarity of code (esp. to the author) has value. However, I think that the variables "stateX" and "previousX" are redundant; if you did not have both you would not have this bug.
Also, I would recommend using the previously read value of the pins for the loop test at "//RESET TARGETS - BONUS SCORE":
if (readingA == HIGH && readingB == HIGH && readingC == HIGH)
With your current code you read the values of the pins twice during the loop. In this case there is a chance the value of the pins could change during the loop and you could get really confusing results.

Using Atmega TCNT1

I'm trying to use an arduino uno to show some students how to make their own 'auto tune' however the code that I wrote is not outputting any signal. The goal is to sample values into an array at one rate and output the data from the array(FIFO)at a slower rate. My understanding is that TCNT1 increments each clock tick, I'm using 16 MHz in my case, and that I can base if logic on the value of TCNT1, I use a mod function here to take and store a single adc value and then play that value to the dac at a later time. acdT dacT represent my timing logic. I've built an external DAC to read only 8 (of 10) bit values from d0-d7 (PORTD). Why am I not seeing a signal?
int i = 0;
int j = 0;
int adcT = 328; // 329 clock tics
int dacT = 349; // 350 clock tics
int buff[15]; // 16 length buffer to store adc values
void setup ()
{
PRR &= ~(1<<PRADC); //ADC turned on
ADMUX = 0x60; //AVcc, left adjusted, ADC0 pin
ADCSRA = 0xC0;//ADC Enabled, no auto trigger
DDRD=0xFF; // set portd to d0 thru d7 digital pins
DDRC=0x00; // accept input from any analog input
TCCR1B |= 1<<CS10; // sets the clock to the system clock ie no pre scaler
}
void loop ()
{
if((TCNT1%acdT == 0) || TCNT1 == 0) // execute at 0 and mod329 clock tics
{
ADCSRA|=(1<<ADSC); // take one adc reading
while(!(ADCSRA & (1<<ADIF))); // wait until the reading is complete
ADCSRA|=(1<<ADIF); //reset adc for next command
buff[i] = ADCH; // take the adc value into the array
i++ // increment
}
if((TCNT1%dacT == 0)) %% TCNT1 ~= 0// execute at mod350 clock tics
{
PORTD = buff[j]; // send the adc reading to digital output
j++;
}
if(TCNT1 == 5262 ) // LCM/3 of 329(16samples) and 350(15samples)
{
TCNT1 = 0;// reset ticker
i = 0;
j = 0;
}
if(TCNT1 == 336)
{
PORTD = buff[15]; // play 16th adc sample to clear array
}
}
TCCR1B |= 1<<CS10; // sets the clock to the system clock ie no pre scaler
And there's your problem. You're attempting to find the modulus of a counter that runs faster than your code. Use the output capture and other features of the timer to trigger interrupts and reset the timer at the appropriate times instead of trying to catch a passing bullet with your bare hands.

how to create a 1 second delay Arduino

Hi i'm new to Arduino and i'm trying to create a 1 second delay but i don't know how i can generate a code that completes the delay_ms function
I've tried to work it out but doesn't seem to get any better
Thank you
void setup()
{
word millisecs;
Serial.begin(9600);
}
void setup() asm volatile(
" ldi r16,0x3F ; r16 = 00111111\n"
" out 4,r16 ; set pins 8-13 as outputs in DDRB\n"
::: "r16");
millisecs = 1000; // 1s blink delay
Serial.begin(9600);
}
void loop()
{
long starttime = millis(); // make a note of the start time
asm volatile(
// jump to "blink" - ie jump around the delay_ms subroutine
" rjmp blink%= ; relative jump to 'blink' \n"
" ldi r16,0x3F ; r16 = 00111111\n"
" out 4,r16 ; set pins 8-13 as outputs in DDRB\n"
::: "r16");
registers used:
r31 - millisecond count (lo byte)
r30 - millisecond count (hi byte)
r17 - 100 microsecond count
r16 - 1 microsecond count
Overall delay (ms) = r30:r31 * r17 * r16
---------------------------------------------------------------------*/
"delay_ms%=: nop ; code to replace nop \n"
"delay_100us%=: nop ; code to replace nop \n"
"delay_1us%=: nop ; code to replace nop \n"
" sbiw r30,1 ; decrement ms count (r31:r30)\n"
" brne delay_ms%= ; loop to delay_ms while > 0 \n"
" ret ; return from subroutine \n"
There is a built in to do this
http://arduino.cc/en/Reference/delay
you just give it the number of ms to delay. So for one second
delay(1000)
You are working way too hard for something so simple. See BlinkWithoutDelay (code below). That code is also part of the Arduino examples which get installed when you install the Arduino IDE. Lots of good learning examples in there. (Oh - the code uses a long for the var previousMillis. That is an error (imo). It would be better to use an unsigned long.)
You also have the option of using Timer interrupts but for a simple second delay (esp. if you don't have much experience), I would suggest the method above and do it all in code that is simple to understand.
/* Blink without Delay
Turns on and off a light emitting diode(LED) connected to a digital
pin, without using the delay() function. This means that other code
can run at the same time without being interrupted by the LED code.
The circuit:
* LED attached from pin 13 to ground.
* Note: on most Arduinos, there is already an LED on the board
that's attached to pin 13, so no hardware is needed for this example.
created 2005
by David A. Mellis
modified 8 Feb 2010
by Paul Stoffregen
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay
*/
// constants won't change. Used here to
// set pin numbers:
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = LOW; // ledState used to set the LED
long previousMillis = 0; // will store last time LED was updated
// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
}
void loop()
{
// here is where you'd put code that needs to be running all the time.
// check to see if it's time to blink the LED; that is, if the
// difference between the current time and last time you blinked
// the LED is bigger than the interval at which you want to
// blink the LED.
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}

Resources