Arduino based battery discharge alarm / coding help.

Hi all,

I'm aiming to d-i-y a battery discharge alarm that will be 'matched' to 3 identical 12V Lead Acid Gel traction batteries, used with an electric outboard.

The quick overview is that it will monitor the battery terminal voltage and current and using the resultant of both, trigger an audible alarm that relates to 50% depth of discharge (or thereabouts).

At the moment I have it working on an Arduino Nano feeding a 2 x 16 LCD via I2C interface (to reduce the wiring).

By copying, pasting and tweaking stuff I've found online, I've just about got it reading and displaying the Volts, the current and calculating and displaying the Watts and have a field for Wh but not sure if I can implement Wh just using the Nanos internal timer?

I might not bother with displaying Wh but display the current low voltage threshold (which will vary, see later) or maybe display both alternately (as they are really just 'background' information).

Because of Peukerts Law, where it says the capacity of a (Lead acid) battery will very dependant on the load / current drawn, it is my thought to continuously calculate that based on a predetermined scale (hopefully supplied by the battery manufacturer) and the WiKi page on it gives us some basic rules and values to work from:

formatting link

So, (Q1) given the right input values (instantaneous current and volts), the variables for that particular battery and the Peukert's Law formula, should I be able to do what I want?

I'm not particularly looking for lab precision here, just reasonably repeatable results that I can cross reverence against other / external meters to confirm it is all at least reasonably representative.

I'm still waiting for some of the bits (batteries and the Hall-effect current sensor) before I can do any real tests but as a starter, one of the things I'm struggling with is getting the Watts value to display properly?

e.g. The volts displays will be to 1 decimal place and typically always between say 11.0 and 13.8V ( just / always two integers), making it easy to display as the display control is only the position of the first character.

The Amps should be between 0.0 and 30.0 and I have been able to use an IF / ELSE to move the screen print position to adjust between 1.5 and

25.0 A. (1 or 2 integers).

The Watts and Wh though will go between 0 and say 360 (W, for the motor) or 0 - 180 Wh for the battery, both being 3 integers. It's that bit I can't seem to get right so would like help with please?

Just to give you the examples, the first bit works (probably more by luck than judgment (ignore comment wraps):

// Read and display Current (col / row) readAmps = analogRead(ampsInput); delay(5); float amps = readAmps * (50.0 / 1023.0); //this maps the measured voltage from 0 to 50V (read as Amps) lcd.setCursor(0,1); // first col, second row lcd.print(" "); // clear the previous value as it could have a different number on integers if (amps < 10) { lcd.setCursor(1,1); // to cope with 0.0 to 9.9, space display out by one } else { lcd.setCursor(0,1); // to cope with 10.0 to 99.9 } lcd.print(amps,1);

So far, so good?

However, I can't seem to get this one right and I think it's to do with the IF, ELSE IF, ELSE rules. Changing the second else if to just else (as I believe it should be) it then won't compile. ;-(

// Calculate and display Watts lcd.setCursor(8,0); lcd.print(" "); float watts = (volts * amps); if (watts < 10) { lcd.setCursor(10,0); lcd.print(watts,1); // displays calculated watts to one decimal place } else if (watts >= 10) { lcd.setCursor(9,0); lcd.print(watts,1); } else if (watts >= 100) { lcd.setCursor(8,0); lcd.print(watts,1); }

Anything over 100 seems to be 1 character too many to the right so I think I have the logic wrong somewhere. ;-(

The 16x2 display should look like this:

12.5 V 187.5 W 15.0 A Wh

What I'm getting is this:

12.5 V 187.5W 15.0 A Wh

At the moment all the analogue inputs are just open / floating so it's just displaying random noise but that is good enough to test the display. Shorting either input to ground correctly displays 0.0 for volts and amps (and watts etc) and to 5V displays 15V, 50A and 750W. ;-)

So, (Q2) could someone familiar with Arduino coding help me on this and any other further hiccups I get please?

Cheers, T i m

Reply to
T i m
Loading thread data ...

I don't know Arduino coding, but your last 'else' won't work, because the previous 'else' covers both watts >=10 and watts >= 100.

I suggest: if watts =100 ... // set cursor 10 else ... // set cursor 9 end if

Reply to
Dave W

Would not the instantaneous drop on start up give a good indication of battery health? Brian

Reply to
Brian Gaff

Whilst it might to some degree and assuming you mean capacity when you say health, I would still like to measure the running current and volts and see the consumed energy in kilowatt hours.

This running project may be a parallel project that would be a semi-automated test rig that would run the battery at various loads, logging the values to an SD card for later perusal and evaluation.

Cheers, T i m

Reply to
T i m

Ah ...

Ok, and putting that into Arduino talk and reversing the column spacing variable resultant (as it counts from the left to right and to the first digit) it then works perfectly. ;-)

if (watts < 10) { lcd.setCursor(10,0); (So a 7.0 would be printed with the 7 10 chrs from the left with the dp at position 11) lcd.print(watts,1); } else if (watts >= 100) { lcd.setCursor(8,0); (So a 123.4 would be printed with the 1 8 chrs from the left with the dp at position 11) lcd.print(watts,1); } else{ lcd.setCursor(9,0); (so a 75.6 would be printed 9 chrs from the left with the dp at position 11) lcd.print(watts,1); }

Brilliant. ;-)

Cheers, T i m

Reply to
T i m

Why not?:

lcd.setCursor((watts>10)?10:(watts>=100)?8:9,0); lcd.print(watts,1);

And save the paint on the curly brace key....

Reply to
The Natural Philosopher

Whilst I like the idea of the compactness / efficiency of just the one line of code ... and it seems to compile and run, it doesn't seem to work properly. ;-(

A value less than 10 (so say 1.2) and with your code we get the dp at position 11 (I think I meant 12 above (not 11) to put it in the right place for each value range), 123.4 has the dp at position 14 and 12.3 at pos 13?

The lcd.setCursor seems to set the position of the first character so it would have to have a lower number position offset the higher the value printed to the display (if that helps)?

So, (with fixed pitch font) we need:

0000000001111111 1234567890123456 1.2 W 12.3 W 123.4 W

but with your code we are seeing:

0000000001111111 1234567890123456 1.2 W 12.3W 123.4

changing your code from:

lcd.setCursor((watts>10)?10:(watts>=100)?8:9,0); lcd.print(watts,1);

to:

lcd.setCursor((watts>10)?8:(watts>=100)?8:10,0); lcd.print(watts,1);

gives us:

0000000001111111 1234567890123456 1.2 W 12.3 W 123.4 W

So fixes two of them why (or how it works). ;-(

Cheers, T i m

Reply to
T i m

Surely TNP's "watts>10" should be "watts

Reply to
Dave W

Reply to
T i m

Reply to
The Natural Philosopher

Reply to
The Natural Philosopher

Reply to
T i m

.

yes.

expression. Anytjinbg that evaluates to a value.

1 is an expersion.

(10-3) is an extression. (numerical) "Today is not Sunday" is an expression (string) a>b is an exoression (boolean) = is an operator. Or part of an expression - never a whole one.

True, and thats why I said what I said. Perhaops I should have said so its really a question of which the you a year from now will find easier to read :-)

Remember the best code is code you never have to read again.

Its true even for those og us who made good livings doing thos stuff. You woork yourself uo to a pitch of understanding, do it, and then its done and you forget it all complenetely. #

Modern compilers are amazing.

Compared to te heap of shity I worked on back in the day when you really had to find the best of 6 ways of writing sonmething to get the compiler to produce compact code.

Nothing wroong woth that. Yiou arent part of a bif team. Wrie te obvious bits first and then when you have a 'livrary' of usefel tested bits - like te coide you just wrote makes a marvelous subroutne, or fuinction sp yiou can lock it away knowing it works, and just call

displayWatts( float watts);

whenever you need to do that thing.

The secret of good coing is mnot letting tedious detail interfere with the logic of what you are doing elsewhere.

That is your main loop then

You can wrire that and shove all the unkown stiff into as yet unwritten functions. Ths one way. Or you can think about te issues of how to apply a e.g. load and log results and write those functions first..

Either way works.

Reply to
The Natural Philosopher

Gdgd.

Ok, thanks.

Understood.

True. ;-)

Oh, ok, that makes me feel a bit better then. ;-)

Because I am an outsider on all of this but just getting in on the edges, I find all of it amazing and find this whole coding thing both exciting (in a fairly limited use of the word etc) because Of what you can make stuff do with it and frustrating because I don't really have the right mind for it and so can't do it easily.

That's good to hear (as I have no 'history' with such things etc).

Ok. It doesn't 'feel' very efficient or structured and I have had to start from scratch several times when I've typed myself into a corner. ;-(

I'm not (whatever that is). ;-)

Well that's sorta what I have been doing. If I get some new hardware (like an I2C display or BT module) I first test is with some existing / example code and if it work, see if I can expand on that to make it do something else (even if that's only changing 'Hello world' to something else).

Then I'll often try to prune it down (if there are any bits that I'm not interested in or don't apply to my scenario) and then maybe make it actually do something I want. Once I have that bit / module working I might either (depending on the complexity), repeat the above with the second bit or try to incorporate it in my first bit.

Understood.

Ok ... and that's the other thing .... I am aware there is 'good practice' and 'coding convention' (some documented, some not) and I'm vary aware I'm fairly unaware of much of it. So I look at my code as someone might after painting a wall with a toothbrush.

So, like it seems 'some people' would rather get me to sort out their PC's rather than even trying to do so themselves, part of me would rather just hand the who coding part over someone else, not because I can't be bothered but because 1) I know it's not 'my thing' and 2) I've got loads of other stuff I should and would like too be doing. So, I would rather say service someone's car while they write my code. ;-) That said, I think I'd also prefer to watch them coding as then I can still be part of that process and wouldn't be sure my brief was accurate enough for them to give me what I had in my head.

Yeah, I have the basic concepts of what needs to happen and even some of the code that might make it do so. The biggest problem I've had in the past is fitting it all together. Like needing to nest a loop ... or setting the right conditional exit etc.

I sometimes drop bits of other code into a commented bit at the bottom and then copy and paste it back where I think it should go and see what happens.

Ok.

Again, that's good to know, that there *are* more than one way of skinning this particular cat. ;-)

So, while we are there and assuming you have played with the Arduino's (and this question should be right up you street ), should it be reasonably easy to take the continuous 'watts' value and by multiplying it over the elapsed time since the last reading and adding it to the accumulated Wh gathered so far, likely to produce a reasonably meaningful value for Wh do you think please?

formatting link

I have a RTC shield with an SD card for data-logging (I've tested all that with example / found code etc).

I've just found thins and might have a read though it later and see if I can use any of it:

formatting link

Cheers, T i m

Reply to
T i m

What seems to be happening now is that 9.9 and under ... and 10.1 and over are ok but 10.0 dead is shifted one to the right?

Cheers, T i m

Reply to
T i m

It could be that if watts = 9.99 it gets rounded up to 10.0 as you are only displaying one digit after the point. I would try changing the condition to 'watts

Reply to
Dave W

Reply to
T i m

HomeOwnersHub website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.