Skip to content

Instantly share code, notes, and snippets.

@IOT-123
Last active April 9, 2018 10:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IOT-123/291c8ed67635f15895decf7e82d48b6e to your computer and use it in GitHub Desktop.
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.
// 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