-
Trying, like hundreds before me, to make a used battery tester with the Arduino. I'm beating my head on the wall trying to learn the proper code to turn the Fet off and keep it off when the voltage rebounds at end of cycle. Getting it to read the inputs and adjustable constant current is not an issues, just a current sink and feeding voltage drop over the sense resistor back through the op Amp to boost it for accurate reading.... I cannot figure out if I need a "for loop", "while loop"-with break, or what it is, to get the damn thing to go "hard off". Not using any 'delays' in any of the loops. Also can't get the counter to accurately count up the mAh and store it at end of cycle. Using the millis() function t keeps running after cutoff....I've been at it a few days and I've been through every example I can find with similar results...searched here, google, the playground, everywhere!!
So I have a low pass filter coming off the pwm pin, into the Gate, and I drive it with an "analogWrite" Is this my first mistake? Should be try a "high" command and then adjust the resistor value, but even after I write it low again later, once it cycles back to the beginning of the loop, the process starts again...lol.
Edit: someone please help point in the right direction so the lightbulb eventually goes off in my head...i know there probably a 10 yr old computer whiz out tmhere that can do it in 10 secs but I want to learn, not be given the answer, please..and thank you..
-
Here's a nudge in the right direction: Read up on state machines and figure out how you can utilize them for this project.
-
Will do, thank you. Little motivation
-
A state machine is often written in C as a switch statement. One of the neat things about state machines is they tend to reduce spaghetti code. Everything will be neat and tidy.
Rather than go into a lengthy explanation, I just wrote one. It's simple but I'm sure you will get the idea.
enum states {start, charge, hold, test}; // add as many state names as you need
void main(void)
{
enum states state = start;
while(1) {
switch(state) {
case start: // we will loop here until we see a button pressed
if (ButtonPressed) {
state = charge;
}
// the logic in each state can be much more complex
// there might also be multiple 'next' states if it is appropriate
break;
case charge: // we will loop here until the battery is charged
if (battery_is_charged) {
state = hold;
}
break;
case hold: // loop here for whatever reason, I have no idea how this should work
if (hold_time_is_over) {
state = test;
}
break;
case test: // we probably wait here for another button press
if (ButtonPressed) {
state = start;
}
break;
default: // if we get to this state, something has gone horribly wrong
// print a message, sound an alarm, whatever
// or ignore it because it won't really happen
break;
}
}
}
Think about it and see if you can't break your project into simple states. One of which will turn off the MOSFET.
-
It should be noted that some states exit immediately, no test required. Take the state that turns off the MOSFET. You would change into the state and then turn off the MOSFET and set the state variable to some next state. There doesn't need to be a test to exit the turn-off state.
It is often helpful to draw the state machine with transitional arrows labeled by the condition under which the branch is taken. The states are normally circles annotated with the actions to be taken in each state.
You can find examples via Google.
https://martin-thoma.com/how-to-draw-a-finite-state-machine/
-
Trying, like hundreds before me, to make a used battery tester with the Arduino. I'm beating my head on the wall trying to learn the proper code to turn the Fet off and keep it off when the voltage rebounds at end of cycle. Getting it to read the inputs and adjustable constant current is not an issues, just a current sink and feeding voltage drop over the sense resistor back through the op Amp to boost it for accurate reading.... I cannot figure out if I need a "for loop", "while loop"-with break, or what it is, to get the damn thing to go "hard off". Not using any 'delays' in any of the loops. Also can't get the counter to accurately count up the mAh and store it at end of cycle. Using the millis() function t keeps running after cutoff....I've been at it a few days and I've been through every example I can find with similar results...searched here, google, the playground, everywhere!!
So I have a low pass filter coming off the pwm pin, into the Gate, and I drive it with an "analogWrite" Is this my first mistake? Should be try a "high" command and then adjust the resistor value, but even after I write it low again later, once it cycles back to the beginning of the loop, the process starts again...lol.
Edit: someone please help point in the right direction so the lightbulb eventually goes off in my head...i know there probably a 10 yr old computer whiz out tmhere that can do it in 10 secs but I want to learn, not be given the answer, please..and thank you..
Can you post your code and a simple schematic of the circuit so that I can build and test one and find out what is going wrong? I bet I could get it going I did something similar before but lost the project. I could build it then send pic and updated schematic and code that I changed.
-
@Beamin,
Once I try to rewrite the stats machines I'll post it. I want to try and figure it out on my own before I ask for "specific" assistance with writing it. I am trying to learn as I go and if someone posts the answer, I am not sure I ah e the will power to resist cheating..
-
I don't consider myself an 'inventor' of things, rather, I am a great copier! Everything I have ever learned was started by standing on the shoulders of others. There is little point in struggling to the point of exhaustion when you can get hints for free.
The education is learning a) there is a problem and b) it is likely around here and c) I may not know how to fix it but I know people who do.
My view, of course...
-
I read some "enum" stuff on the bald Engineer website, maybe I read it wrong, but I thought he said Arduino should use it, implying that it won't work in that from...hum, maybe I need to try that style.
Well I am exhausted again...I'm going nuts. It's because I feel as if Ive failed..I have been blown up a bunch and have some permanent brain issues- fucking afghan ieds-but I am not dumb...I hope.
But my new enemy if "not being ignored like it should"
I'm trying to install a "PWM state" for the mosfet but the condition won't compile..I need help please.
MosfetState = LOW at start, and I can go HIGH, turns of no problem, but I can't figure out how to analogWrite(MosfetState, 180) as a State and get it to compile. Also I am not stopping the loop in any way, no delays () or state set intervals and I think I have to slow things down so it will actually turn off. Even when I State it LOW, the loop is too fast and it doesn't turn off at my trigger.
If this makes sense and someone would give me another jab in the right direction, I'll try one more day,lol, before I break and concede defeat....I love learning this thing but totally agree win your previous post, thanks so much for the help!
-
"If you want to increase your success rate, double your failure rate"
Thomas Watson
Chairman and CEO of IBM
I wouldn't think you would try to pulse the MOSFET as part of your loop (if I understand correctly) PWM is usually done in other ways - usually hardware. At most, the state machine would monitor battery charge and adjust the duty cycle of the PWM. Regardless of how the Arduino implements PWM, all you do is call it from the appropriate state.
It could be that the 'charge' state is where the state machine spends most of its time. Monitoring voltage, adjusting PWM and waiting until the charge is complete before changing state to 'done' or whatever.
Post your code and your schematic so we can take a look. Battery chargers just aren't that complex.
And never concern yourself with failure because
"Success is on the far side of failure"
also Thomas Watson
-
I don't think you have a clear idea of what you want to actually happen exactly and this is causing your problem.
Go back to basics, draw a flowchart.
A "state machine" as written above, can be thought of as a flowchart with each step is a state, you just keep track of which step you are in (state) and make the choices dictated by that step to decide which step you need to go to next.
You need to think especially about what precisely you want to happen when it's "finished", and how you determine it's "finished".
Do you want it to, for example, sit doing nothing.
Do you want it to, for example, wait until you put in a new cell and start the cycle again.
Do you want it to, for example, wait until you press a button and do something, if so, what.
You don't care if the cell voltage "bounces back" when the fet is switched off, if you have decisively moved onto doing something else, even if that something else is sitting doing nothing.
-
@Sleeman,
THIS IS ABOUT LEARNING THE BASICS! I know exactly what I want to do, but don't know HOW to do it. But thank you for the reply. I am working with SWITCH CASE now and trying to figure it out. Never been good with micros, but I built a wall of 50 similar testers using analog bits. - no pun intended, bit, micro haha. I am just learning here, no need to get hostile, unless I'm reading you wrong and your reply was in kind, and your just a blunt dude. The micro keeps seeing the bounce back in batt voltage and I don't want it to, that's my problem..I have three states but haven't implented them correvtly
@rstofer,
I have a low pass on the output smoothing the output for the Fet (Vt 2.7V) so I get a steady DC At the gate. It's to discharge test...I'll post it here for review and thanks again mate. I'd hug ya but a digital high five will have to work. ?
-
I will be interested to see the schematic. Operating a MOSFET as a linear device doesn't seem right but what do I know?
The short answer to "how to handle bounce back" is simple. You are in some state looking at the voltage while discharging and you decide that you have discharged low enough. So you transition to the next state where you remove the load by turning off the MOSFET. It's done and over with. You are no longer looking at the voltage during discharge so there is no chance you will turn the MOSFET back on. You are simply done and gone.
When you draw the state machine diagram or even just write sentences describing the state, what it does and how it transitions to other states, it will be very clear how to write the code.
Just remember, when you get to the state that shuts down the PWM and turns off the MOSFET that you will do those things and immediately transition to some other state where you will wait for some other condition.
I don't have a clue about what you are doing so I can't really say much about what the state after shutdown should do. Do you go back to the start state and wait for a button? Do you hang out in some idle state waiting for a power cycle (reset) or maybe wait for a different button. Blink an LED?
One thing about button presses, you need to have the inputs debounced and sometimes you need to wait for the button to be released. What you really want to find is an edge, not a level.
switch (state)
case press : if (button_pressed) { // this is pseudo code, button_pressed might be
// a pin input or a global variable or even a function call
state = release;
}
break;
case release: if (! button_pressed) {
state = begin; // we won't actually begin until the button is released
}
break;
case begin: // now we start the process
...
}
It depends on how you implement the button input routine. You could, for example, arrange to use the interrupt system to find the rising edge by using interrupt on change. In that case, the interrupt code would set a volatile global variable 'button_pressed'. It would only set it on the rising edge interrupt. Then, in the state machine, once you determine that 'button_pressed' has been set and you are just about to change state, set 'button_pressed' to 0. You have just 'eaten' the button pressed condition so if the switch is to be used later, it will need to generate another rising edge interrupt.
There is code out there in the wild that will show you how to use the interrupt-on-change feature. I didn't look at it.
https://playground.arduino.cc/Code/Interrupts
I realize that throwing out the concept of a volatile global variable seems over the top. Unfortunately, that's the proper way to do things. The compiler needs to know that the variable is volatile (can change outside the current function) or it will merrily optimize it away and toss any related code. The variable needs to be global (declared outside of any function, usually at the top of the code) because it needs to be shared between the interrupt routine (which sets the value) and the main() where the state machine code tests and resets the value. Just be sure to debounce the input. The input pins have a Schmitt Trigger as part of the input structure so a simple low pass filter should work fine for debouncing.
volatile int button_pressed = 0;
void interrupt_handler
{
// somehow we determine that a rising edge has occurred
button_pressed = 1;
}
void setup()
{
// set up interrupt-on-change to branch to interrupt_handler()
// see library code for examples
// ... do other setup stuff
}
void loop()
{
switch (state)
case press : if (button_pressed==1) { // wait for button press interrupt to set value to 1
button_pressed = 0; // we need to clear the variable before moving on
state = begin;
}
break;
case begin: // now we start the process
...
}
}
-
Not over the top at all. I understand it well, just learning how to code it. I am trying to get the controller to read the voltage and that alone determines the states. No extra buttons or inputs.
Once the test is over, the low_cutoff has been reached, I need to tell it to turn off AND stop looking AT the voltage, that's what I was missing. I had not thought about telling it that it was okay to stop reading voltage while in 'Done' state....
Let me try this and I'll be right back
-
You probably won't need it but here is an interrupt-on-change routine that actually works.
const byte ledPin = 13;
const byte interruptPin = 2;
volatile byte state = LOW;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blink, RISING);
}
void loop() {
digitalWrite(ledPin, state);
}
void blink() {
state = !state;
}
The pin input does need to be debounced and I haven't bothered with that. I found the code here:
https://www.arduino.cc/en/Reference/AttachInterrupt (https://www.arduino.cc/en/Reference/AttachInterrupt)
ETA: changed CHANGE to RISING in attachInterrupt.
-
I'll use it for sure, many thanks. Plan to make a few different models. It's for a small video series I am planning.
The circuit is just a current sink, like Dave Jones 'CC load' but the micro replaces the op amp. Trying to do it with just two wires to micro. This is important as I am trying to build the simplest possible discharge tester. And I am trying to use every pwm pin for fets. On the other designs I have the op amp in circuit as well and use one opamp input with gain to feedback the current sensing signal to the controller...but again, for this one, I am trying to do it with two wires off the controller...Gate and voltSensor_1. No additional buttons or sensors, just 1V out over 1 Ohm, which is why I want to PWM ,180 the gate, that setting (with 3055 Fet) lets 1V flow. I've plugged in several other fets and with gate HIGH I think it's a 3710 that gets around 9xx mA. But that's the run down of the design "idea" I may end up having to put a button because I'm still unable to implement the "states" correctly. I need to learn the coding rules and how to organize it to get my desired results.
I'm going to start the new try with:
Enum ( mosfetState_ON = HIGH, mosfetState_OFF= LOW, mosfetState_Wait = LOW)
I am using HIGH here because I don't know how to make the mosfetGate_PWM work.
-
enum mosfetState (mosfetState_ON = HIGH, mosfetState_OFF = LOW, mosfetState_DONE = LOW)
//add State definitions? read "google enum arduino examples"
const int VREF = 4.75;
const int off_Voltage = 3.00;
const int MosfetGatePin = 9;
const int Cell_1 = A5;//returns raw, float VIN_1
float VIN_1 = 0.0;
unsigned long previousMillis = 0.0;
unsigned long currentMillis = 0.0;
unsigned long mAh = 0.0;
void setup(){
Serial.begin(9600);
pinMode(MosfetGatePin,OUTPUT);
pinMode(Cell_1, INPUT);
}
void loop(){
VIN_1 = analogRead(Cell_1) * .00467;
if (VIN_1 > off_Voltage){
MosfetState = mosfetState_ON; // learn to make _ON = analogWrite(mosfetgatepin, 180).
previousMillis = millis() - currentMillis;
mAh = previousMillis /36000.0;
currentMillis = millis();
Serial.print ("V1 = ");
Serial.print (VIN_1);
Serial.print ("\t");
Serial.print ("mAh = ");
Serial.print (mAh);
Serial.println();
}
if(VIN_1 <= off_Voltage){
MosfetState = mosfetState_DONE; //learn to make' _DONE ' not see VIN so it will stay off,
}
digitalWrite(MosfetGatePin, MosfetState);
@rstofer,
This is what I have an my notes next to each entry that I know I need to try and learn. since its beautiful here in TN taking the family out to the pool for a while. back at it again this evening. thanks again for helping me learn
-
enum mosfetState (mosfetState_ON = HIGH, mosfetState_OFF = LOW, mosfetState_DONE = LOW)
That makes my eyes bleed. States are unique and should not be tied directly to the actual output of the device like this. The reason you use enum to define states is pretty much to ensure that they all have unique values.
-
Thanks mate, I found a instrumental series by "Gammon" that may help me learn. I know this is all wrong and that why it's not working correctly.
Here's the article:
http://www.gammon.com.au/statemachine (http://www.gammon.com.au/statemachine)
-
Would I be correct to say there are 4 states that I need to use:
1 waiting for test : here it is reading the voltage to see if it is able to test
2 on : testing
3 off : test over but still reading voltage
4 done: test over no longer reading voltage
Edit: because I am not using an external trigger like push button and the only way to reset the cycle is resting the Nano, I think 3 will work
--------------------------------------------------------
enum ( Mosfet_ON, Mosfet_OFF, Mosfet_DONE)
void loop(){
switch (MosfetState){
case Mosfet_OFF:
analogWrite (MosfetGatePIN, 180);
MosfetState = Mosfet_ON;
break;
Does this look like it's headed in the right direction?
-
Still having trouble getting the triggers in the right order/ code correct. would a delay help? and the mAh counter is not working like it should (because I am not sure if I have the bits in the right State- it didn't work when I had all of it in the ON state), but headed in the right direction. I can PWM the Gate now so theres one win..enough to make me keep at it
-
I think ive got it. In the case statement, I need to tell it what I want to to do, what action to perform while in that state, and I don't have to "switch" it out of that state because I have already set the "if" to do that above...ill be back soon with a report.
edit & update: alls well & finally working BUT I had to dump the PWM idea, it was the reason I was unable to keep the reading steady enough to get the Fet off. but with HIGH & LOW as STATES its a GO!
Thank you again RSTOFER for all the assistance.
-
@Beamin,
Once I try to rewrite the stats machines I'll post it. I want to try and figure it out on my own before I ask for "specific" assistance with writing it. I am trying to learn as I go and if someone posts the answer, I am not sure I ah e the will power to resist cheating..
I can guarantee I won't get it working but it won't for a different reason then your will. Ignorant minds think alike.