Components and supplies
Rotary Encoder Module
Display SH1106 I2C Oled 128x64 pixel (4 pin)
5V Relay Module (optional)
Relay Reed 5V 500 Ohm
Rotary Encoder with Push-Button
AC-DC 100-220V to 5V Step-Down Power Supply module
AD9833 DDS Module
Capacitor 10 µF
Arduino Nano R3
Capacitor 10 nF
Tools and machines
Soldering iron (generic)
Apps and platforms
image2cpp
Project description
Code
JXWG_Graphics.h
c_cpp
Icon resource data file
1 2// This file is an integral part of the JX_WaveGenerator.ino and must be 3// distributed together with the main file to allow it to function correctly. 4// The same license of the main file applies to this file. 5// Janux 01/04/2021 on Turin, Italy. 6 7#ifndef JXWG_Graphics 8#define JXWG_Graphics 9 10//---------------------------------------------------------------------------------------------- 11// Plain b&w bitmaps PROGMEM icons data 12//---------------------------------------------------------------------------------------------- 13 14const byte imgLog[] PROGMEM = { 15 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x88, 0x00, 0x40, 0x80, 0x9c, 0x00, 0x40, 0x80, 16 0x88, 0x00, 0x80, 0x80, 0x88, 0x00, 0x80, 0x80, 0x88, 0x01, 0x00, 0x80, 0x88, 0x02, 0x00, 0x80, 17 0x88, 0x0c, 0x00, 0x80, 0x88, 0x30, 0x00, 0x80, 0x89, 0xc0, 0x00, 0x80, 0x8e, 0x00, 0x10, 0x80, 18 0x9f, 0xff, 0xf8, 0x80, 0x88, 0x00, 0x10, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 19}; 20 21const byte imgDigit[] PROGMEM = { 22 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 23 0x9c, 0x47, 0x3e, 0x80, 0xa2, 0xc8, 0x82, 0x80, 0xa6, 0x40, 0x84, 0x80, 0xaa, 0x47, 0x0c, 0x80, 24 0xb2, 0x48, 0x02, 0x80, 0xa2, 0x48, 0x22, 0x80, 0x9c, 0xef, 0x9c, 0x80, 0x80, 0x00, 0x00, 0x80, 25 0x80, 0x00, 0x3e, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 26}; 27 28const byte imgSweep[] PROGMEM = { 29 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x8f, 0xcf, 0x38, 0x80, 30 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 31 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 32 0x88, 0x49, 0x28, 0x80, 0xb8, 0x79, 0xee, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 33}; 34 35const byte imgSqr[] PROGMEM = { 36 0xff, 0xff, 0xff, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0xff, 0x80, 0x80, 0x82, 0x88, 0xa0, 0x80, 37 0x80, 0x80, 0x80, 0x80, 0x82, 0x88, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0xaa, 0xaa, 0xaa, 0x80, 38 0x80, 0x80, 0x80, 0x80, 0x82, 0x88, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x82, 0x88, 0xa0, 0x80, 39 0xff, 0x80, 0xff, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 40}; 41 42const byte imgSin[] PROGMEM = { 43 0xff, 0xff, 0xff, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0x1c, 0x00, 0x80, 0x82, 0x2a, 0x20, 0x80, 44 0x80, 0x41, 0x00, 0x80, 0x82, 0x49, 0x20, 0x80, 0x80, 0x80, 0x80, 0x80, 0xaa, 0xaa, 0xaa, 0x80, 45 0x80, 0x80, 0x80, 0x80, 0xc3, 0x08, 0x61, 0x80, 0xc1, 0x00, 0x41, 0x80, 0xa2, 0x08, 0x22, 0x80, 46 0x9c, 0x00, 0x1c, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 47}; 48 49const byte imgTri[] PROGMEM = { 50 0xff, 0xff, 0xff, 0x80, 0x82, 0x08, 0x20, 0x80, 0x82, 0x00, 0x20, 0x80, 0x87, 0x08, 0x70, 0x80, 51 0x85, 0x00, 0x50, 0x80, 0x8a, 0x88, 0xa8, 0x80, 0x88, 0x80, 0x88, 0x80, 0xba, 0xeb, 0xae, 0x80, 52 0x90, 0x41, 0x04, 0x80, 0xa2, 0x2a, 0x22, 0x80, 0xa0, 0x22, 0x02, 0x80, 0xc2, 0x1c, 0x21, 0x80, 53 0xc0, 0x14, 0x01, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 54}; 55 56const byte imgCoAc[] PROGMEM = { 57 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 58 0x9c, 0x70, 0x00, 0x80, 0xa2, 0x88, 0x00, 0x80, 0xa2, 0x80, 0xc0, 0x80, 0xa2, 0x81, 0x24, 0x80, 59 0xbe, 0x81, 0x24, 0x80, 0xa2, 0x88, 0x18, 0x80, 0xa2, 0x70, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 60 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 61}; 62 63const byte imgCoDc[] PROGMEM = { 64 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 65 0xbc, 0x70, 0x00, 0x80, 0xa2, 0x88, 0x00, 0x80, 0xa2, 0x81, 0x54, 0x80, 0xa2, 0x80, 0x00, 0x80, 66 0xa2, 0x81, 0xfc, 0x80, 0xa2, 0x88, 0x00, 0x80, 0xbc, 0x70, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 67 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 68}; 69 70const byte imgCoOff[] PROGMEM = { 71 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 72 0x9c, 0xf7, 0x80, 0x80, 0xa2, 0x84, 0x22, 0x80, 0xa2, 0x84, 0x14, 0x80, 0xa2, 0xe7, 0x08, 0x80, 73 0xa2, 0x84, 0x14, 0x80, 0xa2, 0x84, 0x22, 0x80, 0x9c, 0x84, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 74 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 75}; 76 77const byte imgSwMax[] PROGMEM = { 78 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 79 0x81, 0x00, 0x00, 0x80, 0x82, 0x00, 0x00, 0x80, 0x87, 0x01, 0x00, 0x80, 0x82, 0x03, 0x80, 0x80, 80 0x82, 0x07, 0xc0, 0x80, 0x82, 0x0f, 0xe0, 0x80, 0x82, 0x1f, 0xf0, 0x80, 0x80, 0x00, 0x00, 0x80, 81 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 82}; 83 84const byte imgSwMin[] PROGMEM = { 85 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 86 0x81, 0x00, 0x00, 0x80, 0x82, 0x00, 0x00, 0x80, 0x87, 0x1f, 0xf0, 0x80, 0x82, 0x0f, 0xe0, 0x80, 87 0x82, 0x07, 0xc0, 0x80, 0x82, 0x03, 0x80, 0x80, 0x82, 0x01, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 88 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 89}; 90 91const byte imgSwOpt[] PROGMEM = { 92 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 93 0x84, 0x08, 0x10, 0x80, 0x88, 0x1c, 0x38, 0x80, 0x9c, 0x3e, 0x10, 0x80, 0x88, 0x00, 0x00, 0x80, 94 0x88, 0x00, 0x00, 0x80, 0x88, 0x3e, 0x00, 0x80, 0x88, 0x1c, 0x38, 0x80, 0x88, 0x08, 0x00, 0x80, 95 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 96}; 97 98const byte imgSwStep[] PROGMEM = { 99 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 100 0x84, 0x08, 0x04, 0x80, 0x88, 0x0c, 0x08, 0x80, 0x9c, 0x7e, 0x1c, 0x80, 0x88, 0x7f, 0x08, 0x80, 101 0x88, 0x7e, 0x08, 0x80, 0x88, 0x0c, 0x08, 0x80, 0x88, 0x08, 0x08, 0x80, 0x80, 0x00, 0x00, 0x80, 102 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 103}; 104 105const byte imgSwStart[] PROGMEM = { 106 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x00, 0x80, 107 0x80, 0xf0, 0x00, 0x80, 0x80, 0xfc, 0x00, 0x80, 0x80, 0xff, 0x00, 0x80, 0x80, 0xff, 0xc0, 0x80, 108 0x80, 0xff, 0xc0, 0x80, 0x80, 0xff, 0x00, 0x80, 0x80, 0xfc, 0x00, 0x80, 0x80, 0xf0, 0x00, 0x80, 109 0x80, 0xc0, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 110}; 111 112const byte imgSwPause[] PROGMEM = { 113 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x81, 0xe3, 0xc0, 0x80, 114 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 115 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 116 0x81, 0xe3, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 117}; 118 119const byte imgTurn[] PROGMEM = { 120 0x0f, 0x80, 0x30, 0x60, 0x47, 0x10, 0x58, 0xd0, 0x90, 0x48, 0x80, 0xe8, 0x90, 0x48, 0xb8, 0x08, 121 0x90, 0x48, 0x58, 0xd0, 0x47, 0x10, 0x30, 0x60, 0x0f, 0x80 122}; 123 124const byte imgSwRun[] PROGMEM = { 125 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x9b, 0xa2, 0x22, 0x6b, 0xae, 0xec, 0x7b, 0xae, 0xec, 0x9a, 126 0xa6, 0x62, 0xea, 0xae, 0xee, 0x6a, 0xae, 0xee, 0x9c, 0x62, 0x2e, 0xff, 0xff, 0xfe, 0x00, 0x00, 127 0x00 128}; 129 130const byte imgSwPsd[] PROGMEM = { 131 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x1c, 0xdb, 0x30, 0x6b, 0x5a, 0xd6, 0x6b, 0x5a, 0xf6, 0x18, 132 0x5b, 0x32, 0x7b, 0x5b, 0xd6, 0x7b, 0x5a, 0xd6, 0x7b, 0x67, 0x30, 0xff, 0xff, 0xfe, 0x00, 0x00, 133 0x00 134}; 135 136//Small icons --------------------------------------------------------------------------------- 137const byte imgSqrSmall[] PROGMEM = { 138 0x00, 0x00, 0x3e, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0xe3, 0x80, 0x00, 0x00 139}; 140 141const byte imgSinSmall[] PROGMEM = { 142 0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x84, 0x80, 0x84, 0x80, 0x03, 0x00, 0x00, 0x00 143}; 144 145const byte imgTriSmall[] PROGMEM = { 146 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x88, 0x80, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 147}; 148 149const byte imgAcSmall[] PROGMEM = { 150 0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x84, 0x80, 0x84, 0x80, 0x03, 0x00, 0x00, 0x00 151}; 152 153const byte imgDcSmall[] PROGMEM = { 154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x80, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 155}; 156 157const byte imgOffSmall[] PROGMEM = { 158 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x14, 0x00, 0x08, 0x00, 0x14, 0x00, 0x22, 0x00, 0x00, 0x00 159}; 160 161//Total program memory space used by icons data: 1148 byte 162 163 164#endif 165
JXWG_Defs.h
c_cpp
Declarections section
1 2// This file is an integral part of the JX_WaveGenerator.ino and must 3 be 4// distributed together with the main file to allow it to function correctly. 5// 6 The same license of the main file applies to this file. 7// Janux 01/04/2021 on 8 Turin, Italy. 9 10#ifndef JXWG_Defs 11#define JXWG_Defs 12 13#include <Wire.h> 14#include 15 <EEPROM.h> 16 17//Encoder library, see https://www.arduino.cc/reference/en/libraries/simplerotary/ 18#include 19 <SimpleRotary.h> // 20 21//adaptation of the library for SSD1306 to the SH1106 22 display, see https://github.com/wonho-maker/Adafruit_SH1106 23#include <Adafruit_SH1106.h> 24 25#define 26 DEBUG 0 27#define OLED_RESET -1 28Adafruit_SH1106 display(OLED_RESET); 29 30#define 31 PinA 5 //Encoder pin A 32#define PinB 4 //Encoder pin B 33#define 34 PinS 3 //Encoder pin Switch 35SimpleRotary Encoder(PinA, PinB, PinS); 36 37//list 38 of loop mode 39#define LOGARITHMIC 0 //+workmode 40#define SINGLEDIGIT 1 //+workmode 41#define 42 SWEEP 2 //+workmode 43 44#define OPTIONS 3 //-submode of LOGARITHMIC 45 and SINGLEDIGIT 46#define OPTMODE 4 //-submode of OPTIONS 47#define OPTWAVE 48 5 //-submode of OPTIONS 49#define OPTCOUP 6 //-submode of OPTIONS 50#define 51 OPTSWEEP 7 //-submode of SWEEP 52#define SWEEPEDIT 8 //-submode of OPTSWEEP 53#define 54 DIGITCHANGE 9 //-submode of SINGLEDIGIT and SWEEPEDIT 55 56#define PinCoupling 57 7 //Coupling mode pin (relay pin) 58 59//constants 60#define XPOS 28 61#define 62 YPOS 21 63#define DELTAX 12 64#define DELTAY 4 65#define 66 SMALL 1 67#define BIG 2 68#define CW 1 69#define 70 CCW 2 71#define PUSH 1 72#define LONGPUSH 1 73 74//Num 75 Freq digit 76#define MAXDIGIT 6 77 78//Wave type 79#define SQUARE 0 80#define 81 SINE 1 82#define TRIANGLE 2 83 84//Coupling mode 85#define AC 86 0 87#define DC 1 88#define OFF 2 89 90//Sweep 91 status 92#define STILL 0 93#define BREAK 1 94#define PAUSE 2 95 96//Symbols 97 chars 98#define CURSOR 0x5F 99#define ARROW 0x10 100 101//AD9833 102 module Pin connection 103#define DDS_FSY 9 104#define DDS_CLK 10 105#define 106 DDS_DAT 11 107 108//AD9833 Wave Type const 109#define wSquare 0x28 110#define 111 wSine 0x00 112#define wTriangle 0x02 113 114//----------------------------------------------------------------------------- 115// 116 Variables declarections 117//----------------------------------------------------------------------------- 118 119//Strings 120 constants placed in flash memory save ram space 121const char str1[] PROGMEM = "JX 122 WAVE GENERATOR"; // 18 byte 123const char str2[] PROGMEM = "WELCOME"; // 124 8 byte 125const char str3[] PROGMEM = "Hz"; // 3 byte 126const 127 char str4[] PROGMEM = "ERROR!"; // 7 byte 128const char str5[] PROGMEM 129 = "RESET"; // 6 byte //42 byte total 130const char* const string_table[] 131 PROGMEM = {str1, str2, str3, str4, str5}; 132char buffer[18]; //local buffer for 133 string, make sure this is large enough for the largest string it must hold 134 135long 136 lFreq = 1000; //main frequency 137 variable 138long lLastFreq = 1000; //used 139 to save the current freq value in some situations 140long sweepUpPausedVal = 0; 141 //value of sweep when pused 142long sweepDnPausedVal 143 = 0; //value of sweep when pused 144long 145 lSweep[3] = {20000, 0, 100}; //Sweep Hz default 146 value MAX, MIN, STEP; 147byte sweepStatus = STILL; //current 148 status of the sweep process 149const byte Wave[] = {wSquare, wSine, wTriangle}; 150 //array for WaveType 151volatile boolean encoderPush = false; //var 152 used in the routine called by interrupt 153char Freq[MAXDIGIT + 1]; //array 154 for display frequency in 6 digit template "000000" 155byte mode = 0; //current 156 loop mode 157byte idx = 0; //pointer 158 to digit index (0 to 5) 159byte idy = 0; //same 160 of idx in submode 161long cTime = 1; //screensaver 162 counter 163 164//default startup preferences 165byte options[3] = {LOGARITHMIC, 166 SINE, DC}; //mode, wavetype, couplingmode 167 168//define 169 others macros 170#define _WorkMode options[0] 171#define _setWorkMode(x) 172 options[0]=x 173#define _WaveType options[1] 174#define _setWaveType(x) 175 options[1]=x 176#define _CouplingMode options[2] 177#define _setCouplingMode(x) 178 options[2]=x 179#define _reservedbyte 0xFF 180#define _SweepMax lSweep[0] 181#define 182 _SweepMin lSweep[1] 183#define _SweepStep lSweep[2] 184#define 185 _Sweep(x) lSweep[x] 186#define _setSweep(x,f) lSweep[x]=f 187#define 188 _setSweepMax(x) lSweep[0]=x 189#define _setSweepMin(x) lSweep[1]=x 190#define 191 _setSweepStep(x) lSweep[2]=x 192 193//define short functions macros 194#define 195 _clearIconsArea display.fillRect(XPOS - 11, YPOS + 18, 94, 24, BLACK) 196#define 197 _displayErrMsg displayText(XPOS + 2, YPOS, strFromFlash(3), WHITE, BLACK, BIG); 198 199//define 200 CONFIG consts & vars 201#define CONFIG_START 32 //EEPROM Memory start 202 location 203#define CONFIG_VERSION "JXWG1" //Config version ID 204 205//define 206 custom type struct 207typedef struct { 208 char version[6]; 209 byte workmode; 210 211 byte wavetype; 212 byte couplingmode; 213 byte reservedbyte; 214 long sweepmax; 215 216 long sweepmin; 217 long sweepstep; 218} config_type; 219 220//create 221 new struct and load it with default value 222config_type CONFIG = { 223 CONFIG_VERSION, 224 225 _WorkMode, 226 _WaveType, 227 _CouplingMode, 228 _reservedbyte, 229 _SweepMax, 230 231 _SweepMin, 232 _SweepStep, 233}; 234 235//define processor reset function 236void(*ATmegaReset)(void) 237 = 0; 238 239#endif 240
JX_Wave_Generator_8.7.7.ino
c_cpp
Version 8.7.7. Minor revision on 1/16/2021
1 2/* 3 Copyright (c) 2020 Janux 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 The above copyright notice and this permission notice shall be included in all 11 copies or substantial portions of the Software. 12 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 SOFTWARE. 19 20 The configuration saving-loading code is a development of an original idea of the article 21 "How to Load and Save Configurations on an Arduino" by Ragnar Ranyen Homb on the Norwegian Creation website. 22 23*/ 24 25#include "JXWG_Defs.h" 26#include "JXWG_Graphics.h" 27 28void setup() { 29 30 //if you are using a simple encoder and 3x10K pullup resistors, apply this settings below 31 pinMode(PinA, INPUT); 32 pinMode(PinB, INPUT); 33 pinMode(PinS, INPUT); 34 35 //if you are using a simple encoder whitout 3x10K resistors use next tree row 36 //pinMode(PinA, INPUT_PULLUP); 37 //pinMode(PinB, INPUT_PULLUP); 38 //pinMode(PinS, INPUT_PULLUP); 39 40 //MOST PCB WELDED ENCODERS ALREADY HAVE PULLUP RESISTORS ON PIN A AND B BUT NOT ON SWITCH PIN 41 //then use the settings below 42 //pinMode(PinA, INPUT); 43 //pinMode(PinB, INPUT); 44 //pinMode(PinS, INPUT_PULLUP); 45 46 digitalWrite(PinA, HIGH); 47 digitalWrite(PinB, HIGH); 48 digitalWrite(PinS, HIGH); 49 50 pinMode(PinCoupling, OUTPUT); //Coupling Mode 51 52 Encoder.setDebounceDelay(5); 53 54 display.begin(SH1106_SWITCHCAPVCC, 0x3C); //initialize with the I2C addr 0x3C (for the 128x64) 55 display.clearDisplay(); 56 //display.setRotation(2); //uncomment this line if you want to mount the display upside down 57 58 Wire.begin(); // join i2c bus as master 59 TWBR = 5; // freq=615kHz period=1.625uS 60 61 //Assigns encoder switch push event to interrupt 1 Pin 3 of Arduino 62 attachInterrupt(digitalPinToInterrupt(PinS), encoderSwitch, FALLING); 63 64 DDS_Init(); //Initialize the DDS module; 65 setConfig(); //Load config and set startup values 66 67} //---> end setup() 68 69void loop() { 70 JX_WaveGenerator_MAIN(); 71} 72 73//----------------------------------------------------------------------------------------------------------------------------------------- 74// JX WaveGenerator MAIN function 75//----------------------------------------------------------------------------------------------------------------------------------------- 76void JX_WaveGenerator_MAIN() { 77 78 byte encoderSpin = Encoder.rotate(); //Encoder rotation direction 1=CW, 2=CCW 79 byte encoderLongPush = Encoder.pushLong(1000); //encoder long push event 80 long lStep = 0; //current frequency step value 81 long wTime = 600000; //10 min 82 83 if (encoderPush) delay(250); 84 85 if (encoderSpin) { 86 cTime = millis(); 87 } else { 88 if (millis() - cTime > wTime) { 89 ScreenSaver(); 90 } 91 } 92 93 switch (mode) { 94 95 case LOGARITHMIC: //0 96 //----------------------------------------------------------------------------------------------------------------------------------- 97 // mode LOGARITHMIC: Encoder rotation change frequency in logaritmic step 1,10,100,1000,10000,100000 Hz 98 //----------------------------------------------------------------------------------------------------------------------------------- 99 if (encoderSpin) { 100 101 if (lFreq >= 1) { 102 lStep = AutoStep(lFreq, encoderSpin); //Calculate logaritmic step 103 } else if (_CouplingMode == OFF) { //if coupling mode is set to OFF 104 resetCouplingMode(); //set default coupling mode when Frequency is not 0 105 encoderSpin = 0; //skip first spin 106 } 107 108 if (encoderSpin == CW && lFreq <= 999999 - lStep) { //spin CW increment the frequency 109 lFreq += lStep; 110 } 111 if (encoderSpin == CCW && lFreq >= lStep + 1) { //spin CCW decrement the frequency 112 lFreq -= lStep; 113 } 114 115 DDS_FrequencySet(lFreq, Wave[_WaveType]); //send the frequency value to DDS module 116 displayFrequency(lFreq); //send formatted freq to display 117 lLastFreq = lFreq; //save current freq 118 } 119 120 //----------------------------------------------------------------------------------------------------------------------------------- 121 // workmode LOGARITHMIC: Encoder push switch to OPTIONS mode 122 //----------------------------------------------------------------------------------------------------------------------------------- 123 if (encoderPush) { 124 encoderPush = false; //Clear push flag 125 drawSymbol(1); //draw arrow symbol 126 selectIcon(0, WHITE); //draw a border around first icon 127 idx = 0; idy = 0; //reset pointers var 128 mode = OPTIONS; //go to mode OPTIONS 129 } 130 131 break; //end mode LOGARITHMIC 132 133 case SINGLEDIGIT: //1 134 //------------------------------------------------------------------------------------------------------------- 135 // submode SINGLEDIGIT: Encoder rotation move cursor left and right 136 //------------------------------------------------------------------------------------------------------------- 137 if (encoderSpin) { 138 if (encoderSpin == CW && idx < MAXDIGIT + 2) idx++; //clockwise increase pointer 139 if (encoderSpin == CCW && idx > 0) idx--; //counterclockwise decrease pointer 140 141 //------------------------------------------------------------------------------------------------------------ 142 // when idx is from 0 to 5 select frequency digits 143 //------------------------------------------------------------------------------------------------------------ 144 if (idx >= 0 && idx < MAXDIGIT) { //if the current position is within the digits 145 drawSymbol(0); //draw up arrow 146 selectDigit(idx); //show cursor at current position and delete previous 147 if (idx == 5) selectIcon(0, BLACK); //hide first icon selection 148 } 149 150 //------------------------------------------------------------------------------------------------------------ 151 // when idx is from 6 to 8 select icons 152 //------------------------------------------------------------------------------------------------------------ 153 if (idx >= MAXDIGIT && idx <= MAXDIGIT + 2) { //if the current position is beyond the digits 154 hideCursor(MAXDIGIT - 1); //hide cursor at last digit 155 drawSymbol(1); //draw dn arrow 156 selectIcon(idx - MAXDIGIT, WHITE); //select icon 157 } 158 } 159 160 //----------------------------------------------------------------------------------------------------------------------------------- 161 // submode SINGLEDIGIT: Encoder push event 162 //----------------------------------------------------------------------------------------------------------------------------------- 163 if (encoderPush) { 164 encoderPush = false; 165 166 //------------------------------------------------------------------------------------------------------------- 167 // if a digit from 0 to 5 are selected go to mode DIGITCHANGE 168 //------------------------------------------------------------------------------------------------------------- 169 if (idx <= MAXDIGIT - 1) { 170 hideCursor(idx); //flash cursor 171 delay(250); //for 172 selectDigit(idx); //visual confirmation 173 drawSymbol(2); //draw turn icon 174 mode = DIGITCHANGE; //change mode 175 } 176 //------------------------------------------------------------------------------------------------------------- 177 // otherwise there is an icon selected then go to OPTIONS 178 //------------------------------------------------------------------------------------------------------------- 179 else { 180 if (idx >= MAXDIGIT && idx <= MAXDIGIT + 2) { 181 idy = idx - MAXDIGIT; 182 selectOption(idy); 183 idy = options[idy]; 184 } 185 } 186 } 187 break; //end mode SINGLEDIGIT 188 189 190 case SWEEP://2 191 //---------------------------------------------------------------------------------------------------------------- 192 // workmode SWEEP: Encoder rotation move cursor left and right for option selection 193 //---------------------------------------------------------------------------------------------------------------- 194 if (encoderSpin) { 195 if (encoderSpin == CW && idy < 2) idy++; 196 if (encoderSpin == CCW && idy > 0) idy--; 197 selectIcon(idy, WHITE); 198 } 199 200 if (encoderPush) { 201 //----------------------------------------------------------------------------------------------------------------------------------- 202 // workmode SWEEP: Encoder push go to OPTIONS, SWEEP OPTIONS or START/STOP sweep 203 //----------------------------------------------------------------------------------------------------------------------------------- 204 encoderPush = false; 205 206 switch (idy) { 207 case 0: 208 lFreq = atol(Freq); 209 selectOption(idy); 210 idy = options[idy]; 211 delay(100); 212 if (_WorkMode != 2) displayFrequency(lLastFreq); 213 SweepReset(); 214 break; 215 216 case 1: 217 lFreq = atol(Freq); 218 drawSymbol(9); 219 drawSymbol(1); 220 displaySweepIcons(); 221 selectIcon(0, WHITE); 222 idy = 0; 223 displayFrequency(_Sweep(idy)); 224 delay(100); 225 SweepReset(); 226 mode = OPTSWEEP; 227 break; 228 229 case 2: 230 //** sweepStatus: STILL 0 (never started), 1 BREAK, 2 PAUSE ** 231 if (sweepStatus == STILL || sweepStatus == PAUSE) { 232 drawSymbol(3); //draw pause icon 233 selectIcon(2, WHITE); //select icon 234 FrequencySweep(); //run sweep 235 } 236 else { //if paused 237 drawSymbol(4); //draw play icon 238 sweepStatus = PAUSE; 239 } 240 break; 241 } 242 } 243 if (sweepStatus == PAUSE) flashIcon(250); //flashing pause text 244 break; //end mode SWEEP 245 246 case OPTIONS://3 247 if (encoderLongPush) reset(); 248 249 //----------------------------------------------------------------------------------------------------------------------------------- 250 // mode OPTIONS: Encoder spin select option to change (workmode, wavetype, couplingmode) 251 //----------------------------------------------------------------------------------------------------------------------------------- 252 if (encoderSpin) { 253 if (encoderSpin == CW && idy < 2) idy++; 254 if (encoderSpin == CCW && idy > 0) idy--; 255 selectIcon(idy, WHITE); 256 } 257 258 //----------------------------------------------------------------------------------------------------------------------------------- 259 // mode OPTIONS: Encoder push switch to relative mode 260 //----------------------------------------------------------------------------------------------------------------------------------- 261 if (encoderPush) { 262 encoderPush = false; 263 //selectIcon(idy, BLACK); 264 selectOption(idy); 265 hideCursor(0); 266 idy = options[idy]; 267 } 268 break; //end mode OPTIONS 269 270 271 case OPTMODE://4 272 //----------------------------------------------------------------------------------------------------------------------------------- 273 // mode OPTMODE: Encoder spin select mode icons (logarithmic, singledigit, sweep) 274 //----------------------------------------------------------------------------------------------------------------------------------- 275 if (encoderSpin) { 276 if (encoderSpin == CW && idy < 2) idy++; 277 if (encoderSpin == CCW && idy > 0) idy--; 278 selectIcon(idy, WHITE); 279 } 280 281 //----------------------------------------------------------------------------------------------------------------------------------- 282 // mode OPTMODE: Encoder push select workmode to set (stored in option[0]) 283 //----------------------------------------------------------------------------------------------------------------------------------- 284 if (encoderPush) { 285 encoderPush = false; 286 byte pMode = _WorkMode; 287 switch (idy) { 288 case 0: 289 hideCursor(0); 290 drawSymbol(0); 291 lFreq = lLastFreq; 292 displayFrequency(lFreq); 293 _setWorkMode(LOGARITHMIC); 294 break; 295 296 case 1: 297 drawSymbol(0); 298 selectDigit(0); 299 lFreq = lLastFreq; 300 displayFrequency(lFreq); 301 _setWorkMode(SINGLEDIGIT); 302 break; 303 304 case 2: 305 lLastFreq = lFreq; 306 displayFrequency(_SweepMin); //ready to start 307 _setWorkMode(SWEEP); 308 break; 309 } 310 mode = _WorkMode; 311 if (pMode != _WorkMode) saveConfig(); 312 if (_CouplingMode == OFF) resetCouplingMode(); 313 idx = 0; 314 drawAllIcons(); 315 } 316 break; //end mode OPTMODE 317 318 319 case OPTWAVE://5 320 //---------------------------------------------------------------------------------------------------------------- 321 // mode OPTWAVE: Encoder rotation move cursor left and right for wave selection (sqr, sin, tri) 322 //---------------------------------------------------------------------------------------------------------------- 323 if (encoderSpin) { 324 if (encoderSpin == CW && idy < 2) idy++; 325 if (encoderSpin == CCW && idy > 0) idy--; 326 selectIcon(idy, WHITE); 327 } 328 329 //-------------------------------------------------------------------------------------------------------------------- 330 // mode OPTWAVE: Encoder push set new wave type 331 //-------------------------------------------------------------------------------------------------------------------- 332 if (encoderPush) { 333 encoderPush = false; 334 if (_WaveType != idy) { 335 _setWaveType(idy); 336 saveConfig(); 337 } 338 UpdateFrequency(); //updates wavetype 339 drawAllIcons(); 340 idx = 0; 341 mode = _WorkMode; 342 343 } 344 break; //end mode OPTWAVE 345 346 347 case OPTCOUP://6 348 //---------------------------------------------------------------------------------------------------------------- 349 // mode OPTCOUP: Encoder rotation move cursor left and right for coupling mode selection 350 //---------------------------------------------------------------------------------------------------------------- 351 if (encoderSpin) { 352 if (encoderSpin == CW && idy < 2) idy++; 353 if (encoderSpin == CCW && idy > 0) idy--; 354 selectIcon(idy, WHITE); 355 } 356 357 //-------------------------------------------------------------------------------------------------------------------- 358 // mode OPTCOUP: Encoder push select current coupling mode 359 //-------------------------------------------------------------------------------------------------------------------- 360 if (encoderPush) { 361 encoderPush = false; 362 setCouplingMode(idy); 363 drawAllIcons(); 364 idx = 0; 365 mode = _WorkMode; 366 } 367 break; //end mode OPTCOUP 368 369 370 371 case OPTSWEEP://7 372 //-------------------------------------------------------------------------------------------------------------------- 373 // mode OPTSWEEP: Encoder spin select sweep values to edit 374 //-------------------------------------------------------------------------------------------------------------------- 375 if (encoderSpin) { 376 if (encoderSpin == CW && idy < 2) idy++; //clockwise increase pointer 377 if (encoderSpin == CCW && idy > 0) idy--; //counterclockwise decrease pointer 378 selectIcon(idy, WHITE); //select first icon 379 displayFrequency(_Sweep(idy)); //display current sweep value 380 } 381 382 383 if (encoderPush) { 384 encoderPush = false; 385 //-------------------------------------------------------------------------------------------------------------------- 386 // mode OPTSWEEP: Encoder push confirm sweep values to edit 387 //-------------------------------------------------------------------------------------------------------------------- 388 drawSymbol(0); 389 selectDigit(0); 390 selectIcon(idy, WHITE); 391 idx = 0; 392 displayFrequency(_Sweep(idy)); 393 mode = SWEEPEDIT; 394 } 395 break; //end mode OPTSWEEP 396 397 398 case SWEEPEDIT://8 399 400 //-------------------------------------------------------------------------------------------------------------- 401 // mode SWEEPEDIT: Encoder spin select digit to change 402 //-------------------------------------------------------------------------------------------------------------- 403 if (encoderSpin) { 404 if (encoderSpin == CW && idx < MAXDIGIT - 1) idx++; //clockwise increase pointer 405 if (encoderSpin == CCW && idx > 0) idx--; //counterclockwise decrease pointer 406 selectDigit(idx); 407 } 408 409 //-------------------------------------------------------------------------------------------------------------- 410 // mode SWEEPEDIT: Encoder longpush exit from edit and return to SWEEP 411 //-------------------------------------------------------------------------------------------------------------- 412 if (encoderLongPush == LONGPUSH) { 413 encoderPush = false; 414 drawAllIcons(); 415 displayFrequency(_SweepMin); 416 hideCursor(idx); 417 _setWorkMode(SWEEP); 418 SweepReset(); 419 mode = _WorkMode; 420 delay(250); 421 } 422 423 if (encoderPush) { 424 encoderPush = false; 425 //------------------------------------------------------------------------------------------------------------- 426 // mode SWEEPEDIT: Encoder push go to mode DIGITCHANGE 427 //------------------------------------------------------------------------------------------------------------- 428 hideCursor(idx); //flash cursor 429 delay(250); //for 430 selectDigit(idx); //visual confirmation 431 drawSymbol(2); //draw turn icon 432 mode = DIGITCHANGE; //change mode 433 } 434 break;//end mode SWEEPEDIT 435 436 case DIGITCHANGE://9 437 //--------------------------------------------------------------------------------------------------------- 438 // mode DIGITCHANGE: Encoder longpush exit from DIGITCHANGE when in SWEEP mode 439 //--------------------------------------------------------------------------------------------------------- 440 if (encoderLongPush == LONGPUSH && _WorkMode == SWEEP) { 441 encoderPush = false; 442 hideCursor(idx); 443 drawSymbol(1); 444 mode = OPTSWEEP; 445 delay(250); 446 } 447 448 //--------------------------------------------------------------------------------------------------------- 449 // mode DIGITCHANGE: Encoder rotation change digit value (0 -> 9 ->0 and so on) 450 //--------------------------------------------------------------------------------------------------------- 451 if (encoderSpin) { //encoder rotation 452 if (encoderSpin == CW) { //clockwise direction 453 Freq[idx]++; if (Freq[idx] > '9') Freq[idx] = '0'; 454 } else { //counter clockwise direction 455 Freq[idx]--; if (Freq[idx] < '0') Freq[idx] = '9'; 456 } 457 updateDigit(idx, Freq[idx]); //update digit on display 458 } 459 460 //--------------------------------------------------------------------------------------------------------- 461 // mode DIGITCHANGE: Encoder push return to mode SINGLEDIGIT or SWEEPEDIT 462 //--------------------------------------------------------------------------------------------------------- 463 if (encoderPush) { //encoder push flag set by interrupt 464 encoderPush = false; //reset event flag 465 hideCursor(idx); //flash cursor 466 delay(250); //for 467 selectDigit(idx); //visual confirmation 468 drawSymbol(0); 469 470 if (_WorkMode == SWEEP) { 471 long ltemp = _Sweep(idy) ; //save value 472 _setSweep(idy, atol(Freq)); //convert new value from array to long 473 if (_SweepMax > 0 && _SweepMax > _SweepMin && _SweepStep > 0) { //check congruency of the new sweep value 474 if (_Sweep(idy) != ltemp) saveConfig(); //if value has changed write new value in EEPROM 475 displayFrequency(_Sweep(idy)); 476 mode = SWEEPEDIT; //change mode 477 } else { 478 _displayErrMsg; //display error message stored in flash mem 479 delay(1000); 480 _setSweep(idy, ltemp); //restore saved value 481 displayFrequency(_Sweep(idy)); //redisplay value 482 drawSymbol(2); //redraw turn icon 483 } 484 485 } else { //if not in sweep mode 486 if (_CouplingMode == OFF) { //if coupling mode if OFF 487 lLastFreq = atol(Freq); //save current frequency 488 resetCouplingMode(); //set default coupling mode 489 } 490 UpdateFrequency(); //send frequency to DDS Module 491 mode = SINGLEDIGIT; //change mode 492 } 493 } 494 break; //end mode DIGITCHANGE 495 496 default: 497 break; 498 } 499} 500 501//----------------------------------------------------------------------------------------------------------------------------------- 502// Push encoder event - Called by interrupt 503//----------------------------------------------------------------------------------------------------------------------------------- 504void encoderSwitch(void) { 505 encoderPush = true; 506} 507 508//----------------------------------------------------------------------------------------------------------------------------------- 509// Utility functions 510//----------------------------------------------------------------------------------------------------------------------------------- 511// Draw graphics interface 512//---------------------------------------------------------------------------------------------------------------- 513void drawInterface() { 514 515 display.clearDisplay(); 516 display.display(); 517 delay(1000); 518 519 display.drawRoundRect(0, 0, 128, 64, 3, WHITE); //draw external frame 520 display.fillRect(1, 1, 126, 14, WHITE); //draw caption frame 521 522 displayText(12, 4, strFromFlash(0), BLACK, WHITE, SMALL); //print caption title 523 delay(1000); 524 525 if (cTime == 1) { //only on power on 526 displayText(XPOS - 6, YPOS + 10, strFromFlash(1), WHITE, BLACK, BIG); //show Welcom message 527 delay(1000); 528 display.fillRect(2, 16, display.width() - 3, 35, BLACK); //clear Welcome message 529 cTime = 0; 530 } 531 532 display.display(); 533 534 displayText(XPOS + 84, YPOS + 4, strFromFlash(2), WHITE, BLACK, SMALL); //print "Hz" 535 536 sprintf(Freq, "%06li", lFreq); //put frequency value into char array with template "000000" 537 for (int i = MAXDIGIT - 1; i >= 0; i--) { 538 display.drawChar(XPOS + 2 + i * DELTAX, YPOS, Freq[i] , WHITE, BLACK, BIG); //Display with animation effect from right to left 539 display.display(); 540 } 541 542}//end drawInterface() 543 544 545//---------------------------------------------------------------------------------------------------------------- 546// Print string in x,y pos with specified colors and size 547//---------------------------------------------------------------------------------------------------------------- 548void displayText(byte x, byte y, const char *str, byte foreColor, byte backColor, byte textSize) { 549 display.setTextSize(textSize); //textsize: SMALL or BIG global const 550 display.setTextColor(foreColor, backColor); //colors WHITE or BLACK global const of the library 551 display.setCursor(x, y); //set the cursor position 552 display.print(str); //str is the pointer to the string of chars 553 display.display(); //update display 554} 555 556//---------------------------------------------------------------------------------------------------------------- 557// Copies element [i] of the string_table array from flash memory to the ram buffer and returns the pointer to the buffer 558//---------------------------------------------------------------------------------------------------------------- 559char* strFromFlash(byte i) { 560 strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); 561 return (char*)buffer; 562} 563 564//---------------------------------------------------------------------------------------------------------------- 565// Draw or clear a border around selected icon after clearing border of the previous one 566//---------------------------------------------------------------------------------------------------------------- 567void selectIcon(byte icon, byte color) { 568 static byte prevIcon; 569 display.drawRect(XPOS - 10 + prevIcon * 32, YPOS + 19, 29, 20, BLACK); 570 display.drawRect(XPOS - 10 + icon * 32, YPOS + 19, 29, 20, color); 571 display.display(); 572 prevIcon = icon; 573} 574 575//---------------------------------------------------------------------------------------------------------------- 576// Display all workmode icons 577//---------------------------------------------------------------------------------------------------------------- 578void displayWorkModeIcons(void) { 579 byte const *bitmap[3] = {imgLog, imgDigit, imgSweep}; 580 _clearIconsArea; 581 for (byte i = 0; i <= 2; i++) { 582 display.drawBitmap(XPOS - 8 + i * 32, YPOS + 21, bitmap[i], 25, 16, WHITE); 583 } 584 display.display(); 585} 586 587//---------------------------------------------------------------------------------------------------------------- 588// Display all wavetype icons 589//---------------------------------------------------------------------------------------------------------------- 590void displayWaveTypeIcons(void) { 591 byte const *bitmap[3] = {imgSqr, imgSin, imgTri}; 592 _clearIconsArea; 593 for (byte i = 0; i <= 2; i++) { 594 display.drawBitmap(XPOS - 8 + i * 32, YPOS + 21, bitmap[i], 25, 16, WHITE); 595 } 596 display.display(); 597} 598 599//---------------------------------------------------------------------------------------------------------------- 600// Display all coupling mode icons 601//---------------------------------------------------------------------------------------------------------------- 602void displayCouplingModeIcons(void) { 603 byte const *bitmap[3] = {imgCoAc, imgCoDc, imgCoOff}; 604 _clearIconsArea; 605 for (byte i = 0; i <= 2; i++) { 606 display.drawBitmap(XPOS - 8 + i * 32, YPOS + 21, bitmap[i], 25, 16, WHITE); 607 } 608 display.display(); 609} 610 611//---------------------------------------------------------------------------------------------------------------- 612// Display all sweep icons 613//---------------------------------------------------------------------------------------------------------------- 614void displaySweepIcons(void) { 615 byte const *bitmap[3] = {imgSwMax, imgSwMin, imgSwStep}; 616 _clearIconsArea; 617 for (byte i = 0; i <= 2; i++) { 618 display.drawBitmap(XPOS - 8 + i * 32, YPOS + 21, bitmap[i], 25, 16, WHITE); 619 } 620 display.display(); 621} 622 623//---------------------------------------------------------------------------------------------------------------- 624// Draw all icons 625//---------------------------------------------------------------------------------------------------------------- 626void drawAllIcons(void) { 627 _clearIconsArea; 628 drawModeIcon(); 629 630 if (_WorkMode == SWEEP || _WorkMode == SWEEPEDIT ) { 631 display.drawBitmap(XPOS + 24, YPOS + 21, imgSwOpt, 25, 16, WHITE); 632 display.drawBitmap(XPOS + 56, YPOS + 21, imgSwStart, 25, 16, WHITE); 633 drawSymbol(1); 634 idy = 2; 635 selectIcon(idy, WHITE); //ready to sweep 636 drawSmallWaveIcon(); 637 drawSmallCouplingIcon(); 638 } 639 else { 640 drawWaveIcon(); 641 drawCouplingIcon(); 642 drawSymbol(0); 643 if (_WorkMode == SINGLEDIGIT) selectDigit(0); 644 } 645 display.display(); 646} 647 648//---------------------------------------------------------------------------------------------------------------- 649// Draws the icon based on the value of relative option 650//---------------------------------------------------------------------------------------------------------------- 651void drawModeIcon(void) { 652 byte x = XPOS - 8, y = YPOS + 21; 653 byte const *bitmap[3] = {imgLog, imgDigit, imgSweep}; 654 display.fillRect(x, y, 25, 16, BLACK); 655 display.drawBitmap(x, y, bitmap[_WorkMode], 25, 16, WHITE); 656 display.display(); 657} 658 659void drawWaveIcon(void) { 660 byte x = XPOS + 24, y = YPOS + 21; 661 const byte *bitmap[3] = {imgSqr, imgSin, imgTri}; 662 display.fillRect(x, y, 25, 16, BLACK); 663 display.drawBitmap(x, y, bitmap[_WaveType], 25, 16, WHITE); 664 display.display(); 665 drawSmallWaveIcon(); 666} 667 668void drawCouplingIcon(void) { 669 byte x = XPOS + 56, y = YPOS + 21; 670 const byte *bitmap[3] = {imgCoAc, imgCoDc, imgCoOff}; 671 display.fillRect(x, y, 25, 16, BLACK); 672 display.drawBitmap(x, y, bitmap[_CouplingMode], 25, 16, WHITE); 673 display.display(); 674 drawSmallCouplingIcon(); 675} 676 677 678//---------------------------------------------------------------------------------------------------------------- 679// Draws small wave icon based on the value of relative option 680//---------------------------------------------------------------------------------------------------------------- 681void drawSmallWaveIcon(void) { 682 byte x = 114, y = 41; 683 const byte *bitmap[3] = {imgSqrSmall, imgSinSmall, imgTriSmall}; 684 display.fillRect(x, y, 9, 8, BLACK); 685 display.drawBitmap(x, y, bitmap[_WaveType], 9, 8, WHITE); 686 display.display(); 687} 688 689 690//---------------------------------------------------------------------------------------------------------------- 691// Draws small coupling icon based on the value of relative option 692//---------------------------------------------------------------------------------------------------------------- 693void drawSmallCouplingIcon(void) { 694 byte x = 114, y = 50; 695 const byte *bitmap[3] = {imgAcSmall, imgDcSmall, imgOffSmall}; 696 display.fillRect(x, y, 9, 8, BLACK); 697 display.drawBitmap(x, y, bitmap[_CouplingMode], 9, 8, WHITE); 698 display.display(); 699} 700 701//---------------------------------------------------------------------------------------------------------------- 702// Show cursor at x position 703//---------------------------------------------------------------------------------------------------------------- 704void showCursor(byte x) { 705 display.drawChar(XPOS + 2 + x * DELTAX, YPOS + DELTAY, CURSOR, WHITE, WHITE, BIG); 706 display.display(); 707} 708 709//---------------------------------------------------------------------------------------------------------------- 710// Hide cursor at x position 711//---------------------------------------------------------------------------------------------------------------- 712void hideCursor(byte x) { 713 display.drawChar(XPOS + 2 + x * DELTAX, YPOS + DELTAY, CURSOR, BLACK, BLACK, BIG); 714 display.display(); 715} 716 717//---------------------------------------------------------------------------------------------------------------- 718// Show cursor at x position after hiding previous one 719//---------------------------------------------------------------------------------------------------------------- 720void selectDigit(byte x) { 721 static byte lastDigit; 722 hideCursor(lastDigit); 723 display.drawChar(XPOS + 2 + x * DELTAX, YPOS + DELTAY, CURSOR, WHITE, WHITE, BIG); 724 display.display(); 725 lastDigit = x; 726} 727 728//---------------------------------------------------------------------------------------------------------------- 729// Update single digit frequency to chr value 730//---------------------------------------------------------------------------------------------------------------- 731void updateDigit(byte digit, char chr) { 732 display.drawChar(XPOS + 2 + digit * DELTAX, YPOS, chr , WHITE, BLACK, BIG); 733 display.display(); 734} 735 736//---------------------------------------------------------------------------------------------------------------- 737// Drwaw or clear some symbols/icons 738//---------------------------------------------------------------------------------------------------------------- 739void drawSymbol(byte symbol) { 740 741 switch (symbol) { 742 case 0: //Top arrow 743 display.fillRect(2, 20, 25, 16, BLACK); 744 display.fillRect(2, 43, 14, 16, BLACK); 745 display.drawChar(XPOS - 20 , YPOS + 4, ARROW, WHITE, BLACK, SMALL); //draw top arrow top 746 break; 747 748 case 1: //Bottom arrow 749 display.fillRect(2, 20, 25, 16, BLACK); 750 display.fillRect(2, 43, 14, 16, BLACK); 751 display.drawChar(XPOS - 20 , YPOS + 25, ARROW, WHITE, BLACK, SMALL); //draw bottom arrow 752 break; 753 754 case 2: //Turn icon 755 display.fillRect(2, 20, 25, 16, BLACK); 756 display.drawBitmap(XPOS - 21, YPOS + 1, imgTurn, 13, 13, WHITE); //draw turn icon 757 break; 758 759 case 3: //Play icons 760 display.fillRect(4, 23, 23, 11, BLACK); //clear pause icon 761 display.drawBitmap(4, 23, imgSwRun, 23, 11, WHITE); //draw sweep icon 762 display.fillRect(XPOS + 56, YPOS + 21, 25, 16, BLACK); //clear icon area 763 display.drawBitmap(XPOS + 56, YPOS + 21, imgSwPause, 25, 16, WHITE); //drwaw sweep play symbol icon 764 break; 765 766 case 4: //Pause icons 767 display.fillRect(4, 23, 23, 11, BLACK); //clear sweep icon 768 display.drawBitmap(4, 23, imgSwPsd, 23, 11, WHITE); //draw pause icon 769 display.fillRect(XPOS + 56, YPOS + 21, 25, 16, BLACK); //clear icon area 770 display.drawBitmap(XPOS + 56, YPOS + 21, imgSwStart, 25, 16, WHITE); //draw sweep pause symbol icon 771 break; 772 773 case 9: //Simply clear symbol area 774 display.fillRect(2, 20, 25, 16, BLACK); //clear top symbol area 775 display.fillRect(2, 43, 14, 16, BLACK); //clear bottom symbol area 776 break; 777 778 default: 779 break; 780 } 781 display.display(); 782} 783 784//--------------------------------------------------------------------------------------------------------------- 785// Set current frequency in DDS module, if frequency is 0 it will be set to 1 786//--------------------------------------------------------------------------------------------------------------- 787void UpdateFrequency(void) { 788 lFreq = atol(Freq); //convert char array to long 789 if (lFreq < 1) { //the frequency at zero makes no sense 790 ++Freq[MAXDIGIT - 1]; //increase the right most digit 791 lFreq = 1; //set frequency to 1 792 } 793 displayFrequency(lFreq); //update the display 794 DDS_FrequencySet(lFreq, Wave[_WaveType]); //send the frequency value to DDS module 795 lLastFreq = lFreq; //save current freq 796} 797 798//--------------------------------------------------------------------------------------------------------------- 799// Display the frequency with the six-zero template 800//--------------------------------------------------------------------------------------------------------------- 801void displayFrequency(long f) { 802 sprintf(Freq, "%06li", f); //convert long to char with template '000000' 803 displayText(XPOS + 2, YPOS, Freq , WHITE, BLACK, BIG); //print frequency on display 804 display.display(); //refresh display 805} 806 807//--------------------------------------------------------------------------------------------------------------- 808// Reset coupling mode to default 809//--------------------------------------------------------------------------------------------------------------- 810void resetCouplingMode(void) { 811 if (lFreq == 0 && _CouplingMode == OFF) { 812 setCouplingMode(AC); 813 drawCouplingIcon(); 814 } 815} 816 817//--------------------------------------------------------------------------------------------------------------- 818// Set a specific coupling mode 819//--------------------------------------------------------------------------------------------------------------- 820void setCouplingMode(byte cMode) { 821 byte pMode = _CouplingMode; 822 switch (cMode) { 823 case 0: 824 if (lLastFreq > 0) lFreq = lLastFreq; 825 digitalWrite(PinCoupling, LOW); 826 _setCouplingMode(AC); 827 break; 828 829 case 1: 830 if (lLastFreq > 0) lFreq = lLastFreq; 831 digitalWrite(PinCoupling, HIGH); 832 _setCouplingMode(DC); 833 break; 834 835 case 2: 836 lLastFreq = lFreq; 837 lFreq = 0; 838 digitalWrite(PinCoupling, LOW); 839 _setCouplingMode(OFF); 840 break; 841 } 842 DDS_FrequencySet(lFreq, Wave[_WaveType]); 843 displayFrequency(lFreq); 844 if (cMode != pMode) saveConfig(); 845} 846 847 848//--------------------------------------------------------------------------------------------------------------- 849// Select options 850//--------------------------------------------------------------------------------------------------------------- 851void selectOption(byte opt) { 852 853 selectIcon(opt, BLACK); 854 855 switch (opt) { 856 case 0: //workMode; 857 displayWorkModeIcons(); 858 selectIcon(_WorkMode, WHITE); 859 mode = OPTMODE; 860 break; 861 862 case 1: //waveType; 863 displayWaveTypeIcons(); 864 selectIcon(_WaveType, WHITE); 865 mode = OPTWAVE; 866 break; 867 868 case 2: //couplingMode; 869 displayCouplingModeIcons(); 870 selectIcon(_CouplingMode, WHITE); 871 mode = OPTCOUP; 872 break; 873 } 874} 875 876//---------------------------------------------------------------------------------------------------------------- 877// Calculate logarithmic steps of the frequency 878//---------------------------------------------------------------------------------------------------------------- 879long AutoStep(long value, byte spin) { 880 if (spin == CW) { 881 if (value >= 100000) return 100000; 882 if (value >= 10000) return 10000; 883 if (value >= 1000) return 1000; 884 if (value >= 100) return 100; 885 if (value >= 10) return 10; 886 if (value >= 1) return 1; 887 return 0; // Invalid value 888 } 889 else { 890 if (value <= 10) return 1; 891 if (value <= 100) return 10; 892 if (value <= 1000) return 100; 893 if (value <= 10000) return 1000; 894 if (value <= 100000) return 10000; 895 if (value <= 1000000) return 100000; 896 return 0; // Invalid value 897 } 898} 899 900//------------------------------------------------------------------------------------------- 901// Start Sweep or restart it from where it came from before the pause 902//------------------------------------------------------------------------------------------- 903void FrequencySweep() { 904 do { 905 if (sweepDnPausedVal == 0) { //if sweepDown has not been stopped 906 if (sweepUpPausedVal > 0) { //and sweepUp has been stopped 907 sweepUpPausedVal = SweepUp(sweepUpPausedVal); //continues from current value 908 } 909 else { 910 sweepUpPausedVal = SweepUp(_SweepMin); //else start from min 911 } 912 } 913 if (sweepStatus != BREAK) { //if sweep has been stopped 914 if (sweepDnPausedVal > 0) { //and sweepDn has been stopped 915 sweepDnPausedVal = SweepDn(sweepDnPausedVal); //continues from current value 916 } 917 else { 918 sweepDnPausedVal = SweepDn(_SweepMax); //else start from max 919 } 920 } 921 } while (sweepStatus != BREAK); //continues sweep until stopped 922} 923 924//----------------------------------------------------------------------------------------- 925// Sweep Up from sweepmin push encoder to pause 926//----------------------------------------------------------------------------------------- 927long SweepUp(long sweepmin) { 928 long f; 929 930 for (f = sweepmin ; f < _SweepMax ; f += _SweepStep) { 931 DDS_FrequencySet(f, Wave[_WaveType]); 932 displayFrequency(f); 933 if (encoderPush) { 934 sweepStatus = BREAK; 935 break; 936 } 937 } 938 if (sweepStatus == BREAK) return f; 939 return 0; 940} 941 942//----------------------------------------------------------------------------------------- 943// Sweep down from sweepmax push encoder to pause 944//----------------------------------------------------------------------------------------- 945long SweepDn(long sweepmax) { 946 long f; 947 948 for (f = sweepmax; f > _SweepMin ; f -= _SweepStep) { 949 DDS_FrequencySet(f, Wave[_WaveType]); 950 displayFrequency(f); 951 if (encoderPush) { 952 sweepStatus = BREAK; 953 break; 954 } 955 } 956 if (sweepStatus == BREAK)return f; 957 return 0; 958} 959 960//----------------------------------------------------------------------------------------- 961// Clear global sweep vars and restore display 962//----------------------------------------------------------------------------------------- 963void SweepReset(void) { 964 sweepStatus = STILL; 965 sweepUpPausedVal = 0; 966 sweepDnPausedVal = 0; 967 display.fillRect(4, 23, 23, 11, BLACK); //clear sweep text 968 display.display(); 969} 970 971//----------------------------------------------------------------------------------------- 972// Flash sweep pause icon 973//----------------------------------------------------------------------------------------- 974void flashIcon(int interval) { 975 static long previousMillis; 976 static boolean picShow; 977 if (millis() - previousMillis >= interval) { 978 previousMillis = millis(); 979 picShow = !picShow; 980 if (picShow) { 981 display.drawBitmap(4, 23, imgSwPsd, 23, 11, WHITE); //drwaw sweep pause icon 982 display.display(); 983 } else { 984 display.fillRect(4, 23, 23, 11, BLACK); //clear sweep pause icon 985 display.display(); 986 } 987 } 988} 989 990//----------------------------------------------------------------------------------------- 991// Arduino software reset 992//----------------------------------------------------------------------------------------- 993void reset(void) { 994 display.fillRect(1, 16, 125, 46, BLACK); 995 display.display(); 996 displayText(30, 30, strFromFlash(4), WHITE, BLACK, BIG); 997 char str[2]; 998 for (byte i = 3; i > 0; i--) { 999 sprintf(str, "%d", i); 1000 displayText(95, 30, str, WHITE, BLACK, BIG); 1001 delay(1000); 1002 } 1003 display.clearDisplay(); 1004 display.display(); 1005 delay(1000); 1006 ATmegaReset(); 1007} 1008 1009//---------------------------------------------------------------------------------------------------------------- 1010// AD9833 DDS Module Functions 1011// For more details see ANALOG DEVICES data sheet at 1012// https://www.analog.com/media/en/technical-documentation/data-sheets/AD9833.pdf 1013//---------------------------------------------------------------------------------------------------------------- 1014 1015//---------------------------------------------------------------------------------------------------------------- 1016// DDS_WriteRegister() 1017//---------------------------------------------------------------------------------------------------------------- 1018void DDS_WriteRegister(word data) { 1019 digitalWrite(DDS_CLK, LOW); 1020 digitalWrite(DDS_CLK, HIGH); 1021 digitalWrite(DDS_FSY, LOW); 1022 for (byte i = 0; i < 16; i++) { 1023 if (data & 0x8000) 1024 digitalWrite(DDS_DAT, HIGH); 1025 else 1026 digitalWrite(DDS_DAT, LOW); 1027 data = data << 1; 1028 digitalWrite(DDS_CLK, HIGH); 1029 digitalWrite(DDS_CLK, LOW); 1030 } 1031 digitalWrite(DDS_CLK, HIGH); 1032 digitalWrite(DDS_FSY, HIGH); 1033} 1034 1035//---------------------------------------------------------------------------------------------------------------- 1036// DDS_Init() 1037//---------------------------------------------------------------------------------------------------------------- 1038void DDS_Init(void) { 1039 pinMode(DDS_DAT, OUTPUT); 1040 pinMode(DDS_CLK, OUTPUT); 1041 pinMode(DDS_FSY, OUTPUT); 1042 digitalWrite(DDS_FSY, HIGH); 1043 digitalWrite(DDS_CLK, HIGH); 1044 DDS_Reset(); 1045 DDS_FrequencyReset(lFreq, Wave[_WaveType]); 1046} 1047 1048//--------------------------------------------------------------------------------------------------------------- 1049// DDS_Reset() 1050//--------------------------------------------------------------------------------------------------------------- 1051void DDS_Reset() { 1052 DDS_WriteRegister(0x100); 1053 delay(100); 1054} 1055 1056//----------------------------------------------------------------------------- 1057// DDS_FrequencySet() set the AD9833 Module frequency and wave type 1058//----------------------------------------------------------------------------- 1059void DDS_FrequencySet(long frequency, int tWave) { 1060 long lf = frequency * (0x10000000 / 25000000.0); 1061 DDS_WriteRegister(0x2000 | tWave); 1062 DDS_WriteRegister((int)(lf & 0x3FFF) | 0x4000); 1063 DDS_WriteRegister((int)((lf & 0xFFFC000) >> 14) | 0x4000); 1064} 1065 1066//--------------------------------------------------------------------------------------------------------------- 1067// DDS_FrequencyReset() reset the AD9833 Module regs, set frequency and wave type 1068//--------------------------------------------------------------------------------------------------------------- 1069void DDS_FrequencyReset(long frequency, int tWave) { 1070 long lf = frequency * (0x10000000 / 25000000.0); 1071 DDS_WriteRegister(0x2100); 1072 DDS_WriteRegister((int)(lf & 0x3FFF) | 0x4000); 1073 DDS_WriteRegister((int)((lf & 0xFFFC000) >> 14) | 0x4000); 1074 DDS_WriteRegister(0xC000); 1075 DDS_WriteRegister(tWave); 1076} 1077 1078//--------------------------------------------------------------------------------------------------------------- 1079// CONFIGURATION Load & Save 1080//--------------------------------------------------------------------------------------------------------------- 1081 1082//--------------------------------------------------------------------------------------------------------------- 1083// Load whats in EEPROM in to the local CONFIG Struct if it is a valid setting 1084//--------------------------------------------------------------------------------------------------------------- 1085int loadConfig() { 1086 1087 // CONFIG_VERSION ID "JXWG1" 1088 if (EEPROM.read(CONFIG_START + 0) == CONFIG_VERSION[0] && 1089 EEPROM.read(CONFIG_START + 1) == CONFIG_VERSION[1] && 1090 EEPROM.read(CONFIG_START + 2) == CONFIG_VERSION[2] && 1091 EEPROM.read(CONFIG_START + 3) == CONFIG_VERSION[3] && 1092 EEPROM.read(CONFIG_START + 4) == CONFIG_VERSION[4]) { 1093 1094 EEPROM.get(CONFIG_START, CONFIG); 1095 return 1; // return 1 if config loaded 1096 } 1097 return 0; // return 0 if config NOT loaded 1098} 1099 1100//--------------------------------------------------------------------------------------------------------------- 1101// Save the CONFIGURATION in to EEPROM 1102// The EEPROM.put command uses the update method, it writes only if the new value is different from the one 1103// present in memory, to take care of the EEPROM which has ~100000 possible write operations 1104//--------------------------------------------------------------------------------------------------------------- 1105void saveConfig() { 1106 1107 CONFIG.workmode = _WorkMode; 1108 CONFIG.wavetype = _WaveType; 1109 CONFIG.couplingmode = _CouplingMode; 1110 CONFIG.reservedbyte = 0xFF; 1111 CONFIG.sweepmax = _SweepMax; 1112 CONFIG.sweepmin = _SweepMin; 1113 CONFIG.sweepstep = _SweepStep; 1114 1115 EEPROM.put(CONFIG_START, CONFIG); 1116} 1117 1118//---------------------------------------------------------------------------------------------------------- 1119// If successfully load configuration from EEPROM overwrite default values in the CONFIG struct 1120// note the large use of pre-compiler macros instead of cryptic arrays 1121//---------------------------------------------------------------------------------------------------------- 1122void setConfig() { 1123/* 1124 * 1125 //without macros 1126 1127 if (loadConfig()) { 1128 options[0] = CONFIG.workmode; 1129 options[1] = CONFIG.wavetype; 1130 options[2] = CONFIG.couplingmode; 1131 lSweep[0] = CONFIG.sweepmax; 1132 lSweep[1] =CONFIG.sweepmin; 1133 lSweep[2] = CONFIG.sweepstep; 1134 } else { 1135 saveConfig(); 1136 } 1137 1138*/ 1139 1140 if (loadConfig()) { 1141 _setWorkMode(CONFIG.workmode); 1142 _setWaveType(CONFIG.wavetype); 1143 _setCouplingMode(CONFIG.couplingmode); 1144 _setSweepMax(CONFIG.sweepmax); 1145 _setSweepMin(CONFIG.sweepmin); 1146 _setSweepStep(CONFIG.sweepstep); 1147 } else { 1148 saveConfig(); 1149 } 1150 1151 drawInterface(); //Draw all graphics interface 1152 mode = _WorkMode; 1153 1154 if (_CouplingMode == OFF && _WorkMode == SWEEP) { 1155 setCouplingMode(AC); 1156 } else { 1157 setCouplingMode(_CouplingMode); 1158 } 1159 1160 if (_CouplingMode == OFF) { 1161 lFreq = 0; 1162 displayFrequency(0); 1163 } 1164 1165 drawAllIcons(); 1166} //end setConfig() 1167 1168//----------------------------------------------------------------------------------------------------------- 1169// Show some flying icons after 10 minutes of inactivity to avoid persistence damage to the display 1170//----------------------------------------------------------------------------------------------------------- 1171void ScreenSaver() { 1172 byte x = 0, y = 1, d = 2, in = 10, i = 0; 1173 byte const *bitmap[3] = {imgSqr, imgSin, imgTri}; 1174 byte icons[in][3]; 1175 display.clearDisplay(); 1176 display.display(); 1177 1178 //initialize starting coordinates 1179 for (byte f = 0; f < in; f++) { 1180 icons[f][x] = random(display.width()); 1181 icons[f][y] = 0; 1182 icons[f][d] = random(5) + 1; 1183 } 1184 1185 // random choose a icon 1186 randomSeed(analogRead(0)); 1187 i = random(0, 3); 1188 1189 do { 1190 //draw each icon 1191 for (byte f = 0; f < in; f++) 1192 display.drawBitmap(icons[f][x], icons[f][y], bitmap[i], 25, 16, WHITE); 1193 1194 display.display(); 1195 delay(200); 1196 1197 //then erase it and move it 1198 for (byte f = 0; f < in; f++) { 1199 display.drawBitmap(icons[f][x], icons[f][y], bitmap[i], 25, 16, BLACK); 1200 icons[f][y] += icons[f][d]; 1201 1202 // if its gone, reinit 1203 if (icons[f][y] > display.height()) { 1204 icons[f][y] = random(display.width()); 1205 icons[f][y] = 0; 1206 icons[f][d] = random(5) + 1; 1207 } 1208 } 1209 } while (!encoderPush); //Push encoder to resume 1210 encoderPush = false; 1211 cTime = millis(); //reset counter 1212 setConfig(); //redraw display with current settings 1213} 1214 1215//last change in Turin on 01/16/2021 by Janux 1216
JXWG_Graphics.h
c_cpp
Icon resource data file
1 2// This file is an integral part of the JX_WaveGenerator.ino and must be 3// distributed together with the main file to allow it to function correctly. 4// The same license of the main file applies to this file. 5// Janux 01/04/2021 on Turin, Italy. 6 7#ifndef JXWG_Graphics 8#define JXWG_Graphics 9 10//---------------------------------------------------------------------------------------------- 11// Plain b&w bitmaps PROGMEM icons data 12//---------------------------------------------------------------------------------------------- 13 14const byte imgLog[] PROGMEM = { 15 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x88, 0x00, 0x40, 0x80, 0x9c, 0x00, 0x40, 0x80, 16 0x88, 0x00, 0x80, 0x80, 0x88, 0x00, 0x80, 0x80, 0x88, 0x01, 0x00, 0x80, 0x88, 0x02, 0x00, 0x80, 17 0x88, 0x0c, 0x00, 0x80, 0x88, 0x30, 0x00, 0x80, 0x89, 0xc0, 0x00, 0x80, 0x8e, 0x00, 0x10, 0x80, 18 0x9f, 0xff, 0xf8, 0x80, 0x88, 0x00, 0x10, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 19}; 20 21const byte imgDigit[] PROGMEM = { 22 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 23 0x9c, 0x47, 0x3e, 0x80, 0xa2, 0xc8, 0x82, 0x80, 0xa6, 0x40, 0x84, 0x80, 0xaa, 0x47, 0x0c, 0x80, 24 0xb2, 0x48, 0x02, 0x80, 0xa2, 0x48, 0x22, 0x80, 0x9c, 0xef, 0x9c, 0x80, 0x80, 0x00, 0x00, 0x80, 25 0x80, 0x00, 0x3e, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 26}; 27 28const byte imgSweep[] PROGMEM = { 29 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x8f, 0xcf, 0x38, 0x80, 30 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 31 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 0x88, 0x49, 0x28, 0x80, 32 0x88, 0x49, 0x28, 0x80, 0xb8, 0x79, 0xee, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 33}; 34 35const byte imgSqr[] PROGMEM = { 36 0xff, 0xff, 0xff, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0xff, 0x80, 0x80, 0x82, 0x88, 0xa0, 0x80, 37 0x80, 0x80, 0x80, 0x80, 0x82, 0x88, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0xaa, 0xaa, 0xaa, 0x80, 38 0x80, 0x80, 0x80, 0x80, 0x82, 0x88, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x82, 0x88, 0xa0, 0x80, 39 0xff, 0x80, 0xff, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 40}; 41 42const byte imgSin[] PROGMEM = { 43 0xff, 0xff, 0xff, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0x1c, 0x00, 0x80, 0x82, 0x2a, 0x20, 0x80, 44 0x80, 0x41, 0x00, 0x80, 0x82, 0x49, 0x20, 0x80, 0x80, 0x80, 0x80, 0x80, 0xaa, 0xaa, 0xaa, 0x80, 45 0x80, 0x80, 0x80, 0x80, 0xc3, 0x08, 0x61, 0x80, 0xc1, 0x00, 0x41, 0x80, 0xa2, 0x08, 0x22, 0x80, 46 0x9c, 0x00, 0x1c, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 47}; 48 49const byte imgTri[] PROGMEM = { 50 0xff, 0xff, 0xff, 0x80, 0x82, 0x08, 0x20, 0x80, 0x82, 0x00, 0x20, 0x80, 0x87, 0x08, 0x70, 0x80, 51 0x85, 0x00, 0x50, 0x80, 0x8a, 0x88, 0xa8, 0x80, 0x88, 0x80, 0x88, 0x80, 0xba, 0xeb, 0xae, 0x80, 52 0x90, 0x41, 0x04, 0x80, 0xa2, 0x2a, 0x22, 0x80, 0xa0, 0x22, 0x02, 0x80, 0xc2, 0x1c, 0x21, 0x80, 53 0xc0, 0x14, 0x01, 0x80, 0x82, 0x08, 0x20, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 54}; 55 56const byte imgCoAc[] PROGMEM = { 57 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 58 0x9c, 0x70, 0x00, 0x80, 0xa2, 0x88, 0x00, 0x80, 0xa2, 0x80, 0xc0, 0x80, 0xa2, 0x81, 0x24, 0x80, 59 0xbe, 0x81, 0x24, 0x80, 0xa2, 0x88, 0x18, 0x80, 0xa2, 0x70, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 60 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 61}; 62 63const byte imgCoDc[] PROGMEM = { 64 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 65 0xbc, 0x70, 0x00, 0x80, 0xa2, 0x88, 0x00, 0x80, 0xa2, 0x81, 0x54, 0x80, 0xa2, 0x80, 0x00, 0x80, 66 0xa2, 0x81, 0xfc, 0x80, 0xa2, 0x88, 0x00, 0x80, 0xbc, 0x70, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 67 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 68}; 69 70const byte imgCoOff[] PROGMEM = { 71 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 72 0x9c, 0xf7, 0x80, 0x80, 0xa2, 0x84, 0x22, 0x80, 0xa2, 0x84, 0x14, 0x80, 0xa2, 0xe7, 0x08, 0x80, 73 0xa2, 0x84, 0x14, 0x80, 0xa2, 0x84, 0x22, 0x80, 0x9c, 0x84, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 74 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 75}; 76 77const byte imgSwMax[] PROGMEM = { 78 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 79 0x81, 0x00, 0x00, 0x80, 0x82, 0x00, 0x00, 0x80, 0x87, 0x01, 0x00, 0x80, 0x82, 0x03, 0x80, 0x80, 80 0x82, 0x07, 0xc0, 0x80, 0x82, 0x0f, 0xe0, 0x80, 0x82, 0x1f, 0xf0, 0x80, 0x80, 0x00, 0x00, 0x80, 81 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 82}; 83 84const byte imgSwMin[] PROGMEM = { 85 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 86 0x81, 0x00, 0x00, 0x80, 0x82, 0x00, 0x00, 0x80, 0x87, 0x1f, 0xf0, 0x80, 0x82, 0x0f, 0xe0, 0x80, 87 0x82, 0x07, 0xc0, 0x80, 0x82, 0x03, 0x80, 0x80, 0x82, 0x01, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 88 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 89}; 90 91const byte imgSwOpt[] PROGMEM = { 92 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 93 0x84, 0x08, 0x10, 0x80, 0x88, 0x1c, 0x38, 0x80, 0x9c, 0x3e, 0x10, 0x80, 0x88, 0x00, 0x00, 0x80, 94 0x88, 0x00, 0x00, 0x80, 0x88, 0x3e, 0x00, 0x80, 0x88, 0x1c, 0x38, 0x80, 0x88, 0x08, 0x00, 0x80, 95 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 96}; 97 98const byte imgSwStep[] PROGMEM = { 99 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 100 0x84, 0x08, 0x04, 0x80, 0x88, 0x0c, 0x08, 0x80, 0x9c, 0x7e, 0x1c, 0x80, 0x88, 0x7f, 0x08, 0x80, 101 0x88, 0x7e, 0x08, 0x80, 0x88, 0x0c, 0x08, 0x80, 0x88, 0x08, 0x08, 0x80, 0x80, 0x00, 0x00, 0x80, 102 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 103}; 104 105const byte imgSwStart[] PROGMEM = { 106 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0xc0, 0x00, 0x80, 107 0x80, 0xf0, 0x00, 0x80, 0x80, 0xfc, 0x00, 0x80, 0x80, 0xff, 0x00, 0x80, 0x80, 0xff, 0xc0, 0x80, 108 0x80, 0xff, 0xc0, 0x80, 0x80, 0xff, 0x00, 0x80, 0x80, 0xfc, 0x00, 0x80, 0x80, 0xf0, 0x00, 0x80, 109 0x80, 0xc0, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 110}; 111 112const byte imgSwPause[] PROGMEM = { 113 0xff, 0xff, 0xff, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0x81, 0xe3, 0xc0, 0x80, 114 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 115 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 0x81, 0xe3, 0xc0, 0x80, 116 0x81, 0xe3, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x80 117}; 118 119const byte imgTurn[] PROGMEM = { 120 0x0f, 0x80, 0x30, 0x60, 0x47, 0x10, 0x58, 0xd0, 0x90, 0x48, 0x80, 0xe8, 0x90, 0x48, 0xb8, 0x08, 121 0x90, 0x48, 0x58, 0xd0, 0x47, 0x10, 0x30, 0x60, 0x0f, 0x80 122}; 123 124const byte imgSwRun[] PROGMEM = { 125 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x9b, 0xa2, 0x22, 0x6b, 0xae, 0xec, 0x7b, 0xae, 0xec, 0x9a, 126 0xa6, 0x62, 0xea, 0xae, 0xee, 0x6a, 0xae, 0xee, 0x9c, 0x62, 0x2e, 0xff, 0xff, 0xfe, 0x00, 0x00, 127 0x00 128}; 129 130const byte imgSwPsd[] PROGMEM = { 131 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0x1c, 0xdb, 0x30, 0x6b, 0x5a, 0xd6, 0x6b, 0x5a, 0xf6, 0x18, 132 0x5b, 0x32, 0x7b, 0x5b, 0xd6, 0x7b, 0x5a, 0xd6, 0x7b, 0x67, 0x30, 0xff, 0xff, 0xfe, 0x00, 0x00, 133 0x00 134}; 135 136//Small icons --------------------------------------------------------------------------------- 137const byte imgSqrSmall[] PROGMEM = { 138 0x00, 0x00, 0x3e, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0x22, 0x00, 0xe3, 0x80, 0x00, 0x00 139}; 140 141const byte imgSinSmall[] PROGMEM = { 142 0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x84, 0x80, 0x84, 0x80, 0x03, 0x00, 0x00, 0x00 143}; 144 145const byte imgTriSmall[] PROGMEM = { 146 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x88, 0x80, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 147}; 148 149const byte imgAcSmall[] PROGMEM = { 150 0x00, 0x00, 0x30, 0x00, 0x48, 0x00, 0x48, 0x00, 0x84, 0x80, 0x84, 0x80, 0x03, 0x00, 0x00, 0x00 151}; 152 153const byte imgDcSmall[] PROGMEM = { 154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x80, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00 155}; 156 157const byte imgOffSmall[] PROGMEM = { 158 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x14, 0x00, 0x08, 0x00, 0x14, 0x00, 0x22, 0x00, 0x00, 0x00 159}; 160 161//Total program memory space used by icons data: 1148 byte 162 163 164#endif 165
JXWG_Defs.h
c_cpp
Declarections section
1 2// This file is an integral part of the JX_WaveGenerator.ino and must be 3// distributed together with the main file to allow it to function correctly. 4// The same license of the main file applies to this file. 5// Janux 01/04/2021 on Turin, Italy. 6 7#ifndef JXWG_Defs 8#define JXWG_Defs 9 10#include <Wire.h> 11#include <EEPROM.h> 12 13//Encoder library, see https://www.arduino.cc/reference/en/libraries/simplerotary/ 14#include <SimpleRotary.h> // 15 16//adaptation of the library for SSD1306 to the SH1106 display, see https://github.com/wonho-maker/Adafruit_SH1106 17#include <Adafruit_SH1106.h> 18 19#define DEBUG 0 20#define OLED_RESET -1 21Adafruit_SH1106 display(OLED_RESET); 22 23#define PinA 5 //Encoder pin A 24#define PinB 4 //Encoder pin B 25#define PinS 3 //Encoder pin Switch 26SimpleRotary Encoder(PinA, PinB, PinS); 27 28//list of loop mode 29#define LOGARITHMIC 0 //+workmode 30#define SINGLEDIGIT 1 //+workmode 31#define SWEEP 2 //+workmode 32 33#define OPTIONS 3 //-submode of LOGARITHMIC and SINGLEDIGIT 34#define OPTMODE 4 //-submode of OPTIONS 35#define OPTWAVE 5 //-submode of OPTIONS 36#define OPTCOUP 6 //-submode of OPTIONS 37#define OPTSWEEP 7 //-submode of SWEEP 38#define SWEEPEDIT 8 //-submode of OPTSWEEP 39#define DIGITCHANGE 9 //-submode of SINGLEDIGIT and SWEEPEDIT 40 41#define PinCoupling 7 //Coupling mode pin (relay pin) 42 43//constants 44#define XPOS 28 45#define YPOS 21 46#define DELTAX 12 47#define DELTAY 4 48#define SMALL 1 49#define BIG 2 50#define CW 1 51#define CCW 2 52#define PUSH 1 53#define LONGPUSH 1 54 55//Num Freq digit 56#define MAXDIGIT 6 57 58//Wave type 59#define SQUARE 0 60#define SINE 1 61#define TRIANGLE 2 62 63//Coupling mode 64#define AC 0 65#define DC 1 66#define OFF 2 67 68//Sweep status 69#define STILL 0 70#define BREAK 1 71#define PAUSE 2 72 73//Symbols chars 74#define CURSOR 0x5F 75#define ARROW 0x10 76 77//AD9833 module Pin connection 78#define DDS_FSY 9 79#define DDS_CLK 10 80#define DDS_DAT 11 81 82//AD9833 Wave Type const 83#define wSquare 0x28 84#define wSine 0x00 85#define wTriangle 0x02 86 87//----------------------------------------------------------------------------- 88// Variables declarections 89//----------------------------------------------------------------------------- 90 91//Strings constants placed in flash memory save ram space 92const char str1[] PROGMEM = "JX WAVE GENERATOR"; // 18 byte 93const char str2[] PROGMEM = "WELCOME"; // 8 byte 94const char str3[] PROGMEM = "Hz"; // 3 byte 95const char str4[] PROGMEM = "ERROR!"; // 7 byte 96const char str5[] PROGMEM = "RESET"; // 6 byte //42 byte total 97const char* const string_table[] PROGMEM = {str1, str2, str3, str4, str5}; 98char buffer[18]; //local buffer for string, make sure this is large enough for the largest string it must hold 99 100long lFreq = 1000; //main frequency variable 101long lLastFreq = 1000; //used to save the current freq value in some situations 102long sweepUpPausedVal = 0; //value of sweep when pused 103long sweepDnPausedVal = 0; //value of sweep when pused 104long lSweep[3] = {20000, 0, 100}; //Sweep Hz default value MAX, MIN, STEP; 105byte sweepStatus = STILL; //current status of the sweep process 106const byte Wave[] = {wSquare, wSine, wTriangle}; //array for WaveType 107volatile boolean encoderPush = false; //var used in the routine called by interrupt 108char Freq[MAXDIGIT + 1]; //array for display frequency in 6 digit template "000000" 109byte mode = 0; //current loop mode 110byte idx = 0; //pointer to digit index (0 to 5) 111byte idy = 0; //same of idx in submode 112long cTime = 1; //screensaver counter 113 114//default startup preferences 115byte options[3] = {LOGARITHMIC, SINE, DC}; //mode, wavetype, couplingmode 116 117//define others macros 118#define _WorkMode options[0] 119#define _setWorkMode(x) options[0]=x 120#define _WaveType options[1] 121#define _setWaveType(x) options[1]=x 122#define _CouplingMode options[2] 123#define _setCouplingMode(x) options[2]=x 124#define _reservedbyte 0xFF 125#define _SweepMax lSweep[0] 126#define _SweepMin lSweep[1] 127#define _SweepStep lSweep[2] 128#define _Sweep(x) lSweep[x] 129#define _setSweep(x,f) lSweep[x]=f 130#define _setSweepMax(x) lSweep[0]=x 131#define _setSweepMin(x) lSweep[1]=x 132#define _setSweepStep(x) lSweep[2]=x 133 134//define short functions macros 135#define _clearIconsArea display.fillRect(XPOS - 11, YPOS + 18, 94, 24, BLACK) 136#define _displayErrMsg displayText(XPOS + 2, YPOS, strFromFlash(3), WHITE, BLACK, BIG); 137 138//define CONFIG consts & vars 139#define CONFIG_START 32 //EEPROM Memory start location 140#define CONFIG_VERSION "JXWG1" //Config version ID 141 142//define custom type struct 143typedef struct { 144 char version[6]; 145 byte workmode; 146 byte wavetype; 147 byte couplingmode; 148 byte reservedbyte; 149 long sweepmax; 150 long sweepmin; 151 long sweepstep; 152} config_type; 153 154//create new struct and load it with default value 155config_type CONFIG = { 156 CONFIG_VERSION, 157 _WorkMode, 158 _WaveType, 159 _CouplingMode, 160 _reservedbyte, 161 _SweepMax, 162 _SweepMin, 163 _SweepStep, 164}; 165 166//define processor reset function 167void(*ATmegaReset)(void) = 0; 168 169#endif 170
Downloadable files
EAGLE Schematics
EAGLE Schematics
Breadboard wiring
Display type updated
Breadboard wiring
EAGLE Schematics
EAGLE Schematics
Breadboard wiring
Display type updated
Breadboard wiring
Comments
Only logged in users can leave comments
janux
0 Followers
•0 Projects
Table of contents
Intro
14
0