Hello.
Need some help and ideas in my first project.
I have idea to make small wind turbine automated dump load brake , but not like simple way shorting winding ore just with relays nonlinear dump loading.
Idea is in controller set up trigger voltage when the controller starts opening Mosfets to dump load exes energy to other load. But this going on in linear way. Example if trigger voltage 15V and control range be +/- 0.1V. Controller must fast opening or closing Mosfet to drain exes voltage to other source (resistor, water heater,...), and holding trigger voltage.
For this project I thing about some Arduino, voltage sense circuit, small LCD ore led segment display and buttons for trigger voltage setting and voltage reading, and mosfet control board.
I'm think use Arduino nano 3.0, TFT display with ST7735 Drive IC, couple simple buttons.
I'm not sure about voltage sense circuit if simple voltage divider can do. Input voltage will be 0-60V and have to be max precise. And not sure if Arduino can directly control big mosfets.
So I need help with precise voltage sens and mosfet driving circuits and some software basics.
You need a circuit that converts that input voltage range into corresponding MOSFET gate voltage (full OFF/ON). This circuit will control the current through the MOSFET and consequently the energy spent in the MOSFET (heat). A fixed resistor load in series with the MOSFET will help to distribute the heat between resistor and MOSFET. Depending on the heat a 12V fan can be added as both a load and cooling device for the bulk load.
Yes that's what I'm looking for. I think it's can be done in analog way. But try to make digital variant, because I want option to setting trigger voltage and see on display input voltage set trigger voltage and in the future more functions / parameters.
InputVoltage variables from 0.00 - 50.00
setVoltage = 12.00
If I understand correctly digital PWM out is from 0 to 255 digital and 0 - 5V analog.
I need that it's start output from 2-5V and only if InputVotage > setVoltage. And output rise exponential.
Did you read the documentation on the "map" function?
The map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged..
When using map(), it is important to know that it will happily extrapolate for input values outside the input domain, this is why it is often used with constrain(), for which casual searching turns up no corresponding floating point function.
But constraining either type is a few simple if statements.
For that matter, mapping either type is simple enough mathematics.
Hello,
slowly I'm getting some wear with my project, but I have small problem with stable input voltage reading. Right now input Voltage is unstable and jumping around 0.02V. Even if power supply and multi meter dose not.
Maybe there is some options to improve my code?
Did you read the documentation on the "map" function?
The map() function uses integer math so will not generate fractions, when the math might indicate that it should do so. Fractional remainders are truncated, and are not rounded or averaged..
If I understand correctly digital PWM out is from 0 to 255 digital and 0 - 5V analog.
I need that it's start output from 2-5V and only if InputVotage > setVoltage. And output rise exponential.
Exponential implies non-linearity, you might find this one useful
That could be noise, quantitation error or several other things. Your volt meter is dampened so it probably will not show that. Posting an annotated schematic showing exactly how this is wired will help solve the problem. Note any wires over 10"/25cm.
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
#include <math.h>
#include <averager.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const int voltageSensePin = A1; // Voltage sense pin
const int upButtonPin = 2; // Pin number for the "UP" button
const int downButtonPin = 3; // Pin number for the "DOWN" button
const int analogOutPin = 9; // Pin number for analog output
const int setButtonHoldTime = 4000; // Time to hold the button for entering setting mode (4 seconds)
float setVoltage = 10.00; // Set voltage in setting mode
bool settingMode = false; // Flag to indicate if in setting mode
unsigned long lastButtonPressTime = 0; // Variable to store the time of the last button press
unsigned long readingSum = 0;
float alpha = 0.05;
averager<float> average;
float vIN = 0.00;
float R1 = 15850.0;
float R2 = 1174.0;
float Vdata = 0;
float vRaw=0;
int Vtest = 0;
void setup() {
Serial.begin(9600);
pinMode(upButtonPin, INPUT_PULLUP); // Set the "UP" button pin as an input with pull-up resistor
pinMode(downButtonPin, INPUT_PULLUP); // Set the "DOWN" button pin as an input with pull-up resistor
pinMode(analogOutPin, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.setTextSize(2);
display.display(); // Clear the display buffer
delay(2000); // Pause for 2 seconds
display.clearDisplay(); // Clear the display
average.setExponentialMovingAverageAlpha(alpha);
int address = 0;
EEPROM.get(address, setVoltage);
setVoltage = constrain(setVoltage, 10.00, 50.00);
}
void loop() {
for(int i = 0; i < 100; i++){
Vdata = Vdata + analogRead(voltageSensePin);
delayMicroseconds(20);
}
Vdata = Vdata / 100;
vRaw = ((Vdata*5.0) / 1024.0 / (R2/(R1+R2)));
uint16_t new_value = analogRead(voltageSensePin);
average.updateExponentialMovingAverage(new_value);
vIN = ((average.getExponentialMovingAverage()*5.0) / 1024.0 / (R2/(R1+R2)));
// Check if in setting mode
if (settingMode) {
handleSettingMode();
} else {
updateDisplay("IN", vIN);
// Read the state of the "UP" and "DOWN" buttons
int upButtonState = digitalRead(upButtonPin);
int downButtonState = digitalRead(downButtonPin);
// Check if either button is pressed
if (upButtonState == LOW || downButtonState == LOW) {
lastButtonPressTime = millis();
}
// Check if the "UP" button is pressed and enter setting mode
if (upButtonState == LOW && downButtonState == HIGH) {
enterSettingMode();
}
// Check if the "DOWN" button is pressed and enter setting mode
if (downButtonState == LOW && upButtonState == HIGH) {
enterSettingMode();
}
}
adjustAnalogOutput();
// Check for inactivity to save set voltage to EEPROM
if (millis() - lastButtonPressTime > setButtonHoldTime && settingMode) {
saveSetVoltageToEEPROM();
settingMode = false;
}
}
void enterSettingMode() {
settingMode = true;
lastButtonPressTime = millis(); // Update the time of the last button press
display.clearDisplay(); // Clear the display
int address = 0;
EEPROM.get(address, setVoltage);
// Check if the read value is a valid number
if (isnan(setVoltage) || setVoltage < 10.00 || setVoltage > 50.00) {
// If not valid, set a default value
setVoltage = 10.00;
}
updateDisplay("Set", setVoltage); // Update the display with set voltage
delay(1000);
}
void handleSettingMode() {
// Read the state of the "UP" and "DOWN" buttons
int upButtonState = digitalRead(upButtonPin);
int downButtonState = digitalRead(downButtonPin);
// Check if the "UP" button is pressed and adjust set voltage
if (upButtonState == LOW && downButtonState == HIGH) {
setVoltage += 0.05;
delay(100); // Debounce delay
lastButtonPressTime = millis(); // Update the time of the last button press
}
if (downButtonState == LOW && upButtonState == HIGH) {
setVoltage -= 0.05;
delay(100); // Debounce delay
lastButtonPressTime = millis(); // Update the time of the last button press
}
setVoltage = constrain(setVoltage, 10.00, 50.00);
updateDisplay("Set", setVoltage);
}
void updateDisplay(String mode, float value) {
display.clearDisplay();
display.setTextSize(2); // Clear the display
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.print(mode + ":");
display.print(value, 2); // Display value with two decimal places
display.display();
}
void adjustAnalogOutput() {
float deltaV=(vIN - setVoltage+0.1)*1000;
Vtest = map(deltaV,0,300,0,255);
Vtest = constrain(Vtest,0,255);
analogWrite(analogOutPin, Vtest);
if(Vtest>0){
digitalWrite(LED_BUILTIN, HIGH);
}
else {digitalWrite(LED_BUILTIN, LOW);}
if((vRaw -setVoltage) > 0.5){
analogWrite(analogOutPin,255);
}
}
void saveSetVoltageToEEPROM() {
int address = 0;
EEPROM.put(address, setVoltage);
}
you need to check where you can "help" your floating point operations.
Float divisions are the worst performant. However often can be replaced with multiplication.
A blocking loop during the analogReads does also eat CPU cycles.
Look at this snippet
void loop()
{
// do you need 100? what happens when going to 50, 20, 10 or even 1?
for (int i = 0; i < 100; i++) {
Vdata = Vdata + analogRead(voltageSensePin);
delayMicroseconds(20); // <<<<<<<<<<< sums up to 2 milliseconds per loop
}
Vdata = Vdata * 0.01; // replace expensive division
vRaw = Vdata * (5.0 / 1024.0 / (R2/(R1+R2)));
// As (5.0 / 1024.0 ) * (R1+R2) / R1; is a constant, calculate it compile time
The latter could be a global var that needs to be calculated once.
Does it help with precision, if I measure VCC with 1.1V build in reference voltage. and then use this voltage to other measurements that use VCC as reference?
Or better get stable VCC 5.00v and forget.