From eb26ecc53cac3453f083fefa643cdcff13ba8a06 Mon Sep 17 00:00:00 2001 From: "jon.langseth@lilug.no" Date: Mon, 29 Aug 2011 14:37:12 +0200 Subject: [PATCH] Initial code import, contains "fairly runnable" RCTXDuino code. --- README | 3 + hardware/README | 4 + hardware/prototype_1/rctxduino.sch | Bin 0 -> 84060 bytes source/RCTXDuino/RCTXDuino.pde | 720 +++++++++++++++++++++++++++++ source/README | 3 + tools/README | 6 + 6 files changed, 736 insertions(+) create mode 100644 README create mode 100644 hardware/README create mode 100644 hardware/prototype_1/rctxduino.sch create mode 100644 source/RCTXDuino/RCTXDuino.pde create mode 100644 source/README create mode 100644 tools/README diff --git a/README b/README new file mode 100644 index 0000000..4ca7df0 --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +All the README files in this project are going to +need updating with useful content. Just adding +some README files with dummylike content first. diff --git a/hardware/README b/hardware/README new file mode 100644 index 0000000..1c09113 --- /dev/null +++ b/hardware/README @@ -0,0 +1,4 @@ +Anticipating several versions/editions before a final design +of the hardware is landed, this directory is split up from the +start. This way, we do not have to throw away the old designs +to make room for new ones :P diff --git a/hardware/prototype_1/rctxduino.sch b/hardware/prototype_1/rctxduino.sch new file mode 100644 index 0000000000000000000000000000000000000000..839c46b15611a9a8fd91f3188133f444edcef86b GIT binary patch literal 84060 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 D>HZSX literal 0 HcmV?d00001 diff --git a/source/RCTXDuino/RCTXDuino.pde b/source/RCTXDuino/RCTXDuino.pde new file mode 100644 index 0000000..cf711bb --- /dev/null +++ b/source/RCTXDuino/RCTXDuino.pde @@ -0,0 +1,720 @@ +#include +#include + +// --------------- ADC related stuffs.... -------------------- + +int maxval[8]; // Stores maximum values read during calibration, setup() sets 1024 +int minval[8]; // Stores minimum values read during calibration, setup() sets 0 +int rev[8]; +int dr[8]; // The Dual-rate array uses magic numbers :P +/* dr[0] = Input channel #1 of 2 for D/R switch #1. 0 means off, 1-4 valid values. + dr[1] = Input channel #2 of 2 for D/R switch #1. 0 means off, 1-4 valid values. + dr[2] = Input channel #1 of 2 for D/R switch #2. 0 means off, 1-4 valid values. + dr[3] = Input channel #2 of 2 for D/R switch #2. 0 means off, 1-4 valid values. + dr[4] = D/R value for switch # 1 LOW(off). Value -100 to 100 in steps of 5. + dr[5] = D/R value for switch # 1 HIGH(on). Value -100 to 100 in steps of 5. + dr[6] = D/R value for switch # 1 LOW(off). Value -100 to 100 in steps of 5. + dr[7] = D/R value for switch # 1 HIGH(on). Value -100 to 100 in steps of 5. +*/ + +volatile float channel[8]; + +// ----------------- Display related stuffs -------------------- +LiquidCrystal lcd( 12, 11, 10, 6, 7, 8, 9); +// Parameters are: rs, rw, enable, d4, d5, d6, d7 pin numbers. + +// ----------------- PPM related stuffs ------------------------ +// The PPM generation is handled by Timer0 interrupts, and needs +// all modifiable variables to be global and volatile... +int max_channels = 6; // How many channels should PPM generate ... +volatile long sum = 0; // Frame-time spent so far +volatile int cchannel = 0; // Current channnel +volatile bool do_channel = true; // Is next operation a channel or a separator + +// All time values in usecs +// TODO: +// The timing here (and/or in the ISR) needs to be tweaked to provide valid +// RC PPM signals accepted by standard RC RX'es and the Microcopter... +long framelength = 21500; // Max length of frame +long seplength = 400; // Lenght of a channel separator +long chmax = 1700; // Max lenght of channel pulse +long chmin = 600; // Min length of channel +long chwidht = (chmax - chmin); // Useable time of channel pulse (1000) + +// ----------------- Menu/IU related stuffs -------------------- + +// Keys/buttons/switches for UI use, including dual-rate/expo +// are digital inputs connected to a 4051 multiplexer, giving +// 8 inputs on a single input pin. +#define KEY_UP 0 +#define KEY_DOWN 1 +#define KEY_RIGHT 2 +#define KEY_LEFT 3 +#define KEY_INC 4 +#define KEY_DEC 5 +#define KEY_DR1 6 +#define KEY_DR2 7 + +// Voltage sense pin is connected to a 1/3'd voltage divider. +#define BATTERY_CONV (10 * 3 * (5.0f/1024.0f)) +#define BATTERY_LOW 92 + +enum { + VALUES, + BATTERY, + TIMER, + MENU +} +displaystate; + +enum { + TOP, + INVERTS, + DUALRATES, + EXPOS, // Some radios have "drawn curves", i.e. loopup tables stored in external EEPROM ... + DEBUG, + SAVE +} +menu_mainstate; +int menu_substate; + +boolean keys[8]; +boolean prev_keys[8]; + +int battery_val; + +// The display/UI is handled only when more +// than UI_INTERVAL milliecs has passed since last... +#define UI_INTERVAL 250 +unsigned long last = 0; + +unsigned long timer_start = 0; +unsigned long timer_init = 0; +unsigned long timer_value = 0; +boolean timer_running = false; + +// ----------------- DEBUG-STUFF -------------------- +unsigned long prev_loop_time; +unsigned long avg_loop_time; +unsigned long t; + + +// ---------- CODE! ----------------------------------- + +// ---------- Arduino SETUP code ---------------------- +void setup(){ + pinMode(13, OUTPUT); // led + + pinMode(2, OUTPUT); // s0 + pinMode(3, OUTPUT); // s1 + pinMode(4, OUTPUT); // s2 + pinMode(5, OUTPUT); // e + + lcd.begin(16,2); + lcd.print("Starting...."); + + Serial.begin(9600); + Serial.println("Starting...."); + delay(500); + read_settings(); + scan_keys(); + if ( keys[KEY_UP]) + calibrate(); + + pinMode(A5, OUTPUT); // PPM output pin + do_channel = false; + set_timer( seplength ); + Timer1.initialize(framelength); + Timer1.attachInterrupt(ISR_timer); + + displaystate = VALUES; + + // Arduino believes all pins on Port C are Analog. + // In reality they are tri-purpose; ADC, Digital, Digital Interrupts + // Unfortunately the interrupt mode is unusable in this scenario, but digital I/O works :P + pinMode(A2, INPUT); + + // Debugging: how long does the main loop take on avg... + t = micros(); + avg_loop_time = t; + prev_loop_time = t; + + dr[0] = dr[1] = dr[2] = dr[3] = 0; + dr[4] = dr[5] = dr[6] = dr[7] = 100; + +} + +// ---------- Arduino main loop ----------------------- +void loop () { + + // Determine if the UI needs to run... + boolean disp; + if ( millis() - last > UI_INTERVAL ) { + last = millis(); + disp = true; + } + else disp = false; + + process_inputs(); + + // Wasting a full I/O pin on battery status monitoring! + battery_val = analogRead(1) * BATTERY_CONV; + if ( battery_val < BATTERY_LOW ) { + digitalWrite(13, 1); // Simulate alarm :P + displaystate = BATTERY; + } + + if ( disp ) + { + ui_handler(); + } + if ( displaystate != MENU ) + { + // Debugging: how long does the main loop take on avg, + // when not handling the UI... + t = micros(); + avg_loop_time = ( t - prev_loop_time + avg_loop_time ) / 2; + prev_loop_time = t; + } + + // Whoa! Slow down partner! Let everything settle down before proceeding. + delay(5); +} + +// ----- Simple support functions used by more complex functions ---- + +void set_ppm_output( bool state ) +{ + digitalWrite(A5, state); // Hard coded PPM output +} + +void set_timer(long time) +{ + Timer1.detachInterrupt(); + Timer1.attachInterrupt(ISR_timer, time); +} + +boolean check_key( int key) +{ + return ( keys[key] && !prev_keys[key] ); +} + +void mplx_select(int pin) +{ + digitalWrite(5, 1); + delayMicroseconds(24); + + digitalWrite(2, bitRead(pin,0)); // Arduino alias for non-modifying bitshift operation + digitalWrite(3, bitRead(pin,1)); // us used to extract individual bits from the int (0..7) + digitalWrite(4, bitRead(pin,2)); // Select the appropriate input by setting s1,s2,s3 and e + digitalWrite(5, 0); // on the 4051 multiplexer. + + // May need to slow the following read down to be able to + // get fully reliable values from the 4051 multiplex. + delayMicroseconds(24); + +} + +// ----- "Complex" functions follow --------------------------------- + +void calibrate() +{ + int i, r0, r1, r2, adc_in; + int calcount = 0; + int num_calibrations = 200; + + lcd.clear(); + lcd.print("Move controls to"); + lcd.setCursor(0,1); + lcd.print("their extremes.."); + Serial.print("Calibration. Move all controls to their extremes."); + + for (i=0; i<=7; i++) { + minval[i] = 1024; + maxval[i] = 0; + } + while ( calcount <= num_calibrations ) + { + for (i=0; i<=7; i++) { + mplx_select(i); + adc_in = analogRead(0); + + // Naive min/max calibration + if ( adc_in < minval[i] ) { + minval[i] = adc_in; + } + if ( adc_in > maxval[i] ) { + maxval[i] = adc_in; + } + delay(10); + } + + calcount++; + } + + // TODO: WILL need to do center-point calibration after min-max... + + lcd.clear(); + lcd.print("Done calibrating"); + + Serial.print("Done calibrating"); + delay(2000); +} + +void read_settings(void) +{ + // Dummy. Will be modified to read model settings from EEPROM + for (int i=0; i<=7; i++) { + minval[i] = 0; + maxval[i] = 1024; + } +} + +void write_settings(void) +{ + // Dummy. Not used anywhere. Will be fleshed out to save settings to EEPROM. +} + +void scan_keys ( void ) +{ + int i, r0, r1, r2; + boolean key_in; + + // To get more inputs, another 4051 analog multiplexer is used, + // but this time it is used for digital inputs. 8 digital inputs + // on one input line, as long as proper debouncing and filtering + // is done in hardware :P + for (i=0; i<=7; i++) { + // To be able to detect that a key has changed state, preserve the previous.. + prev_keys[i] = keys[i]; + + // Select and read input. + mplx_select(i); + keys[i] = digitalRead(A2); + delay(2); + } +} + + +void process_inputs(void ) +{ + int current_input, r0, r1, r2, adc_in; + for (current_input=0; current_input<=7; current_input++) { + + mplx_select(current_input); + adc_in = analogRead(0); + + channel[current_input] = ((float)adc_in - (float)minval[current_input]) / (float)(maxval[current_input]-minval[current_input]); + if ( rev[current_input] ) channel[current_input] = 1.0f - channel[current_input]; + } +} + + +void ISR_timer(void) +{ + Timer1.stop(); // Make sure we do not run twice while working :P + + if ( !do_channel ) + { + set_ppm_output( LOW ); + sum += seplength; + do_channel = true; + set_timer(seplength); + return; + } + + if ( cchannel >= max_channels ) + { + set_ppm_output( HIGH ); + long framesep = framelength - sum; + + sum = 0; + do_channel = false; + cchannel = 0; + set_timer ( framesep ); + return; + } + + if ( do_channel ) + { + set_ppm_output( HIGH ); + long next_timer = (( chwidht * channel[cchannel] ) + chmin); + // Do sanity-check of next_timer compared to chmax ... + while ( chmax < next_timer ) next_timer--; + sum += next_timer; + + // Done with channel separator and value, + // prepare for next channel... + cchannel++; + do_channel = false; + set_timer ( next_timer ); + return; + } +} + +void serial_debug() +{ + int current_input; + for (current_input=0; current_input<=7; current_input++) { + int v = (int)(channel[current_input] * 100); + + Serial.print("Input #"); + Serial.print(current_input); + Serial.print(" value: "); + Serial.print(channel[current_input]); + Serial.print(" pct: "); + Serial.print(v); + Serial.print(" min: "); + Serial.print(minval[current_input]); + Serial.print(" max: "); + Serial.print(maxval[current_input]); + Serial.println(); + } + Serial.print("Battery level is: "); + Serial.println(battery_val); + + Serial.print("Average loop time:"); + Serial.println(avg_loop_time); + + Serial.println(); +} +void dr_inputselect( int no, int in ) +{ + if ( dr[menu_substate] < 0 ) dr[menu_substate] = 4; + if ( dr[menu_substate] > 4 ) dr[menu_substate] = 0; + + lcd.setCursor(0 , 0); + lcd.print("D/R switch "); + lcd.print( no + 1 ); + lcd.print(" "); + lcd.setCursor(0 , 1); + lcd.print("Input "); + lcd.print(in+1); + + lcd.print(": "); + if ( ! dr[menu_substate] ) lcd.print("Off"); + else lcd.print(dr[menu_substate]); + + if ( check_key(KEY_INC) ) { + dr[menu_substate]++; + return; + } + else if ( check_key(KEY_DEC) ) { + dr[menu_substate]--; + return; + } + // Wrap around. + return; + +} + +void dr_value() +{ + int pos; + int state; + + if ( menu_substate == 4) state = keys[KEY_DR1]; + else state = keys[KEY_DR2]; + + pos = 4 + (menu_substate - 4) * 2; + if (state) pos++; + + lcd.setCursor(0 , 0); + lcd.print("D/R switch "); + lcd.print( menu_substate - 3 ); + lcd.print(" "); + lcd.setCursor(0 , 1); + lcd.print( state ? "HI" : "LO" ); + lcd.print(" Value :"); + + lcd.print( dr[pos] ); + + if ( keys[KEY_INC] ) { + if ( dr[pos] < 100) dr[pos] += 5; + return; + } + else if ( keys[KEY_DEC] ) { + if ( dr[pos] > -100) dr[pos] -= 5; + return; + } + + return; +} +void ui_handler() +{ + int row; + int col; + scan_keys(); + + if ( displaystate != MENU ) + { + menu_substate = 0; + if ( check_key(KEY_UP) && displaystate == VALUES ) { + displaystate = BATTERY; + return; + } + else if ( check_key(KEY_UP) && displaystate == BATTERY ) { + displaystate = TIMER; + return; + } + else if ( check_key(KEY_UP) && displaystate == TIMER ) { + displaystate = VALUES; + return; + } + + else if ( check_key(KEY_DOWN) ) { + displaystate = MENU; + return; + } + } + + digitalWrite(13, digitalRead(13) ^ 1 ); + + switch ( displaystate ) + { + case VALUES: + int current_input; + for (current_input=0; current_input<=7; current_input++) { + // In channel value display, do a simple calc + // of the LCD row & column location. With 8 channels + // we can fit eight channels as percentage values on + // a simple 16x2 display... + if ( current_input < 4 ) + { + col = current_input * 4; + row = 0; + } + else + { + col = (current_input-4) * 4; + row = 1; + } + // Overwriting the needed positions with + // blanks cause less display-flicker than + // actually clearing the display... + lcd.setCursor(col, row); + lcd.print(" "); + lcd.setCursor(col, row); + // Display uses percents, while PPM uses ratio.... + int v = (int)(channel[current_input] * 100); + lcd.print(v); + } + break; + + + case BATTERY: + lcd.clear(); + lcd.print("Battery level: "); + lcd.setCursor(0 , 1); + lcd.print( (float)battery_val/10); + lcd.print("V"); + if ( battery_val < BATTERY_LOW ) lcd.print(" - WARNING"); + else lcd.print(" - OK"); + break; + + + + case TIMER: + unsigned long delta; + int hours; + int minutes; + int seconds; + + lcd.clear(); + lcd.print("Timer: "); + lcd.print( timer_running ? "Running" : "Stopped" ); + lcd.setCursor(5 , 1); + if ( timer_running ) + { + timer_value = millis() - (timer_start + timer_init); + } + hours = ( timer_value / 1000 ) / 3600; + timer_value = timer_value % 3600000; + minutes = ( timer_value / 1000 ) / 60; + seconds = ( timer_value / 1000 ) % 60; + if ( hours ) { + lcd.print(hours); + lcd.print(":"); + } + if ( minutes < 10 ) lcd.print("0"); + lcd.print( minutes ); + lcd.print(":"); + if ( seconds < 10 ) lcd.print("0"); + lcd.print( seconds ); + + if ( check_key(KEY_INC) ) { + if ( !timer_running && !timer_start ) + { + timer_start = millis(); + timer_value = 0; + timer_running = true; + } else if ( !timer_running && timer_start ) { + timer_start = millis() - timer_value; + timer_running = true; + } else if ( timer_running ) { + timer_running = false; + } + return; + } else if ( check_key(KEY_DEC) ) { + if ( !timer_running && timer_start ) { + timer_value = 0; + timer_start = 0; + timer_init = 0; + } + return; + } + break; + + case MENU: + lcd.clear(); + switch ( menu_mainstate ) + { + case TOP: + lcd.print("In MENU mode!"); + lcd.setCursor(0 , 1); + lcd.print("Esc UP. Scrl DN."); + menu_substate = 0; + if ( check_key(KEY_UP) ) { + displaystate = VALUES; + return; + } + else if ( check_key(KEY_DOWN) ) { + menu_mainstate = INVERTS; + return; + } + break; + + + case INVERTS: + if ( menu_substate >= max_channels ) menu_substate = 0; + if ( menu_substate < 0) menu_substate = (max_channels - 1); + lcd.print("Channel invert"); + lcd.setCursor(0 , 1); + lcd.print("Ch "); + lcd.print(menu_substate+1); + lcd.print( (rev[menu_substate] ? ": Invert" : ": Normal")); + + if ( check_key(KEY_UP) ) { + menu_mainstate = TOP; + return; + } + else if ( check_key(KEY_DOWN) ) { + menu_mainstate = DUALRATES; + return; + } + + if ( check_key(KEY_RIGHT) ) { + menu_substate++; + return; + } + else if ( check_key(KEY_LEFT) ) { + menu_substate--; + return; + } + else if ( check_key(KEY_INC) || check_key(KEY_DEC) ) { + rev[menu_substate] ^= 1; + return; + } + break; + + case DUALRATES: + if ( menu_substate > 5 ) menu_substate = 0; + if ( menu_substate < 0) menu_substate = 5; + + if ( check_key(KEY_UP) ) { + menu_mainstate = INVERTS; + return; + } + if ( check_key(KEY_DOWN) ) { + menu_mainstate = EXPOS; + return; + } + if ( check_key(KEY_RIGHT) ) { + menu_substate++; + return; + } + else if ( check_key(KEY_LEFT) ) { + menu_substate--; + return; + } + switch (menu_substate) + { + case 0: + dr_inputselect(0, 0); + return; + case 1: + dr_inputselect(0, 1); + return; + case 2: + dr_inputselect(1, 0); + return; + case 3: + dr_inputselect(1, 1); + return; + case 4: + case 5: + dr_value(); + return; + default: + menu_substate = 0; + break; + } + break; + + case EXPOS: + //________________ + lcd.print("Input expo curve"); + lcd.setCursor(0 , 1); + lcd.print("Not implemented"); + // Possible, if input values are mapped to +/- 100 rather than 0..1 .. + // plot ( x*(1 - 1.0*cos (x/(20*PI)) )) 0 to 100 + // Run in wolfram to see result, adjust the 1.0 factor to inc/red effect. + // Problem: -100 to 100 is terribly bad presicion, esp. considering that + // the values started as 0...1024, and we have 1000usec to "spend" on channels. + if ( check_key(KEY_UP ) ) { + menu_mainstate = DUALRATES; + return; + } + if ( check_key(KEY_DOWN ) ) { + menu_mainstate = DEBUG; + return; + } + break; + + case DEBUG: + lcd.setCursor(0 , 0); + lcd.print("Dumping debug to"); + lcd.setCursor(0 , 1); + lcd.print("serial port 0"); + serial_debug(); + if ( check_key(KEY_UP ) ) { + // FIXME: Remember to update the "Scroll up" state! + menu_mainstate = EXPOS; + return; + } else if ( check_key(KEY_DOWN ) ) { + menu_mainstate = SAVE; + return; + } + break; + + default: + lcd.print("Not implemented"); + lcd.setCursor(0 , 1); + lcd.print("Press DOWN..."); + if ( check_key(KEY_DOWN ) ) menu_mainstate = TOP; + } + break; + + + default: + // Invalid + return; + } + + return; +} + + + + + diff --git a/source/README b/source/README new file mode 100644 index 0000000..f2fa38d --- /dev/null +++ b/source/README @@ -0,0 +1,3 @@ +The reason for the folder-in-a-folder here, is to keep things +fairly clean, while at the same time satisfy the Arduino requirement +that the PDE file must live in a folder of the same name. diff --git a/tools/README b/tools/README new file mode 100644 index 0000000..b1daebb --- /dev/null +++ b/tools/README @@ -0,0 +1,6 @@ +Yeah. Tools. Must have tools. +Possible tool examples: + * scripts that generate stuff. + * scripts that verify stuff. + * other stuff. + -- 2.39.2