This sketch listens on 115200 baud. You enter the voltage (0 to 5 volts), it reproduces it with PWM.
Pretty simple, yet pretty dramatic.
I tested its accuracy with a multimeter. 8-bit accuracy ![]()
Note: This requires the Streaming library to compile. You can just use a series of Serial.print and println statements instead, but Streaming just makes it easier. (Face it, I love C++ streams) ![]()
#include <SoftwareSerial.h>
#include <Streaming.h>
// Required for memory functions
#include <stdlib.h>
// Required for modf() and fabs()
#include <math.h>
// Maximum length of serial input
#define MAX_LEN 16
// PWM pin of your choice
#define PWM_PIN 12
// Onboard LED
#define LED 13
// Serial data rate
#define BAUD 115200
// The index for serial to char * conversion
static int a = 0;
// Storage for the serial input
static char * volt_char = NULL;
// Storage for the voltage
static double volts;
void setup()
{
// Set pin modes
pinMode( PWM_PIN, OUTPUT );
pinMode( LED, OUTPUT );
// Turn on PWM output
digitalWrite( PWM_PIN, HIGH );
// Allocate storage
volt_char = (char *)calloc( MAX_LEN, sizeof( char ) );
// Start serial
Serial.begin( BAUD );
// Initial message!
Serial << "Enter voltage level: ";
}
void loop()
{
// Poll serial
while( Serial.available() > 0 ) {
// Get characters
if( a < MAX_LEN )
volt_char[a] = char( Serial.read() );
else
{
// Tell the user and flush serial input
Serial << "Too long" << endl << "Enter voltage level: ";
Serial.flush();
// Reset vars and clear memory
a = 0;
memset( volt_char, 0x00, MAX_LEN );
break;
}
// Increase character index
a++;
// Wait for serial to catch up. Change as needed.
delay( 1 );
}
if( a > 0 )
{
// LED on
digitalWrite( LED, HIGH );
// No negatives. Convert the char * to a double.
volts = fabs( atof( (const char *)volt_char ) );
// Sort out invalid voltages
if( ( volts < 1.00 && ( volt_char[0] == '0' || volt_char[0] == '.' ) ) || ( volts >= 1.00 && volts <= 5.00 && volts != 0.00 && volt_char[0] != '0' ) || ( volts == 0.00 && ( volt_char[0] == '0' || volt_char[0] == '.' ) ) )
{
// Set up three vars to hold the parts of the voltage
double pwm = ( volts / 5.00 ) * 255.00, fractpart, intpart;
// fractpart: Decimal part, intpart: integral part
fractpart = modf( pwm, &intpart );
// Round the integer part based upon the fractional part
if( fractpart >= 0.5 )
intpart += 1.0;
// Set the voltage
analogWrite( PWM_PIN, floor( intpart ) );
// Output a message
Serial << volts << "... OK";
}
else if( volts > 5.00 )
Serial << "Too high";
else
Serial << "Invalid";
// Output the standard message
Serial << endl << "Enter voltage level: ";
// Clear memory
memset( volt_char, 0x00, MAX_LEN );
a = 0;
// LED off
digitalWrite( LED, LOW );
}
// Wash, rinse, repeat.
}