Nokolino_diy
Nokolino_diy copied to clipboard
Attiny85/Digispark Support?
Hi (not a bug, feel free to close without notice)
I wanted to recreate a Nokilino with a Attiny85/Digispark. Unfortunately, I fail because of the used Libraries (EEPROM.h and SoftwareSerial.h). Am I doing something wrong or would the code have to be adapted for this? (DigisparkSoftSerial does not work for me)
Hi!
I will have a look soon.
Hello again,
i made a Digispark version. Check the src/ folder.
- SoftwareSerial.h is called SortSerial.h.
- EEPROM.h is working but not included in the Digispark package, i don't now why... Now it is included in the src/ folder.
- analogRead(A2) is now analogRead(2)
- Alas, battery warning is not working, Attiny is not good implemented in the package.
Hopefully it is working, i can't test it by myself, i don't have a Digispark module. Be sure to set the clock to 8 MHz or JQ6500 may have problems.
Good luck!
Thank you very much. I have here a "screaming" JQ8400-FL-10P which is connected to a Digispark. (Power via USB, all "eeprom_write_word" changed to EEPROM.write or EEPROM.read ).
Nokolino does not talk every minute. Code: https://github.com/NikolaiRadke/Nokolino_pcb/tree/master/src/Nokolino_V31 Code:
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <SoftSerial.h>
#include <EEPROM.h>
//--------------------------------------------------------------------------------
// Configuation
#define Time 1 // Say something every statistical 10 minutes
#define Volume 25 // Volume 0-30 - 25 is recommended
#define Darkness 4 // Optional: The lower the darker the light must be
#define Button_event 40 // Last button event number (XXX.mp3)
#define Time_event 163 // Last time event number -> Very last file is "beep"
//#define Breadboard // Breadboard or PCB?
#ifdef Breadboard
#define Offset 0.3 // Battery measuring error
#define maxInput 50 // Max. value from busy line
#else
#define Offset 0.1
#define maxInput 0
#endif
// Optional - comment out with // to disable o remove // to enable
#define StartupBeep // Will say "beep" when turned on
//#define BatteryWarning // Gives a warning when battery is low
//#define LightSensor // Will be quite in the dark
//#define SleepComplain // Will complain if button pressed while its dark
//---------------------------------------------------------------------------------
// Optional battery warning
#define minCurrent 3.30 +Offset // Low power warning current + measuring error
#define battLow 3.10 +Offset // Minimal voltage before JQ8400 fails
// Hardware pins
#define TX 1
#define RX 2
#define Busy 2
// ADC and BOD
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define BODS 7 // BOD sleep bit in MCUCR
#define BODSE 2 // BOD sleep enable bit in MCUCR
// Variables
uint16_t seed,files;
uint16_t address=1;
volatile boolean f_wdt = 1; // Volatile -> it is an interrupt routine
boolean low=false;
boolean dark=false;
char count_files;
uint8_t files_byte[6];
SoftSerial mp3(TX,RX); // TX to D2, RX to D1
int main(void) {
#ifdef BatteryWarning
uint16_t current;
double vref;
uint16_t counter=10; // Check shortly after startup
#endif
init(); {
// Power saving
MCUCR |= _BV(BODS) | _BV(BODSE); // Disable brown out detection - default?
ACSR |= _BV(ACD); // Disable analog comparator - default?
setup_watchdog(3); // Set sleep time to 128ms
// Port Setup
DDRB &= ~(1<<PB0); // D0 INPUT
PORTB |= (1<<PB0); // D0 HIGH
// Start JQ8400
newdelay(750); // JQ8400 needs a short time to settle
mp3.begin(9600);
mp3.write("\xAA\x13\x01");
mp3.write(Volume); // Set volume 0-30
mp3.write((uint8_t) 190+Volume); // Calculate and write checksum
newdelay(100);
mp3.write("\xAA\x0C"); // Count files on module
mp3.write((uint8_t) 0x00);
mp3.write(0xB6);
newdelay(100);
for (seed=0;seed<6;seed++) // Read 6 HEX chars from module
files_byte[seed]=(uint8_t) mp3.read();// and convert the chars into uint8_t
files=16*files_byte[3]+files_byte[4];// Convert 2 bytes into uint16_t
// Nokolino mode | else Music box mode
if (files==Time_event+1) {
// Randomize number generator
address=EEPROM.read(0); // Read EEPROM address
if ((address<2) || (address>(EEPROM.length()-3))) {
// Initialize EEPROM and size for first use or after end of cycle
address=2; // Starting address
EEPROM.write(0,address); // Write starting address
EEPROM.write(address,0); // Write seed 0
}
seed=EEPROM.read(address); // Read seed
if (seed>900) { // After 900 write-cyles move to another address
seed=0; // to keep the EEPROM alive
address+=2;
EEPROM.write(0,address);
}
randomSeed(seed); // Randomize
seed++; // New seed
EEPROM.write(address,seed); // Save new seed for next startup
// Optional startup beep
#ifdef StartupBeep
JQ8400_play(Time_event+1); // Nokolino says "Beep"
newdelay(1000); // Busy is not working well afer startup
#endif
}
mp3.write("\xAA\x04"); // Stop and sleep
mp3.write((uint8_t) 0x00); // Needed for Music box mode
mp3.write(0xAE); // and no startup beep
newdelay(100);
}
// Main loop
while(1) {
// Wait for button or time and go to sleep - ~8 times/second
if (!low) { // Quiet if battery too low
if (!(PINB & (1<<PB0))) { // If button is pressed then
if (dark) { // if fototransistor is available
#ifdef SleepComplain // and complain feature enabled
if (files==Time_event+1) // and not in music box mode
JQ8400_play(Time_event); // complain when button pressed
#endif
}
else if (files==Time_event+1)
JQ8400_play(random(0,Button_event+1)); // Button event
else {
JQ8400_play(address); // or single music box files
(address==files)? address=1:address++;
}
}
else if ((!dark) && (files==Time_event+1) && (random(0,Time*60*8)==1)) // Time event
JQ8400_play(random(Button_event+1,Time_event+1));
}
attiny_sleep(); // Safe battery
// Optional: Check current
#ifdef BatteryWarning
if (counter==0) {
current=MeasureVCC();
vref=1024*1.1f/(double)current;
if (vref<=minCurrent) { // Current below minimum
if (vref<=battLow) low=true; // Power too low for J8400
else JQ8400_play(Time_event+1);// Nokolino says "Beep"
}
else low=false;
counter=400; // Every minute, 400x128ms+some runtime ms for 60s
}
counter--;
#endif
// Optional: Check darkness
#ifdef LightSensor
if (analogRead(3)<=Darkness) dark=true;
else dark=false;
#endif
}}
void JQ8400_play(uint8_t f) { // Plays MP3 file
mp3.write("\xAA\x07\x02"); // Play file number f
mp3.write((uint8_t) 0x00);
mp3.write(f);
mp3.write((uint8_t) 179+f); // Calculate und wirte checksum
newdelay(100);
while (analogRead(2)>maxInput)
attiny_sleep(); // Check busy
newdelay(100);
}
void attiny_sleep() { // Sleep to save power
cbi(ADCSRA,ADEN); // Switch ADC off
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_mode();
sbi(ADCSRA,ADEN); // Switch ADC on
}
void newdelay(uint16_t z) // New delay function to save flash
{
uint32_t zmillis=millis();
while (millis()-zmillis<z);
}
void setup_watchdog(uint8_t mode) { // Setup wake time
uint8_t bb;
bb=mode & 7;
if (mode > 7) bb|= (1<<5);
bb|= (1<<WDCE);
MCUSR &= ~(1<<WDRF);
WDTCR |= (1<<WDCE) | (1<<WDE);
WDTCR = bb;
WDTCR |= _BV(WDIE);
}
uint16_t MeasureVCC(void) { // Thank you, Tim!
PRR &=~_BV(PRADC);
ADCSRA =_BV(ADEN)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0);
ADMUX =_BV(REFS2) | 0x0c;
newdelay(1);
ADCSRA |=_BV(ADSC);
while (!(ADCSRA&_BV(ADIF)));
ADCSRA |=_BV(ADIF);
return ADC;
}
ISR(WDT_vect) { // Set global flag
f_wdt=1;
}
I added a JQ8400 version here: https://github.com/NikolaiRadke/Nokolino_pcb/tree/master/src
Can you guess the time interval between the random talking? Maybe you should flash the bootloader to set the Attiny85 to 8 MHz.
The time intervals are mostly correct. The chip programmed with the correct settings (8mhz no USB). But the button does not work correctly with UBS Power. At most, no pressing is detected. With power from a battery, everything works as it should.
I see. the hardware close programming to save flash space may cause problems with the digispark package. Now the button is questioned by standard Arduino code. Give it a try.