I've been trying to figure out how we could create a software PWM via arduino's digital pin. The current arduino supplies only 3 pins for PWM, which wasn't enough to drive our light dislay. The key in making this happen was to not use any delays at all. There are still some issues with the brightness of the LED's, but that should be easy to solve with some tweaking.
Code in next page
// software pwm
// trying to replicate photo sensing tube on a 11 to 6 scale
// how many sensors and lights we have
#define TOTAL_SENSORS 6
#define TOTAL_LIGHTS 11
// constants for duration
// change max to have longer duration
// change consts for faster charge up
#define DURATION_MAX 100
#define DURATION_DIV 1
#define DURATION_CONSTS 5
//#define DEBUG_SENSOR_RAW 1
//#define DEBUG_SENSOR_DURATION 1
// values
int analog_value[TOTAL_SENSORS] = { 0,0,0,0,0,0 };
int analog_duration[TOTAL_SENSORS] = { 0,0,0,0,0,0 };
int sensor_light_map[TOTAL_LIGHTS] = {0,2,4,6,8,10};
// need work on calcibration
boolean below_threshold ( int pin, int value ) {
switch(pin) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
if ( value < 20 ) return true;
break;
}
return false;
}
void read_sensor_input() {
//Serial.println("reading sensor input ");
byte ii;
int new_value = 0;
for ( ii = 0; ii < TOTAL_SENSORS; ii++ ) {
new_value = analogRead(ii);
#ifdef DEBUG_SENSOR_RAW
Serial.print(ii,DEC);
Serial.print(" got value ");
Serial.println(new_value,DEC);
#endif
if ( below_threshold(ii,new_value)) {
#ifdef DEBUG_SENSOR_DURATION
Serial.print(ii,DEC);
Serial.print("is on - duration is ");
Serial.println(analog_duration[ii],DEC);
#endif
analog_duration[ii] = analog_duration[ii] + DURATION_CONSTS;
if ( analog_duration[ii] > DURATION_MAX ) analog_duration[ii] = DURATION_MAX;
analog_value[ii] = 1;
} else {
#ifdef DEBUG_SENSOR_DURATION
Serial.print(ii,DEC);
Serial.print("is off - duration is ");
Serial.println(analog_duration[ii],DEC);
#endif
if ( analog_duration[ii] > 0 ) analog_duration[ii]--;
analog_value[ii] = 0;
}
}
}
// compute light routine ///////////////////////////////////////////////////////////////////////
void interpolate_light () {
// hard code these
code_pwm(1,(get_pwm(0)+get_pwm(2))/2);
code_pwm(3,(get_pwm(2)+get_pwm(4))/2);
code_pwm(5,(get_pwm(4)+get_pwm(6))/2);
code_pwm(7,(get_pwm(6)+get_pwm(8))/2);
code_pwm(9,(get_pwm(8)+get_pwm(10))/2);
}
void compute_light () {
byte ii;
// assign index values
for ( ii = 0; ii < TOTAL_SENSORS; ii++ ) {
if ( analog_value[ii] == 1 ) {
code_pwm(sensor_light_map[ii],100);
} else {
// a simple formula to translate duration to light values
// the longer the duraiton the slower the light values decrease
if ( analog_duration[ii] > 0 ) {
code_pwm(sensor_light_map[ii],analog_duration[ii] / DURATION_DIV);
}
if ( analog_duration[ii] <= 0 ) {
code_pwm(sensor_light_map[ii],0); // no more light values give it 0
}
}
}
interpolate_light();
}
// main //////////////////////////////////////////////////////////////////////////////////
void setup() {
int ii;
for ( ii = 2; ii < 2 + TOTAL_LIGHTS; ii++ )
pinMode(ii,OUTPUT); // start from pin 2 for some reason when i use 0 and 1 i cant upload code to arduino??!?!
Serial.begin(9600);
}
void loop () {
read_sensor_input();
compute_light();
perform_pwm();
}
// software pwm code ///////////////////////////////////////////////////////////////////////
#define SW_PWM TOTAL_LIGHTS
int sw_pwm_time_on[SW_PWM] = {0,0,0,0,0,0,0,0,0,0,0};
int sw_pwm_pin_map[SW_PWM] = {2,3,4,5,6,7,8,9,10,11,12};
int get_pwm ( int which_pin ) {
return sw_pwm_time_on[which_pin];
}
void code_pwm ( int which_pin, int percent ) {
// translate percentage to a scale of SW_PWM_TOTAL_TIME
sw_pwm_time_on[which_pin] = percent;
}
void perform_pwm() {
int ii, jj;
// init
for ( ii = 0; ii < SW_PWM; ii++ ) {
if ( sw_pwm_time_on[ii] > 0 ) {
digitalWrite(sw_pwm_pin_map[ii],HIGH);
}
}
// do actual looping
for ( jj = 0; jj < 100; jj++ ) {
for ( ii = 0; ii < SW_PWM; ii++ ) {
if ( sw_pwm_time_on[ii] < 0 ) {
digitalWrite(sw_pwm_pin_map[ii],LOW);
}
sw_pwm_time_on[ii]--;
}
}
}
// end software pwm code ///////////////////////////////////////////////////////////////////