Help with the Math

Hi All,
I've been working on a project for a while now and I think I'm 95% of the way there.
It's a mosfet and driver circuit with an OLED display.

I want it to be able to self regulate current at a value that will be set via potentiometer.
I'm using a CQ2064 current sensor Data Sheet Here and a 10K pot.

The brains of the operation is the Arduino Every and there is an opto isolated driver for the mosfet connected to pin 3 for PWM.

I don't have all the components to complete the connection to the mosfet but the driver is connected to the Arduino. When I power up, the display works and displays all the values as one would think is correct. Raw Amps reads 0, Volts/Cell read 2.5v but this is not connected, Duty Cycle reads 0% and the Target Amps reads between 7 and 10.

The thing that confuses me during testing is there is 0v on pin 3 regardless of where the target amps are set. If the sketch is correct there should be 5v on pin 3 because there is not enough Raw Amps to meet the Target Amps.

#include <Ewma.h>
#include <Arduino.h>
#include <U8g2lib.h>

#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

Ewma adcFilter1(0.005);
Ewma adcFilter2(0.003);
Ewma adcFilter3(0.005);

byte targetPotPin = A5; 
byte voltSensePin = A3;
byte currentSensePin = A0; 
byte mosfet = 3;

int targetVal = 0;
int targetPotVal = 0;
int voltageVal = 0;
int dutyCyclePercent = 0;
int dutyCycle = 0;

float target = 0.0;
float targetBuffer = 0.03;
float current = 0.0;
float currentVal = 0.0;
float voltage = 0.0;
float currentForDisplay = 0.0;
float correctedCurrent = 0.0;

const float maxCurrent = 11.0;
const float minVolts = 1.4;
const float maxVolts = 2.1;
const float referenceVolts = 5.0;

unsigned long currentTime = 0;
unsigned long prevTime = 0;
unsigned long prevVoltTestTime = 0;

U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, 10, 9, 8); //Duinotech 7 pin 1.3" OLED from Jaycar.
// CS = 10; DC = 9; RES = 8; CLK = 13; MOSI = 11; --- Pins 13 and 11 aren't defined but need to be connected.

//U8G2_SSD1306_128X64_NONAME_1_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE);
//DFR0650 OLED DISPLAY. ON ARDUINO NANO EVERY: SCL = A5; SDA = A4;

const uint8_t tile_area_x_pos = 9;  // Update area left position (in tiles. 1 tile = 10 cursor)
const uint8_t tile_area_y_pos = 0;  // Update area upper position (distance from top in tiles)
const uint8_t tile_area_width = 5;
const uint8_t tile_area_height = 8; // this will allow cour18 chars to fit into the area
const u8g2_uint_t pixel_area_x_pos = tile_area_x_pos*8;
const u8g2_uint_t pixel_area_y_pos = tile_area_y_pos*8;
const u8g2_uint_t pixel_area_width = tile_area_width*8;
const u8g2_uint_t pixel_area_height = tile_area_height*8;


//------------------------------------//
void setup() {

//Serial.begin(115200);

  pinMode(mosfet, OUTPUT);
  digitalWrite(mosfet, LOW);
  
  u8g2.begin();
  u8g2.enableUTF8Print();    // enable UTF8 support for the Arduino print() function
  
  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_prospero_nbp_tr);
  u8g2.setCursor(19, 17);
  u8g2.print("Duty Cycle:");
  u8g2.setCursor(10, 31);
  u8g2.print("Target Amps:");
  u8g2.setCursor(27, 45);
  u8g2.print("Raw Amps:"); 
  u8g2.setCursor(21, 60);
  u8g2.print("Volts/Cell:"); 
  u8g2.sendBuffer();

}

//------------------------------------//
void loop() {

currentTime = millis();

   if(currentTime - prevTime >= 300){
      updateOLED();
      prevTime = currentTime;
   }    

   targetPotVal = analogRead(targetPotPin);
   currentVal = analogRead(currentSensePin);  
   voltageVal = analogRead(voltSensePin);
   
   int filteredTarget = adcFilter1.filter(targetPotVal);
   int filteredCurrent = adcFilter2.filter(currentVal);
   int filteredVoltage = adcFilter3.filter(voltageVal);

          /*-----------------------------------------------------------
           initialize current sensor. 0 current will read 2.5v on analog
           pin, so this will now write a value between -60 and +60amps
           -----------------------------------------------------------*/ 
   current = (2.5 - (filteredCurrent / 1024.0) * referenceVolts) / -0.04;

          /*-----------------------------------------------------------
           Map target amps to a value between 7.00amps and 10.00amps
           -----------------------------------------------------------*/     
   int val = (filteredTarget * 10); 
   val = map(val, 0, 10230, 70, 101);
   target = val / 10.0;
   
          /*-----------------------------------------------------------
           Increase or decrease current to match targetCurrent
           -----------------------------------------------------------*/         
   if(current <= (target - targetBuffer)){
      correctedCurrent = current + 0.1;
   }
   else if(current >= (target + targetBuffer)){
      correctedCurrent = current - 0.1;
   } 

          /*-----------------------------------------------------------
           Convert correctedCurrent to PWM value and write to mosfet pin
           -----------------------------------------------------------*/ 
   dutyCycle = (correctedCurrent / 60.0) * 255.0;
   analogWrite(mosfet, dutyCycle);
   
           /*-----------------------------------------------------------
            Calculate values for volts and dutycycle for display readout
            -----------------------------------------------------------*/
   voltage = (filteredVoltage / 1023.0) * referenceVolts;
   
   dutyCyclePercent = (dutyCycle/255.0)*100;

 /*  if(currentTime - prevVoltTestTime >= 5000){
      while(voltage <= minVolts){
         analogWrite(mosfet, LOW);
         u8g2.clearBuffer();
         u8g2.setFont(u8g2_font_prospero_nbp_tr);
         u8g2.setCursor(8, 25);
         u8g2.print("<--Low Cell Voltage-->");
         u8g2.setCursor(11, 50);
         u8g2.print("Shutdown Immediately!");
         u8g2.sendBuffer();
      }
      while(voltage >= maxVolts){
         analogWrite(mosfet, LOW);
         u8g2.clearBuffer();
         u8g2.setFont(u8g2_font_prospero_nbp_tr);
         u8g2.setCursor(6, 25);
         u8g2.print("<--High Cell Voltage-->");
         u8g2.setCursor(11, 50);
         u8g2.print("Shutdown Immediately!");
         u8g2.sendBuffer();
      }
      while(current >= maxCurrent){
         analogWrite(mosfet, LOW);
         u8g2.clearBuffer();
         u8g2.setFont(u8g2_font_prospero_nbp_tr);
         u8g2.setCursor(1, 25);
         u8g2.print("Max Amperage Exceeded!");
         u8g2.setCursor(11, 50);
         u8g2.print("Shutdown Immediately!");
         u8g2.sendBuffer();
      }
      prevVoltTestTime = currentTime;
   }*/
}

//-------------------------------------//
void updateOLED(){
  
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_prospero_nbp_tr);
    u8g2.setCursor(85, 17);
    u8g2.print(dutyCyclePercent);
    u8g2.setCursor(100, 15);
    u8g2.print("%");
    u8g2.setCursor(85, 31);
    u8g2.print(target);
    u8g2.setCursor(85, 45);
    u8g2.print(current);
    u8g2.setCursor(85, 60);
    u8g2.print(voltage);
    u8g2.setDrawColor(1);
    u8g2.updateDisplayArea(tile_area_x_pos, tile_area_y_pos, tile_area_width, tile_area_height);

}

All your words do not mean much without a schematic. Sorry.

1 Like

https://hackaday.com/2014/04/29/a-simple-programmable-electronic-load-using-the-arduino

https://blog.arduino.cc/2018/08/27/create-a-constant-current-and-power-load-with-arduino/
Similar ideas

Here is an updated circuit with a different current sensor that's connected to A7 instead of A0 but the rest is the same as the board I'm testing on. The board I'm testing has the CQ2064 sensor installed.

Just realized I haven't change the mosfet label. It's an IRFP044NPBF.

Figured out why it was holding pin 3 at zero volts. Was simple to once I saw it. All that was needed was to change this line correctedCurrent = current + 0.1; to this correctedCurrent = correctedCurrent + 0.1;

Once it started working I also found that the dutyCycle would keep on incrementing so I modified this section,

   if(current <= (target - targetBuffer)){
      correctedCurrent = current + 0.1;
   }
   else if(current >= (target + targetBuffer)){
      correctedCurrent = current - 0.1;
   } 

To this

   if(current <= (target - targetBuffer)){
      if(dutyCycle <= 255.0){      // incrementing
          correctedCurrent = correctedCurrent + 0.1;    
      }
      else if(dutyCycle > 255.0){
          correctedCurrent = correctedCurrent -0.1;    
      }
   }
   else {    // decrementing
      correctedCurrent = correctedCurrent - 0.1;
   }

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.