Large program management-stitching together functional code blocks?

SO, now that I have successfully gotten my homebrew ATMega2561 arduino-compatible to talk to the IDE, accept a program via the USB port, and generally not cause me headaches, it's time to coax it into actually doing useful things.

This is a big project for me-there is a LOT going on that the processor needs to handle. It's a multi-band, dual-modulation, digitally tuned, radio transmitter/receiver. Currently, 3 or 4 bands and three modulation modes are "within reach" hardware-wise. I don't think I would need to expand this software past 4 bands, and maybe adding digital modulation modes later on or in a different project.

I have to do the following:

  • Display frequency, band, modulation, and power on the 2.8" LCD display.
  • Input from four pushbuttons
  • input from transmit key
  • Input from rotary encoder
  • analog input for RF power output
  • analog input for RSSI
  • control three banks of relays for bandswitching
  • control transmit/receive switching
  • control modulation mode select relays
  • TWI-bus controlled SI5351 local oscillator
  • Selectable power output (analog? digital? I2C softpot?)

So far, I've accomplished the following on an Arduino Uno, one at a time:

  • Setup the 2.8" TFT display and print static data to learn how to print to the display
  • read an analog sensor and run the input through a simple equation
  • toggle a digital output
  • read a rotary encoder (digital input, it works, but it's terrible
  • read and debounce a pushbutton(digital input)

Clearly, I have some work to do. Also, I need to get all these things to happen at once, instead of a single sketch at a time. I am a hardware guy-my software skills are akin to the contents of Jeremy Clarkson's toolbox, but given enough time I can get it to work. I DO have extensive libraries and code examples to work with-but a LOT of them are targeted at different ATmega platforms, and a lot of them are just standalone examples on how to use a product/system/part.

Now, it's clear that this is a big job-I have plenty of room (I hope) to get it done, but I have no idea of the architecture of a program this large. How would you lay out this program, and why do it that way? Is there a "normal" way of doing this or is it just a "slap it together, if it works it's not shit!" situation?

generally, you create a big loop (ok it's already present@arduino sketches). Inside the big loop you do this

  1. read all the inputs lets say to variables, and then calculate what you are going to do / to change at the outputs and what to display
  2. write the display
  3. set the outputs

(then the loop starts again)

That's it already. If some output or display are not time critical, you can run counters and update them only every n loops.

Have a look at Planning and Implementing a Program

...R

Working on this more tonight, this is my original TFT-LCD code that I plan to build from...next up is button pushes, for controlling band select, modulation select, and to store and recall memory frequencies. After that, the Rotary.h library for the rotary encoder, plus the pushbutton in the encoder to allow setting frequency.

The below code compiles and runs on the Uno, but I'll need to change the pin assignments to get it to run on my custom board. Haven't made that change yet. Considering writing a my-pin-assignment library to avoid having to change a lot, plan is to get all this hardware working, then PCB revision 2 will be made and things'll get prettied up.

#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_TFTLCD.h> // Hardware-specific library


//Define the LCD control lines
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0

#define LCD_RESET A4 // Can alternately just connect to Arduino's reset pin

//Define some colors:
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

//configuring the data lines for tft library
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

void setup(void) {
  // setting up the serial console monitor
  Serial.begin(9600);
  Serial.println("serial console works"); 

  tft.reset(); //reset the display
  tft.begin(0x9341); //start up the display
  Serial.println("started the display, boss");
}
void loop(void) { 
  
 
  tft.setRotation(3); //landscape mode with data pins on the top and address lines on the bottom
  tft.fillScreen(BLACK); //this cleared the screen, but it did it every loop through-so display flickered for redraw

  //Filter Indicator
  tft.setCursor(6,6);
  tft.setTextColor(CYAN, BLACK);
  tft.setTextSize(2);
  tft.println("6Khz Filter");
  //tft.println("3Khz Filter");

  //Band Indicator, display indicated band
  tft.setCursor(6,25);
  tft.setTextColor(CYAN, BLACK);
  tft.setTextSize(2);
  tft.println("40M Band");
  //tft.println("20M band");
  //tft.println("10M Band");
  //tft.println("6M Band");

  //Memory Indicator
  tft.setCursor(220,6);
  tft.setTextColor(CYAN, BLACK);
  tft.setTextSize(2);
  tft.println("Memory A"); //replace A with A/B/C for whichever stored frequency is in position A/B/C

  //Setup Main TX Tuning Display
  tft.setCursor(6, 80); //Don't get closer than "6" from the edge, it's too close.
  tft.setTextColor(RED, BLACK);
  tft.setTextSize(2); //text size 2 is about 3/16" tall
  tft.println("TX");
  tft.setCursor(60, 80);
  tft.setTextColor(GREEN, BLACK);
  tft.setTextSize(3); //text size 4 is about 1/4" tall
  tft.println("Mhz"); //Make the "123" the Transmit Mhz tuning, "456" the Transmit khz tuning, and "789" the Transmit hz tuning later
  tft.setCursor(110, 80);
  tft.println("."); //seperator
  tft.setCursor(128, 80);
  tft.println("Khz"); //Khz tuning
  tft.setCursor(180, 80);
  tft.println("."); //seperator
  tft.setCursor(198, 80);
  tft.println("hz_"); //hz tuning
  tft.setCursor(280, 80);
  tft.setTextColor(YELLOW, BLACK);
  tft.setTextSize(2);
  tft.println("MHz");
  
   //Setup Main RX Tuning Display
  tft.setCursor(6, 136); //Don't get closer than "6" from the edge, it's too close.
  tft.setTextColor(RED, BLACK);
  tft.setTextSize(2); //text size 2 is about 3/16" tall
  tft.println("RX");
  tft.setCursor(60, 130);
  tft.setTextColor(GREEN, BLACK);
  tft.setTextSize(3); //text size 4 is about 1/4" tall
  tft.println("123"); //Make the "123" the Recive Mhz tuning, "456" the Recieve khz tuning, and "789" the Recieve hz tuning later
  tft.setCursor(110, 130);
  tft.println("."); //seperator
  tft.setCursor(128, 130);
  tft.println("456"); //Khz tuning
  tft.setCursor(180, 130);
  tft.println("."); //seperator
  tft.setCursor(198, 130);
  tft.println("789"); //hz tuning
  tft.setCursor(280, 136);
  tft.setTextColor(YELLOW, BLACK);
  tft.setTextSize(2);
  tft.println("MHz");
  

  //Setup to display Mode Indication, select only one at a time
  tft.setCursor(40, 180);
  tft.setTextColor(CYAN,BLACK);
  tft.setTextSize(3);
  tft.println("LSB");

  //tft.setCursor(40, 180);
  //tft.setTextColor(CYAN,BLACK);
  //tft.setTextSize(3);
  //tft.println("AM");

  //tft.setCursor(40, 180);
  //tft.setTextColor(CYAN,BLACK);
  //tft.setTextSize(3);
  //tft.println("USB");

  delay(5000); //slow the redraw flicker down for testing
}

Personally, I like classes. See the link in my sig for a bit of a walk-through on how I use classes to build something complex.,