Attiny13 millis

Hi.
Can somebody explain me how millis works on Attiny13 ? Overflow etc.

I am trying to make Ni-Cd charger, measuring voltage and switching on and off current + indication are no problem. But I also want to have timed cut-off. But it doesn’t works like I want. First I added t=9 and it looks like solved, but then I chenged time to 4.5 hours and again there is some issue.

byte t = 0;
byte in = 3;
byte ledPin = 4;
int Value = 0;
unsigned int pm = 0;
byte stat = 1;
const byte pwrPin =  2;
unsigned int previousMillis = 0;
unsigned int currentMillis = 0;

void setup() {
pinMode(ledPin, OUTPUT); 
pinMode(pwrPin, OUTPUT);
digitalWrite(ledPin, HIGH);  
}

void loop() {
Value = analogRead(in);   //read battery voltage 
if (millis() - pm >= 1800000){pm = millis();t = t+1;}   //each 30minutes increment t value
if (t >= 9){digitalWrite(pwrPin, 0);blink(50);t=9;}else  //t reaches 9 = 4.5 hours >> fast blinking, turn off charging
{
if (Value > 512){stat=0;} //voltage of battery pack > 18V = status 0
if (Value < 460){stat=1;}//voltage of battery pack < 16.5V = status 1
if (stat == 0){digitalWrite(pwrPin, 0);blink(500);}//status 0 = slow blinking, turn charging off
if (stat == 1){digitalWrite(pwrPin, 1);digitalWrite(ledPin, 1);}//status  1 = turn indication led and charging on
}

}

//blinking function
int blink(int x){ 
currentMillis = millis();
  if(currentMillis - previousMillis > x) {
    previousMillis = currentMillis;   
    if (digitalRead(ledPin) == LOW)
     digitalWrite(ledPin, HIGH); 
    else
     digitalWrite(ledPin, LOW); 
}
}
//end of blinking function
unsigned int previousMillis = 0;
unsigned int currentMillis = 0;

?

This is only for blink function. Slow blinking is after voltage reach peak value = slow blinking and shut down output controlling power transistor. And fast blinking is after 4.5h and doesn’t matter on voltage, after this time it should start blinking fast ant turn off charging.

That was a hint. Consider now the variable "pm"

I will try something, but problem is: Binary sketch size: 1 010 bytes (of a 1 024 byte maximum) XD

How come pwrPin gets qualified "const", but "ledPin" doesn't?

BTW, code formatting doesn't cost any RAM or flash memory.

Easy. Copy and paste from another sketch file.

I am not programmer. This is my 5th sketch. I know nothing about C. So please consider it.

Is it important if it is const or not ? Why does it matter ?

Atmega328 > millis > overflow after cca 50 days. Attiny13 when ? What happens if millis is some small number after overflow and PM is big number (before overflow), millis - pm = what ? negative number ? hiw I can make absolute value from number ?

Is it important if it is const or not ? Why does it matter

No, it’s not important; keywords are invented for the hell of it.

If it’s a constant, the compiler may find good reason not to allocate it any RAM.

OK if it is constant, it will take less RAM. Right ?

And how I figure out RAM usage ? I have problems only with program memory. I don't know how big RAM is in attiny. I don't care. I just want to have comparator and timer in one small package instead of LM358 and 555 and lot of discrete components. Thats all.

I don't know how big RAM is in attiny. I don't care.

You've got 64 bytes. You should care

Ok now i know that I have only 64bytes. But How I know how much of ram my sketch using or need to have ?

This problem with timing can be caused by small RAM of Attiny ?

So what can I do, increase t from 9 and decrease interval between incrementation of t ?

you can cut back on your variables a lot…

have a look at this… state engine method.

#define DEBUG// to test with a shorter time... comment out to return to your 30 mins

#define INITIAL_CHARGE 0
#define SENSOR_CHARGE 1
#define CHARGE_OFF 2

#ifdef DEBUG
#define THIRTY_MINUTES 3000UL
#else
#define THIRTY_MINUTES 1800000UL
#endif

byte t = 0;
const byte sensorPin = 3;
const byte ledPin = 4;
unsigned long pm;
byte state = INITIAL_CHARGE;
const byte pwrPin =  2;
unsigned long previousMillis;

void setup() 
{
  Serial.begin(115200);
  pinMode(ledPin, OUTPUT); 
  pinMode(pwrPin, OUTPUT);  
}

void loop() 
{
  if (millis() - pm >= THIRTY_MINUTES)
  {
    pm = millis();
    t++;
    Serial.print(t); 
    Serial.print(" State = "); 
    Serial.println(state);
    if (t < 2)
    {
      state = INITIAL_CHARGE;
    }
    else if (t < 9)
    {
      state = SENSOR_CHARGE;
    }
    else
    {
      state = CHARGE_OFF;
      t = 21;
    }
  }

  if (state == INITIAL_CHARGE)
  { 
    digitalWrite(ledPin, HIGH);
    digitalWrite(pwrPin, HIGH);
  }
  else if (state == SENSOR_CHARGE)
  {
    blink(500);
    int Value = analogRead(sensorPin);   //read battery voltage
    if (Value > 512)
    {
      digitalWrite(pwrPin, LOW);
    } 
    if (Value < 460)
    {
      digitalWrite(pwrPin, HIGH);
    }
  }
  else if (state == CHARGE_OFF)
  {
    blink(50);
    digitalWrite(pwrPin, LOW);
  }
}

int blink(int x)
{ 
  if(millis() - previousMillis > x) 
  {
    previousMillis = millis();   
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
}

Thanks a lot for complete sketchfile and many ideas.

Copy, paste, comment serialbegin and serial stuff. : Binary sketch size: 1 028 bytes (of a 1 024 byte maximum)

I also tried only replace blinking function. Yours looks nicer, smaller, but with old function it is smaller after compilation. 12bytes.

First hour charging without voltage sensing ? Why ? More if commands ?

This is not good idea, because you can put almost fully charged battery to charger and than it should stop charging after short time. Or there can be power lost. No no.

How this works?:

define THIRTY_MINUTES 1800000UL

What is difference between this and: const unsigned int THIRTY_MINUTES = 1800000; I see this first lines beginning with # first time. How this works ?

//OK I google it. commands for compiler. Right ? Only replaces THIRTY_MINUTES by value during compilation. 1800000UL - UL means unsigned long ? It must be there ? It is possible that because I don't have it it doesn't work right ?

Although you failed to mention the battery capacity or charge rate, timed charging of a Ni-Cd or Ni-Mh battery is a poor method at best... There is a slight difference between the two and I would recommend you wiki the differences... That LM358 was there for a purpose.. it is most likely that one was a comparator for sensing the cell voltage and the other section modified the pulse rate of the 555 to switch from bulk charging to a pulsed top-off method..

Doc

I have battery pack 12*1.2V NiCd. Included charger is transformer/wall adapter + rectifier, diode and 5R/2W resistor, thats All. And LED diode +resistor. So you must disconnect charger after 3-5 hours to prevent overcharge. And I want to modify this dumb charger to smart charger. Thats all. There is very limited space, so I need simple schematic, only few components and not very big components. Everything is OK, but I have problem only with this millis on attiny, it works not like I want. I want to stop charging and run blinking function after 4.5 hours always, independently on battery voltage.

I was only give you some direction… I cannot test the sketch.

will this fit into your ATtiny?

#define DEBUG// to test with a shorter time... comment out to return to your 30 mins

#define INITIAL_CHARGE 0
#define CHARGE_OFF 1

#ifdef DEBUG
#define FOUR_POINT_FIVE_HOURS 60000UL
#else
#define FOUR_POINT_FIVE_HOURS 16200000UL
#endif

const byte pwrPin =  2;
const byte sensorPin = 3;//A3
const byte ledPin = 4;

byte state = INITIAL_CHARGE;
unsigned long pm;
unsigned long previousMillis;

void setup() 
{
  pinMode(ledPin, OUTPUT); 
  pinMode(pwrPin, OUTPUT);
}

void loop() 
{
  if (millis() - pm >= FOUR_POINT_FIVE_HOURS)
  {
    state = CHARGE_OFF;
  }
  if (state == INITIAL_CHARGE)
  {
    int Value = analogRead(sensorPin);
    if (Value > 512) digitalWrite(pwrPin, LOW); 
    if (Value < 460) digitalWrite(pwrPin, HIGH);
  }
  else
  {
    digitalWrite(pwrPin, LOW);
  }
  if(millis() - previousMillis > state==INITIAL_CHARGE?500:50) 
  {
    previousMillis =millis();   
    digitalWrite(ledPin, !digitalRead(ledPin));
  }
}

Now I have this:

const byte in = 3;
const byte ledPin = 4;
const byte pwrPin =  2;
byte stat = 1;
byte t = 0;
int Value = 0;
unsigned int pm = 0;
unsigned int previousMillis = 0;
unsigned int currentMillis = 0;

void setup() {
pinMode(ledPin, OUTPUT); 
pinMode(pwrPin, OUTPUT);
//digitalWrite(ledPin, HIGH);  
}

void loop() {
Value = analogRead(in);    
if (millis() - pm >= 300000UL){pm = millis();t++;}
if (t >= 2){digitalWrite(pwrPin, 0);blink(50);t=2;}else{
if (Value > 512){stat=0;}
if (Value < 460){stat=1;}
if (stat == 0){digitalWrite(pwrPin, 0);blink(500);}
if (stat == 1){digitalWrite(pwrPin, 1);digitalWrite(ledPin, 1);}
                                                        }
            }


int blink(int x){
currentMillis = millis();
  if(currentMillis - previousMillis > x) {
    previousMillis = currentMillis;   
    if (digitalRead(ledPin) == LOW)
     digitalWrite(ledPin, HIGH); 
    else
     digitalWrite(ledPin, LOW); 
                                          }
                 }

Binary sketch size: 988 bytes (of a 1 024 byte maximum)

This:
if (millis() - pm >= 300000UL){pm = millis();t++;}
if (t >= 2){digitalWrite(pwrPin, 0);blink(50);t=2;}
should trigger blinking and turn off charging after 10 minutes, but it will do it after 5minutes and 30seconds cca.
After I change it to 1800000 and in t >= 2, t=2 replace 2 by 9 it should do it after 4.5h, but it will do it again sooner, after 0.5h cca. Why ?

What is max value of attiny13 millis after it jump back to 0 and starts counting again from 0. I can’t use serial.print here.

How can I do 4.5h delay with attiny13 or count time 4.5h ?

millis() returns an unsigned long…

you are rolling over your unsigned int after 65 seconds (216 = 65,536milliseconds) versus approx 4.3billion with an unsigned long which equates to about 49 days…

you could try to bit shift millis()

myInt = (millis() >> 16)

play around with that… each change at 217 is 65seconds…

something like this…

int myLastInt;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  int myInt = millis() >> 16;
  if (myInt != myLastInt)
  {
    Serial.println(myInt);
  }
  myLastInt = myInt;
}

FYI, your function is set up to return an int… which it does not.

int blink(int x){

use:

void blink(int x){

each change at 2^17 is 65seconds…

sp. “each change at 216 is 65seconds…”

AWOL:

each change at 2^17 is 65seconds…

sp. “each change at 216 is 65seconds…”

thanks AWOL!

just when I thought I was being clever… :blush: