Go Down

Topic: Servo power down / current drain / watchdog timer attiny85 (Read 4425 times) previous topic - next topic

jimLee

You say you just want the servo to do a couple swipes? You -could- just hard code about a second of 1ms pin highs, then about a second of 2ms pin highs and be done with it.

Unless you are interested in controlling the actual servo position, then this wouldn't work.

-jim lee

marky_mark

Thanks Jim, the servo hits a switch as well, so controlling position is important.  Good to know though.

cheers

Mark.

jimLee

Servos stop within 20ms if you stop sending pulses..

maybe this would do it for you?

while(digitalRead(swithcPin1)) sendPulse(1);

then the other end would be..

while(digitalRead(swithcPin2)) sendPulse(2);

-jim lee

marky_mark

#18
Mar 12, 2012, 02:39 am Last Edit: Mar 12, 2012, 05:08 am by Coding Badly Reason: 1
Hmm... No luck as yet.

Using what I think is a fairly bare bones version of the code; it's still not working for me.  I'm not sure if I've inserted the mentioned lines in the correct positions, but it still draws power throughout the sequence.  If I try to inesert myServo.detach(); anywhere, the servo will not move at all.

Can anyone see where I am going wrong here?  I tried to add Nicks lines too, however I obviously need to create some sort of variable for that to work?

Thanks,

Mark.

Code: [Select]
/*
* Watchdog Sleep Example
* Demonstrate the Watchdog and Sleep Functions
* LED on digital pin 0
*
* KHM 2008 / Lab3/  Martin Nawrath nawrath@khm.de
* Kunsthochschule fuer Medien Koeln
* Academy of Media Arts Cologne
*
* XXXXXXXXXXXXXXXXXXX originally by InsideGadgets (www.insidegadgets.com)
* to suit the ATtiny85 and removed the cbi( MCUCR,SE ) section
* in setup() to match the Atmel datasheet recommendations
*/

#include <avr/sleep.h>
#include <avr/wdt.h>

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#include "Servo8Bit.h"

Servo8Bit myServo;  //create a servo object.
                   //a maximum of five servo objects can be created


int pinLed = 0;
//create the variable, init it to zero.
uint8_t originalValue = 0;
volatile boolean f_wdt = 1;

void setup(){
 pinMode(pinLed,OUTPUT);
 setup_watchdog(8); // approximately 4 seconds sleep
   }

void loop(){
 if (f_wdt==1) {  // wait for timed out watchdog / flag is set when a watchdog timeout occurs
   f_wdt=0;       // reset flag
//Restore the TCCR1 register to re-enable the timer.
TCCR1 = originalValue;
//reattach the servo that was previously detached
   myServo.attach(1,544,2200); //attach the servo to pin PB1
   digitalWrite(pinLed,HIGH);  // let led blink
       for(int pos = 0; pos < 180; pos++)  // goes from 0 degrees to 180 degrees
   {                                   // in steps of 1 degree
       myServo.write(pos);             // tell servo to go to position in variable 'pos'
       delay(15);                      // waits 15ms for the servo to reach the position
   }

   for(int pos = 180; pos > 1; pos--)  // goes from 180 degrees to 0 degrees
   {
       myServo.write(pos);             // tell servo to go to position in variable 'pos'
       delay(15);                      // waits 15ms for the servo to reach the position
   }
   digitalWrite(pinLed,LOW);
   //save the value of the Timer Counter Control Register 1
   originalValue = TCCR1;
   //turn off timer 1
   TCCR1 = 0; //turn off timer 1
   pinMode(pinLed,INPUT); // set all used port to intput to save power
   system_sleep();
   pinMode(pinLed,OUTPUT); // set all ports into state before sleep
 }
}

// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep() {
 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
}

// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(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
}




Moderator edit: [code] [/code] tags added.

Nick Gammon

OK, get rid of the smiley-faces. Edit your post, select the code, and hit the "#" button to put it into [ code ] tags.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics


Nick Gammon

#21
Mar 12, 2012, 06:39 am Last Edit: Mar 12, 2012, 07:29 am by Nick Gammon Reason: 1
Well I've made a few changes (so I could understand it basically) and tested with my Attiny85 I happened to have lying around. :)

Code: [Select]
#include <avr/sleep.h>
#include <avr/wdt.h>
#include "Servo8Bit.h"

Servo8Bit myServo;  //create a servo object.
int pinLed = 0;

void setup()
 {
 pinMode(pinLed,OUTPUT);
 }  // end of setup

void loop()
 {
 //reattach the servo that was previously detached
 myServo.attach(1,544,2200); //attach the servo to pin PB1

 digitalWrite(pinLed,HIGH);  // let led blink
 for(int pos = 0; pos < 180; pos++)  // goes from 0 degrees to 180 degrees
   {                                   // in steps of 1 degree
   myServo.write(pos);             // tell servo to go to position in variable 'pos'
   delay(15);                      // waits 15ms for the servo to reach the position
   }

 for(int pos = 180; pos > 1; pos--)  // goes from 180 degrees to 0 degrees
   {
   myServo.write(pos);             // tell servo to go to position in variable 'pos'
   delay(15);                      // waits 15ms for the servo to reach the position
   }
 digitalWrite(pinLed,LOW);

 myServo.detach ();

 //save the value of the Timer Counter Control Register 1
 byte saved_TCCR1 = TCCR1;
 //turn off timer 1
 TCCR1 = 0; //turn off timer 1

 pinMode(pinLed,INPUT); // set all used port to intput to save power

 system_sleep();

 pinMode(pinLed,OUTPUT); // set all ports into state before sleep
 //Restore the TCCR1 register to re-enable the timer.
 TCCR1 = saved_TCCR1;
}  // end of loop

// set system into the sleep state
// system wakes up when wtchdog is timed out
void system_sleep()
 {
 // disable ADC
 byte saved_ADCSRA = ADCSRA;  
 ADCSRA = 0;

 // clear various "reset" flags
 MCUSR = 0;    
 // allow changes, disable reset
 WDTCR = _BV (WDCE) | _BV (WDE);
 // set interrupt mode and an interval
 WDTCR = _BV (WDIE) | _BV (WDP3) | _BV (WDP0);    // set WDIE, and 8 seconds delay
 wdt_reset();  // pat the dog
 
 set_sleep_mode (SLEEP_MODE_PWR_DOWN);  

 sleep_enable();
 sleep_cpu ();  
 sleep_disable();

 ADCSRA = saved_ADCSRA;
 }  // end of system_sleep

// Watchdog Interrupt Service / is executed when watchdog timed out
ISR(WDT_vect)
 {
  wdt_disable();  // disable watchdog
 }   // end of WDT_vect


I didn't quite get what the flag was for the watchdog, so that went out the window. And a few other things I didn't get either.

I'm not quite sure about the servo output. I'm seeing about 25 pulses of about 1.54 mS high each followed by 18.76 mS low, per batch.

With the LED disconnected the circuit draws about 8.8 mA when active, and about 675 uA when sleeping. Is that roughly what you are expecting? With the LED on pin 5 it draws 16.5 mA (that would vary depending on the resistor on the LED).

(edit) See below for corrected figures.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

marky_mark

Hmm... I can't believe you could take half a look at that mess and create something tangible.

Thanks for your help, I'm looking forward to sitting down and trying to figure out what's going on and where I was going wrong.

I hope this little exercise will help someone else.

Hat's off to you mate.

Nick Gammon

I made a major cock-up of the measurements. I had left in the circuit on the breadboard an IR sensor from a previous experiment that was drawing current.

The revised figures are:


  • Sleeping: 8 uA

  • Awake (with no LED): 8.1 mA



Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

marky_mark

Just a quick update...

I had Nick's code running fine yesterday, however today when I tried it, it was a no go again.  Tried on a couple of different chips and rewired a dozen times so who knows what's going on there.

Went back to the code I'd posted above.  The trick is not so much in the detachment of the servo after all that, it is to put a protection diode on the pin controlling the servo .

Testing on my desk at the moment and working fine.  Figured this out as there was no current when the red to the servo was detached, but remained current draw when the brown was.

Trick for young players I guess.

Nick Gammon

Yep the old protection diode. An oldie but a goodie.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

marky_mark

Hmm....

The plot thickens...

The unit is kind of functioning, however when running through the MOSFET, it crashes after a few cycles (not many, maybe 5 - 20).

Because I'm running with the LED of the gate pin for the MOSFET, I can see the LED behaves strangely when it crashes, either flickering a bit, staying on continuously, or staying off.  I should point out it would function correctly up until this point.

Voltage is fine, around 5v, however different power supplies seem to result in the same issues.

Odd, but no doubt common... I thought best to continue this thread? 

Is this likely a stack thing, or a resistor pull-down thing (which I don't completely understand, but think I have right), or something else entirely?

Cheers, Mark.

Nick Gammon

What's your circuit?

This is how I am wiring up MOSFETs in this situation:



The 10 ohm series resistor limits current out of the processor, and the 10K pulls the gate low when the chip is off/asleep.

In your case you would have the servo where "Load" is.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Go Up