3/1/26 Had started this in February, One of my co-workers wanted a device that sounds like its a cricket that make noise to annoy. So I chose the ATtiny10 with a 5x5mm piezo (very tiny speaker). With some c code, it works great! I chose to have it go at sudo random times and lengths. With this set up and re-chargeable 2032 batteries, it will run for days.
3/26/26 Updated PCB to allow for larger piezo as well as the small one.
This was the first proto type to test it and make sure it was loud enough and sounds like a cricket. It worked. Took a lot of tweaking in the c code though.
I designed the PCB to take 2 different sizes of Piezo speakers. The one of the right has a 10 ohm resister with the small 5mm piezo, the on on the left has a 5 ohm resistor with an 8.5m piezo. So the one on the left is definitely louder.
PCB I've got Oshpark printing for me. Designed with kicad 9.0.7 and updated with version 10.0
C code done on command line with avr-gcc written with vi (vim).
/*
main10.c
Sherman Stebbins
3/18/26
ATtiny10 Cricket - 1 MHz Version
---------------------------------
Clock: 1 MHz internal
PB0 -> Piezo
ATtiny10 (SOT-23-6 package)
=================================
________
| |
PB0 1 |. 6| VCC
GND 2 | 5| PB3 / RESET
PB1 3 | 4| PB2
|________|
Pin Functions
---------------------------------
1 PB0 - OC0A / PWM output
2 GND
3 PB1 - OC0B / ADC1
4 PB2 - ADC2 / INT0
5 PB3 - RESET / ADC3
6 VCC
Notes:
- Cricket speaker on PB0 (OC0A)
- The Frequency of the chip is set to about 4.2kHz (total range of
crikets is about 2-8.2kHz
- Designed to annoy people.. Works great.
- Timer0 used in CTC toggle mode
*/
#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#define OCR_VALUE 14 // ~4200 Hz tone (prescaler 8)
//
// Not cleared on RESET (but decided not to use this time)
//volatile unsigned char count __attribute__((section(".noinit")));
//volatile unsigned char sleepLoopCount __attribute__((section(".noinit")));
volatile uint8_t count = 0;
volatile uint8_t sleepLoopCount = 0;
//Set chirpTime to array of 7 different times:
//2000=2sec, 5000=5sec chirping, etc.
const uint16_t chirpTime[7]={2000,500,1000,3000,1000,2000,1000};
//Set sleepLoops to array of 6 diffent times to offset chirptime to give
//illusion of random the longer its on
const uint8_t sleepLoops[6]={1,3,1,5,2,7};
volatile uint8_t chirp_on = 0;
volatile uint8_t chirp_count = 0;
volatile uint16_t ms_count = 0;
volatile uint16_t runtime_ms = 0;
void timer_start(void);
void timer_stop(void);
void watchdog_setup(void);
int main(void)
{
DDRB |= (1 << PB0);
// Disable ADC for lower power (but probably overkill)
ADCSRA &= ~(1 << ADEN);
sei();
timer_start();
sleepLoopCount=0;
count=0;
while (1)
{
if (runtime_ms >= chirpTime[count]) //2000=2sec, 5000=5sec chirping
{
timer_stop();
PORTB &= ~(1 << PB0);
runtime_ms = 0;
chirp_count = 0;
chirp_on = 0;
count++;
if (count >= 7) {
count = 0;
}
sleepLoopCount++;
if (sleepLoopCount >= 6) {
sleepLoopCount = 0;
}
watchdog_setup();
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
//total sleep time:(put to count 0-6)
for (uint8_t i = 0; i < sleepLoops[sleepLoopCount]; i++)//15=~120sec
{
sleep_enable();
sleep_cpu();
sleep_disable();
}
// sei(); //added to see if it helped the second round timing.
timer_start();
}
}
}
ISR(TIM0_COMPA_vect)
{
static uint8_t sub_ms = 0;
static uint16_t phase_timer = 0;
if (chirp_on)
PINB = (1 << PB0); // toggle pin
sub_ms++;
//speed 4-fast 8-slow
if (sub_ms >= 8) //8 // ~1 ms (8 × 119us)
{
sub_ms = 0;
ms_count++;
runtime_ms++;
phase_timer++;
if (chirp_on)
{
//messed with sound putting to 5
if (phase_timer >= 25) //25
{
chirp_on = 0;
phase_timer = 0;
chirp_count++;
}
}
else
{
//made it a much shorter chirp at 2 instead of 4
if (chirp_count < 4) //4
{
if (phase_timer >= 25)
{
chirp_on = 1;
phase_timer = 0;
}
}
else
{
//made it much faster at 200
if (phase_timer >= 500) //500
{
chirp_count = 0;
chirp_on = 1;
phase_timer = 0;
}
}
}
}
}
//Wakefrom sleep
ISR(WDT_vect){
}
void timer_start(void)
{
TCCR0A = 0;
TCCR0B = (1 << WGM02) | (1 << CS01); // CTC, prescaler 8
OCR0A = OCR_VALUE;
TIMSK0 = (1 << OCIE0A);
}
void timer_stop(void)
{
TCCR0B = 0;
TIMSK0 = 0;
}
void watchdog_setup(void)
{
cli();
// Clear watchdog reset flag (important on tiny10)
RSTFLR |= (1 << WDRF);
// Timed sequence to change WDT
CCP = 0xD8;
WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0); // 8 sec interrupt only
sei();
}