Last active
April 9, 2018 10:23
-
-
Save IOT-123/291c8ed67635f15895decf7e82d48b6e to your computer and use it in GitHub Desktop.
ATTINY85 checks the current distance of objects to a SR04 Ultrasonic range finder against a user configurable value. If closer, a pin is set HIGH to wake a HOST MCU, then sleeps for 1 second. If not closer, just sleeps for a second. Repeat.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ATTINY85 / 1MHz | |
#include <EEPROM.h> | |
#include <avr/sleep.h> | |
#include <avr/wdt.h> | |
#define USE_SOFTWARE_SERIAL 1 | |
#if (USE_SOFTWARE_SERIAL) | |
#include <SoftwareSerial.h> | |
#define RX 0 | |
#define TX 1 | |
SoftwareSerial Serial(RX, TX); | |
#endif | |
#ifndef cbi | |
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) | |
#endif | |
#ifndef sbi | |
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) | |
#endif | |
volatile boolean _f_wdt = 1; | |
const int _triggerPin = 0; | |
const int _butPin = A0; | |
const int _powerPin = 2; | |
const int _userInputDelay = 10000; // 10s | |
const int _userInputDefault = 2; | |
const int _triggerHold = 5000; | |
int _userInputValue; | |
int _triggerDistance = -1; | |
void setup() { | |
#if (USE_SOFTWARE_SERIAL) | |
Serial.begin(9600); | |
#endif | |
setupWatchdog(6); // approximately 1 seconds sleep | |
initPins(); | |
delay(100); | |
serialPrintLn("setup"); | |
_userInputValue = getUserValue(); // reads button presses for 10s | |
serialPrintLn("USER VALUE: " + String(_userInputValue)); | |
} | |
void loop() { | |
setPower(true); | |
delay(100); | |
readSensorCheckTrigger(); | |
setPower(false); | |
systemSleep(); | |
resetPorts(); | |
} | |
void serialPrintLn(String text){ | |
#if (USE_SOFTWARE_SERIAL) | |
Serial.println(text); | |
#endif | |
} | |
void initPins(){ | |
pinMode(_powerPin,OUTPUT); | |
digitalWrite(_powerPin,LOW); | |
pinMode(_triggerPin, OUTPUT); | |
digitalWrite(_triggerPin,LOW); | |
delay(100); | |
pinMode(_triggerPin,INPUT); | |
} | |
// counts button presses for 10s, or gets previously set value from EEPROM | |
int getUserValue(){ | |
int butPresses = 0; | |
int butState = 0; | |
int lastButState = 0; | |
unsigned long initMillis = millis(); | |
while (true){ | |
butState = getResetButtonState(); | |
if (butState != lastButState) { | |
if (butState == HIGH) { | |
butPresses++; | |
serialPrintLn("press"); | |
} | |
delay(100); | |
} | |
lastButState = butState; | |
unsigned long curMillis = millis(); | |
if(curMillis - initMillis > _userInputDelay) { | |
break; | |
} | |
} | |
if (butPresses == 0){ | |
butPresses = EEPROMReadInt(0); | |
if (butPresses == -1){ | |
butPresses = _userInputDefault; | |
} | |
}else{ | |
if (butPresses > 10){ | |
butPresses = 10; | |
} | |
EEPROMWriteInt(0, butPresses); | |
} | |
return butPresses; | |
} | |
// explanation: https://electronics.stackexchange.com/questions/195146/use-the-reset-pin-on-attiny85-as-input-with-voltage-divider | |
int getResetButtonState(){ | |
return (analogRead(_butPin) > 1000 ) ? 0 : 1; | |
} | |
void EEPROMWriteInt(int address, int value) | |
{ | |
byte two = (value & 0xFF); | |
byte one = ((value >> 8) & 0xFF); | |
EEPROM.update(address, two); | |
EEPROM.update(address + 1, one); | |
} | |
int EEPROMReadInt(int address) | |
{ | |
long two = EEPROM.read(address); | |
long one = EEPROM.read(address + 1); | |
return ((two << 0) & 0xFFFFFF) + ((one << 8) & 0xFFFFFFFF); | |
} | |
// toggle low side power switch: https://www.electronics-tutorials.ws/transistor/tran_7.html | |
void setPower(bool on){ | |
if (on){ | |
pinMode(_powerPin,OUTPUT); | |
digitalWrite(_powerPin,HIGH); | |
}else{ | |
digitalWrite(_powerPin,LOW); | |
delay(100); | |
pinMode(_powerPin,INPUT); | |
} | |
} | |
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms | |
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec | |
void setupWatchdog(int ii) { | |
byte bb; | |
int ww; | |
if (ii > 9 ) ii=9; | |
bb=ii & 7; | |
if (ii > 7) bb|= (1<<5); | |
bb|= (1<<WDCE); | |
ww=bb; | |
MCUSR &= ~(1<<WDRF); | |
// start timed sequence | |
WDTCR |= (1<<WDCE) | (1<<WDE); | |
// set new watchdog timeout value | |
WDTCR = bb; | |
WDTCR |= _BV(WDIE); | |
} | |
// Watchdog Interrupt Service / is executed when watchdog timed out | |
ISR(WDT_vect) { | |
_f_wdt=1; // set global flag | |
} | |
// set system into the sleep state | |
// system wakes up when wtchdog is timed out | |
void systemSleep() { | |
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF | |
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here | |
sleep_enable(); | |
sleep_mode(); // System sleeps here | |
sleep_disable(); // System continues execution here when watchdog timed out | |
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON | |
} | |
void setTrigger(){ | |
serialPrintLn("setTrigger..."); | |
pinMode(_triggerPin,OUTPUT); | |
digitalWrite(_triggerPin,HIGH); | |
delay(_triggerHold); | |
digitalWrite(_triggerPin,LOW); | |
delay(100); | |
pinMode(_triggerPin,INPUT); | |
} | |
void resetPorts(){// set all ports into state before sleep | |
pinMode(_triggerPin,OUTPUT); | |
pinMode(_powerPin,OUTPUT); | |
} | |
//--------------------------------THE FOLLOWING CODE IS SPECIFIC TO THE CURRENT SENSOR | |
const int _sr04TriggerPin = 3; | |
const int _sr04EcchoPin = 4; | |
void readSensorCheckTrigger(){ | |
const int min = 10; | |
const int max = 400; | |
if (_triggerDistance == -1){ | |
_triggerDistance = map(_userInputValue, 1, 10, min, max); | |
serialPrintLn("TRIGGER DISTANCE: " + String(_triggerDistance) + "cm"); | |
} | |
long distance = getCentimeters(); | |
serialPrintLn("CURRENT DISTANCE: " + String(distance) + "cm"); | |
if (distance < _triggerDistance){ | |
setTrigger(); | |
} | |
} | |
long getCentimeters(){ | |
long duration, cm; | |
float current_time=0; | |
// The sensor is triggered by a HIGH pulse of 10 or more microseconds. | |
// Give a short LOW pulse beforehand to ensure a clean HIGH pulse: | |
pinMode(_sr04TriggerPin, OUTPUT); | |
digitalWrite(_sr04TriggerPin, LOW); | |
delayMicroseconds(2); | |
digitalWrite(_sr04TriggerPin, HIGH); | |
delayMicroseconds(10); | |
digitalWrite(_sr04TriggerPin, LOW); | |
// Read the signal from the sensor: a HIGH pulse whose | |
// duration is the time (in microseconds) from the sending | |
// of the ping to the reception of its echo off of an object. | |
pinMode(_sr04EcchoPin, INPUT); | |
duration = pulseIn(_sr04EcchoPin, HIGH); | |
// get the current time in milliseconds since the program started | |
current_time = millis(); | |
// convert the time into a distance | |
cm = microsecondsToCentimeters(duration); | |
return cm; | |
} | |
long microsecondsToCentimeters(long microseconds) | |
{ | |
// The speed of sound is 340 m/s or 29 microseconds per centimeter. | |
// The ping travels out and back, so to find the distance of the | |
// object we take half of the distance travelled. | |
return microseconds / 29 / 2; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment