// include library code here #include #include #include // declare routines here void transmitsymbol(void); void dds(unsigned long freq); void start_message(void); void menu(void); void fixed(void); void sweep(void); void vfo(void); void calibrate(void); int read_encoder(void); unsigned long get_frequency(char message[]); // variables and constants here unsigned long TXfreq = 10140060; unsigned long TenMHz = 10000000; #define ENC_PORT PINC byte DATA = 42; // DDS DATA byte CLOCK = 40; // DDS CLOCK byte LOAD = 38; // DDS LOAD byte ENC_A = 36; // Encoder A This is bit 0 of PORT C byte ENC_B = 37; // Encoder B This is bit 1 of PORT C byte ENC_SW = 48; // Encoder Switch byte ledpin = 13; // on board LED (watchdog) byte calset = 41; // Calibrate set - tie low to call calibration byte calup = 43; // increment calibration factor byte caldown = 45; // decrement calibration factor // my EEPROM 4 word data structure here struct CalFact { union { long value; struct { unsigned char b1; unsigned char b2; unsigned char b3; unsigned char b4; }__attribute__((packed)); }__attribute__((packed)); }__attribute__((packed)); struct CalFact CalFactor; // declare LCD as listed pins below LiquidCrystal lcd(32, 30, 28, 26, 24, 22); // declare the keypad structure const byte ROWS = 4; // Four rows const byte COLS = 3; // Three columns // Define the Keymap char keys[ROWS][COLS] = { {'1','2','3'}, {'4','5','6'}, {'7','8','9'}, {'#','0','*'} }; // Connect keypad ROW0, ROW1, ROW2 and ROW3 to these Arduino pins. byte rowPins[ROWS] = { 9, 8, 7, 6 }; // Connect keypad COL0, COL1 and COL2 to these Arduino pins. byte colPins[COLS] = { 12, 11, 10 }; // Create the Keypad Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); // initiatisation routine void setup() { // LCD lcd.begin(20,4); // Encoder Pins pinMode(ENC_A, INPUT); digitalWrite(ENC_A, HIGH); pinMode(ENC_B, INPUT); digitalWrite(ENC_B, HIGH); pinMode(ENC_SW, INPUT); digitalWrite(ENC_SW, HIGH); // DDS pins for data, clock and load pinMode (DATA, OUTPUT); // DDS pins as output pinMode (CLOCK, OUTPUT); pinMode (LOAD, OUTPUT); digitalWrite(DATA, LOW); // internal pull-down digitalWrite(CLOCK, LOW); digitalWrite(LOAD, LOW); // Watchdog LED pin pinMode (ledpin, OUTPUT); // needs to be used as a watchdog // Calibration pins pinMode (calset, INPUT); // calibration related pins are inputs pinMode (calup, INPUT); pinMode (caldown, INPUT); digitalWrite(calset, HIGH); // internal pull-up enabled digitalWrite(calup, HIGH); digitalWrite(caldown, HIGH); // switch on Serial Port for debug back to PC Serial.begin(9600); // connect to the serial port // initialise CalFactor.value from EEPROM CalFactor.b1 = EEPROM.read(50); CalFactor.b2 = EEPROM.read(51); CalFactor.b3 = EEPROM.read(52); CalFactor.b4 = EEPROM.read(53); dds(0); dds(TenMHz); } // main loop void loop() { // Calibration process follows: if(digitalRead(calset) == LOW) { calibrate(); } // display some Bad Mogic start_message(); // now loop forever calling the menu while (1) { menu(); } } // dds instruction write - takes unsigned long frequency in Hz void dds(unsigned long freq) { int last8; unsigned long DDSLong; unsigned long Bitmask32 = 1; byte Bitmask8 = 1; byte FirstBit = 1; float clock_frequency = 180000000; float twoE32 = pow (2,32); DDSLong = ((twoE32 * (freq+CalFactor.value))/ clock_frequency); for (Bitmask32 = 1; Bitmask32 > 0; Bitmask32 <<= 1) { // iterate through 32 bits of DDSLong if (DDSLong & Bitmask32) // if bitwise AND resolves to true digitalWrite(DATA,HIGH); else // if bitwise AND resolves to false digitalWrite(DATA,LOW); digitalWrite(CLOCK,HIGH); // Clock data in by setting clock pin high then low delayMicroseconds(1); digitalWrite(CLOCK,LOW); } for (Bitmask8 = 1; Bitmask8 > 0; Bitmask8 <<= 1) { // iterate through last 8 bits of 40 bit instruction to DDS if (Bitmask8 & FirstBit) // 1st bit of remaining 8 needs to be 1 to enable clock multiplier digitalWrite(DATA,HIGH); else digitalWrite(DATA,LOW); digitalWrite(CLOCK,HIGH); // Clock data in by setting clock pin high then low delayMicroseconds(1); digitalWrite(CLOCK,LOW); } digitalWrite (LOAD, HIGH); // Pulse DDS update delayMicroseconds(1); digitalWrite (LOAD, LOW); // to execute previous instruction set return; } void start_message(void) { lcd.clear(); delay(100); lcd.print(" G0MGX DDS Sig Gen"); lcd.setCursor(0,2); lcd.print(" Bad Magic ...."); delay(2000); lcd.clear(); return; } void menu(void) { char key; lcd.clear(); delay(100); lcd.print(" G0MGX DDS Sig Gen"); lcd.setCursor(0,1); lcd.print(" 1. Fixed 2. Sweep"); lcd.setCursor(0,2); lcd.print(" 3. VFO"); lcd.setCursor(0,3); lcd.print("> "); key = keypad.waitForKey(); lcd.setCursor(2,3); lcd.print(key); if(key) // Check for a valid key. { switch (key) { case '1': fixed(); break; case '2': sweep(); break; case '3': vfo(); break; default: break; } } return; } void fixed(void) { dds(get_frequency("Frequency",10000000)); } void sweep(void) { unsigned long start_frequency; unsigned long end_frequency; unsigned long increments; unsigned long sweep_frequency; unsigned long display_frequency; start_frequency = get_frequency("Low",10000000); end_frequency = get_frequency("High",10000000); increments = get_frequency("Step",1000); lcd.clear(); lcd.print(" G0MGX DDS Sig Gen"); lcd.setCursor(0,1); lcd.print("Sweeping..."); while (1) { lcd.setCursor(0,3); lcd.print("Step : "); lcd.print(increments); for (sweep_frequency = start_frequency; sweep_frequency <= end_frequency; sweep_frequency = sweep_frequency + increments) { lcd.setCursor(0,2); lcd.print("Frequency : "); lcd.setCursor(12,2); display_frequency = sweep_frequency - (sweep_frequency % 1000); lcd.print(display_frequency); dds(sweep_frequency); } } } void vfo(void) { int vfo_increment = 1000; int step_count = 1; unsigned long frequency = get_frequency("Start ", 10000000); static uint8_t counter = 1; int8_t tmpdata; // start the DDS with the users frequency dds(frequency); // set ut the LCD display lcd.clear(); lcd.print(" G0MGX DDS Sig Gen"); lcd.setCursor(0,1); lcd.print("VFO"); lcd.setCursor(0,2); lcd.print("Frequency : "); lcd.print(frequency); lcd.setCursor(0,3); lcd.print("Step : "); lcd.print(vfo_increment); while (1) { // Read the encoder state tmpdata = read_encoder(); // in this crazyness here I need to find a way to somehow // only use one in four of the reads from the encoder // so I am relying on counter/4 returning 0 unless // counter itself is also 4 if (tmpdata) counter ++; // increment or decrement if appropriate if (tmpdata > 0) frequency = frequency + ((counter / 4) * vfo_increment); if (tmpdata < 0) frequency = frequency - ((counter / 4) * vfo_increment); // if it's changed send the new frequency to the dds if ((tmpdata > 0 || tmpdata < 0) && (counter / 4) == 1) dds(frequency); if (counter == 4) counter = 1; // update display lcd.setCursor(12,2); lcd.print(frequency); // now check for the step change switch on the encoder if (digitalRead(ENC_SW) == LOW) { delay (100); // pathetic debounce step_count++; step_count = step_count & 0x03; switch (step_count) { case 0: vfo_increment = 10; break; case 1: vfo_increment = 100; break; case 2: vfo_increment = 1000; break; case 3: vfo_increment = 1; break; } if (digitalRead(ENC_SW==LOW)) { delay (500); // delay for 1/2 second but after that assume we are changing the increment again } // update displayed vfo increment setting lcd.setCursor(7,3); lcd.print(vfo_increment); lcd.print(" "); } } } void calibrate(void) { unsigned long FreqLong; unsigned long TempWord; // no need to output 10MHz calibration signal on DDS // as we have just run setup() which does this already // display calibration text lcd.clear(); lcd.setCursor(0,0); lcd.print("Adjust to 10MHz"); lcd.setCursor(0,1); lcd.print("Cal Factor= "); lcd.setCursor(12,1); lcd.print(CalFactor.value); // remain in the loop while the calset is low while(digitalRead(calset) == LOW) { if (digitalRead(calup) == LOW) { delay(250); //crude debounce delay CalFactor.value++; dds(TenMHz); } if (digitalRead(caldown) == LOW) { delay(250); //crude debounce delay CalFactor.value--; dds(TenMHz); } lcd.setCursor(12,1); lcd.print(CalFactor.value); lcd.print(" "); } // Now write the Calfactor value back to EEPROM EEPROM.write(50,CalFactor.b1); EEPROM.write(51,CalFactor.b2); EEPROM.write(52,CalFactor.b3); EEPROM.write(53,CalFactor.b4); } unsigned long get_frequency(char message[], int long multiplier) { unsigned long ret_frequency = 0; char key; int user_key; lcd.clear(); lcd.print("Enter "); lcd.print(message); lcd.print(":"); lcd.setCursor (0,2); lcd.print("> "); while (multiplier > 0) { // Get keypress key = keypad.waitForKey(); // convert from char to integer user_key = key-48ul; // if the char entered is a * or # force bail out if (key == '*' || key == '#') multiplier = 0; // So we aren't about to bail out if this is true if (multiplier != 0) { // if we dont have a zero and the ret_frequency is no longer 0 it can't be a leading zero if (user_key == 0 && ret_frequency == 0 ){} else // dont print leading 0s lcd.print(user_key); } ret_frequency = ret_frequency + (user_key * multiplier); multiplier = multiplier / 10; } delay(200); if (ret_frequency == 0) ret_frequency = TenMHz; return ret_frequency; } int read_encoder() { static int enc_states[] = {0, -1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0}; static int old_AB = 0; old_AB <<= 2; old_AB |= (ENC_PORT & 0x03); return (enc_states[(old_AB & 0x0f)]); }