Hi,
I have upgraded an old fire truck toy with 2 LEDs, a piezo (speaker) and an ATTiny13a (1.2MHz on 2 AAA with each 1.34V max). The fire truck is nothing more than a plastic shell with two axle and wheels on it. No electronic at all.
Searched the forum for related posts but found non similar. Read the interrupts page from Nick Gammon, again and again ;).
What is it I want--and I partially have achieved already:
When the truck starts moving, start playing the "siren" and have the two LEDs flash alternately, all for a fixed time. No need to make it more complex.
What was needed to do:
- "recognize" the moving and activate an interrupt
- activate the LED alternately
- play a simple tone sequence as long as the LEDs are flashing
What is working: Basically all.
Problems/questions:
- Siren is pretty quiet. How to make the piezo siren loader without changing power supply or adding step up converter?
- Sometimes the LED/siren get "stuck" and slowed down, respectively. That is, a single tone is heard for more time than usual and one LED is on for more than a second. This happens when moving the truck as well as when it is stopped. More frequent when it's moving. I guess the interrupt is firing so fast that the ATTiny13a can't keep up? Well that is what I want to clarify with your help. What is wrong with my interrupt handling?
- Recognizing the movement was a bit tricky. Maybe someone has another/better idea how to recognize the movement? My current solution: The front axle is made of metal. I attached small conducting magnets to it. When the fire truck starts moving the magnets are rotated, hit the bottom and short two separate wires below. PB1 (INT0) is pulled to ground. IMO the magnets and the axle will suffer attrition after some use.
I'm using MicroCore, GitHub - MCUdude/MicroCore: A light-weight Arduino hardware package for ATtiny13, and Arduino IDE 1.6.9.
Sketch below and schematics attached (hobbyist here but did my best).
Thanks for your help & best!
#define PIN_IRQ PB1 // external interrupt INT0
#define PIN_LED PB3
#define PIN_LED2 PB2
#define PIN_BUZZER PB0
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t irq = false;
#define SLEEP_INTERVAL 128
#include <avr/sleep.h>
ISR(WDT_vect) {
}
#define PLO(pin) (PORTB &= ~(1<<pin))
#define PHI(pin) (PORTB |= (1<<pin))
void pinChange() {
//detachInterrupt(0);
irq=true;
}
int main(int argc, char** argv) { // 20 bytes smaller than setup/loop!
pinMode(PIN_IRQ,INPUT);
pinMode(PIN_LED,OUTPUT);
pinMode(PIN_LED2,OUTPUT);
pinMode(PIN_BUZZER,OUTPUT);
// Buzzer
TCCR0A |= (1<<WGM01); // set timer mode to Fast PWM
TCCR0A |= (1<<COM0A0); // connect PWM pin to Channel A of Timer0
attachInterrupt (0, pinChange, LOW);
sei();
sirene(); // signal battery attached
while (1) {
if (irq) {
sirene();
sirene();
sirene();
sirene();
irq=false;
//attachInterrupt (0, pinChange, LOW);
}
sleepNow(SLEEP_INTERVAL);
}
}
void sirene() {
tone(1);PHI(PIN_LED);_delay_ms(250);
tone(2);PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(250);
PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(250);
tone(1);PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(250);
tone(2);PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(250);
PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(250);
stop();PLO(PIN_LED);PLO(PIN_LED2);_delay_ms(50);
tone(1);PHI(PIN_LED);_delay_ms(50);
PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(50);
PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(50);
PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(50);
PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(50);
tone(2);PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(50);
PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(50);
PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(50);
PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(50);
PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(50);
PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(50);
PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(50);
PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(50);
PHI(PIN_LED2);PLO(PIN_LED);_delay_ms(50);
PHI(PIN_LED);PLO(PIN_LED2);_delay_ms(50);
PLO(PIN_LED);PLO(PIN_LED2);
stop();
}
void sleepNow(byte b) {
{
ACSR |= (1<<ACD); //Analog comparator off
ACSR = ADMUX = ADCSRA = 0;
}
if (b != 128) {
WDTCR |= b; //Watchdog
// Enable watchdog timer interrupts
WDTCR |= (1<<WDTIE);
}
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
cli(); // No interrupts; timed sequence
BODCR = (1<<BODS) | (1<<BODSE);
BODCR = (1<<BODS);
sei(); // Enable global interrupts or we never wake
sleep_mode();
sleep_disable();
}
/******************
* adapted from Łukasz Marcin Podkalicki <lpodkalicki@gmail.com>
* ATtiny13/007
* Simple tone generator.
*/
typedef struct s_note {
uint8_t OCRxn; // 0..255
uint8_t N;
} note_t;
#define N_1 (_BV(CS00))
#define N_8 (_BV(CS01))
#define N_64 (_BV(CS01)|_BV(CS00))
#define N_256 (_BV(CS02))
#define N_1024 (_BV(CS02)|_BV(CS00))
// bei 1.2 MHz
// bei 4.8?
static void tone(uint8_t t)
{
note_t ta = {20, N_64};
note_t tue = {127, N_8};
note_t val = t==1?ta:tue;
// PB0!!
TCCR0B = (TCCR0B & ~((1<<CS02)|(1<<CS01)|(1<<CS00))) | val.N;
OCR0A = val.OCRxn - 1; // set the OCRnx
}
static void stop(void)
{
TCCR0B &= ~((1<<CS02)|(1<<CS01)|(1<<CS00)); // stop the timer
}
/*****************************/