The code below is a simple one to get a ramp voltage output from a DAC once the user enters the Start Time , End Time, Start Voltage , End Voltage.
Since I will be using this very often in a code with different ramp rates, I want to be able to convert this to a sub routine with the four parameters as arguments to the function.
I think I need to have a function which does all the calculations once and runs the iterations from the next call onwards. Any other better idea ?? Thanks
#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
// Set this value to 9, 8, 7, 6 or 5 to adjust the resolution
#define DAC_RESOLUTION (9)
float rampStartVal = 1 , rampEndVal = 2;
float rampStartSec = 0, rampEndSec = 5;
uint16_t rampVal ;
float rampCount;
float rampValTotal;
uint16_t perCountRampVal;
uint16_t dacStartCode;
uint16_t dacEndCode;
unsigned long dacUpdateInterval = 50, dacUpdateMs = millis();
void setup(void) {
Serial.begin(9600);
// For Adafruit MCP4725A1 the address is 0x62 (default) or 0x63 (ADDR pin tied to VCC)
// For MCP4725A0 the address is 0x60 or 0x61
// For MCP4725A2 the address is 0x64 or 0x65
dac.begin(0x62);
dac.setVoltage(0, false); // Initialize the DAC output to zero
rampCount = ((rampEndSec - rampStartSec ) * 1000) / dacUpdateInterval; // Find the number of iterations required
rampValTotal = ( rampEndVal - rampStartVal ) * 1000; // Find the absolute value of voltage increase
perCountRampVal = (( rampValTotal / rampCount ) * 4095) / 5000; // Find the per iteration voltage increment
dacStartCode = rampStartVal * 1000 * 4095 / 5000; // Start count for DAC
dacEndCode = rampEndVal * 1000 * 4095 / 5000; // End count for DAC
rampVal = dacStartCode; // Preload the DAC with start count.
}
void loop(void) {
if ( millis() - dacUpdateMs > dacUpdateInterval ) {
dacUpdateMs = millis();
if ( rampVal < dacEndCode ) {
rampVal = perCountRampVal + rampVal;
dac.setVoltage(rampVal, false);
}
}
}
you could abstract that into a class offering a ramp-up or ramp-down capability.
with the use of a timer the class could auto-trigger or you could have a class method that you call from the loop "often enough" which handles all the instances and see if a step needs to be taken
A function passed 4 parameters sounds like the right idea but if the variables are declared global there is no need to pass them. Both ways have advantages and disadvantages
In the sketch that you posted all of the variables are global so you could just put any code in a function and call it, like this
#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
// Set this value to 9, 8, 7, 6 or 5 to adjust the resolution
#define DAC_RESOLUTION (9)
float rampStartVal = 1 , rampEndVal = 2;
float rampStartSec = 0, rampEndSec = 5;
uint16_t rampVal ;
float rampCount;
float rampValTotal;
uint16_t perCountRampVal;
uint16_t dacStartCode;
uint16_t dacEndCode;
unsigned long dacUpdateInterval = 50, dacUpdateMs = millis();
void setup(void)
{
Serial.begin(9600);
// For Adafruit MCP4725A1 the address is 0x62 (default) or 0x63 (ADDR pin tied to VCC)
// For MCP4725A0 the address is 0x60 or 0x61
// For MCP4725A2 the address is 0x64 or 0x65
dac.begin(0x62);
dac.setVoltage(0, false); // Initialize the DAC output to zero
calculate();
}
void loop(void)
{
if ( millis() - dacUpdateMs > dacUpdateInterval )
{
dacUpdateMs = millis();
if ( rampVal < dacEndCode )
{
rampVal = perCountRampVal + rampVal;
dac.setVoltage(rampVal, false);
}
}
}
void calculate()
{
rampCount = ((rampEndSec - rampStartSec ) * 1000) / dacUpdateInterval; // Find the number of iterations required
rampValTotal = ( rampEndVal - rampStartVal ) * 1000; // Find the absolute value of voltage increase
perCountRampVal = (( rampValTotal / rampCount ) * 4095) / 5000; // Find the per iteration voltage increment
dacStartCode = rampStartVal * 1000 * 4095 / 5000; // Start count for DAC
dacEndCode = rampEndVal * 1000 * 4095 / 5000; // End count for DAC
rampVal = dacStartCode; // Preload the DAC with start count.
}
How complex is this going to become? Could there be multiple DACs eventually? Do you need to worry about overlap.
I was going to suggest putting your parameters in a struct, including time in millis when the ramp started and pass it to your function by reference. I like @J-M-L's solution better.
Okay I tried my own way and came up with this. Not too bad I think. I now only have to figure out a way to know when the ramp has reached the required level. Maybe I will need to work out something within the function and pass the status as a boolean ?
#include <Wire.h>
#include <Adafruit_MCP4725.h>
Adafruit_MCP4725 dac;
// Set this value to 9, 8, 7, 6 or 5 to adjust the resolution
#define DAC_RESOLUTION (9)
unsigned long dacUpdateInterval = 50, dacUpdateMs = millis();
void setup(void) {
Serial.begin(9600);
// For Adafruit MCP4725A1 the address is 0x62 (default) or 0x63 (ADDR pin tied to VCC)
// For MCP4725A0 the address is 0x60 or 0x61
// For MCP4725A2 the address is 0x64 or 0x65
dac.begin(0x62);
dac.setVoltage(0, false); // Initialize the DAC output to zero
}
//=========================
void loop(void) {
rampUpVoltage( 0.5, 4.5, 0, 5);
}
//=========================
void rampUpVoltage ( float rampStartVal, float rampEndVal, float rampStartSec, float rampEndSec) {
float rampCount;
float rampValTotal;
float perCountRampVal;
float dacStartCode;
float dacEndCode;
rampCount = ((rampEndSec - rampStartSec ) * 1000) / dacUpdateInterval; // Find the number of iterations required
rampValTotal = ( rampEndVal - rampStartVal ) * 1000; // Find the absolute value of voltage increase
perCountRampVal = ( rampValTotal / rampCount ) * 4095 / 5000; // Find the per iteration voltage increment
dacStartCode = rampStartVal * 1000 * 4095 / 5000; // Start count for DAC
dacEndCode = rampEndVal * 1000 * 4095 / 5000; // End count for DAC
uint16_t static rampVal = dacStartCode ;
if ( millis() - dacUpdateMs > dacUpdateInterval ) {
dacUpdateMs = millis();
if ( rampVal <= dacEndCode ) {
rampVal += perCountRampVal ;
dac.setVoltage(uint16_t(rampVal), false);
}
}
}