├── COURSE KITS └── Kits Order.pdf ├── COURSE NOTES (PDF) ├── Concept S1 - Arduino.pdf ├── Concept S2 - VFO RTC.pdf ├── Concept S3 - EagleCAD.pdf ├── Concept S4 - ENC LCD.pdf ├── Concept S5 - VFH kit build.pdf ├── Concept S6 - SDR Design.pdf └── Concept S7 - SDR Kit build.pdf ├── COURSE SLIDES (PDF) ├── Concept S1 Arduino.pdf ├── Concept S2 VFO RTC.pdf ├── Concept S3 Eagle.pdf ├── Concept S4 ENC LCD.pdf ├── Concept S5 VFO kit.pdf ├── Concept S6 SDRX Design.pdf └── Concept S7 SDR kit.pdf ├── EAGLE ├── ARDUINO SHIELDS │ ├── SDR_40M1 │ │ ├── SDRX_40M1.brd │ │ ├── SDRX_40M1.sch │ │ └── eagle.epf │ └── VFO_RTC_IQ3 │ │ ├── VFO_RTC_IQ3.brd │ │ └── VFO_RTC_IQ3.sch └── INVAMP │ ├── eagle-book.lbr │ └── invamp.sch ├── HELP ├── HELP I2C LCD module.pdf ├── HELP MorseEnDecoder.pdf ├── HELP RTC.pdf ├── HELP Rotary Encoder.pdf ├── HELP SI5351 module.pdf ├── HELP Si5351 Library.pdf └── HELP Wire.h.pdf ├── LICENSE ├── My_Blink └── My_Blink.ino ├── My_Do_Nothing └── My_Do_Nothing.ino ├── My_LCD_Test └── My_LCD_Test.ino ├── My_Morse_KB └── My_Morse_KB.ino ├── My_RTC_LCD └── My_RTC_LCD.ino ├── My_RTC_Set └── My_RTC_Set.ino ├── My_SDR_40M └── My_SDR_40M.ino ├── My_SDR_40M_4 └── My_SDR_40M_4.ino ├── My_VFO_40M └── My_VFO_40M.ino ├── My_VFO_40M_4 └── My_VFO_40M_4.ino ├── My_VFO_KB └── My_VFO_KB.ino ├── My_VFO_ROTARY └── My_VFO_ROTARY.ino ├── My_VFO_ROTARY_LCD └── My_VFO_ROTARY_LCD.ino ├── My_WSPR_40M └── My_WSPR_40M.ino ├── README.md ├── WSPR_Symbol_Generator └── WSPR_Symbol_Generator.ino └── libraries ├── DS3231 ├── DS3231.cpp ├── DS3231.h ├── Examples │ ├── DS3231_oscillator_test │ │ └── DS3231_oscillator_test.ino │ ├── DS3231_set │ │ └── ds3231_set.ino │ └── DS3231_test │ │ └── ds3231_test.ino ├── Readme.txt └── keywords.txt ├── LiquidCrystal_I2C ├── LiquidCrystal_I2C.cpp ├── LiquidCrystal_I2C.h ├── LiquidCrystal_I2C.o ├── diff.txt ├── examples │ ├── CustomChars │ │ └── CustomChars.pde │ ├── HelloWorld │ │ ├── ARD_LCD_HCARDU0023_I2C_Hello_World_Example.ino │ │ └── ARD_LCD_HCARDU0023_I2C_Hello_World_Example.pde │ └── SerialDisplay │ │ └── SerialDisplay.pde └── keywords.txt ├── Morse_EnDecoder ├── Morse EnDecoder usage.rtfd │ └── TXT.rtf ├── MorseEnDecoder.cpp ├── MorseEnDecoder.h ├── examples │ ├── Morse_EnDecoder_barebones │ │ └── Morse_EnDecoder_barebones.ino │ └── Morse_EnDecoder_demo │ │ └── Morse_EnDecoder_demo.ino └── keywords.txt ├── Rotary ├── README.md ├── Rotary.cpp ├── Rotary.h ├── examples │ ├── Interrupt │ │ └── Interrupt.ino │ └── Polling │ │ └── Polling.ino └── keywords.txt ├── Si5351 ├── README.md ├── examples │ ├── si5351calibration │ │ └── si5351calibration.ino │ ├── si5351example │ │ └── si5351example.ino │ └── si5351phase │ │ └── si5351phase.ino ├── keywords.txt ├── licence.txt ├── si5351.cpp └── si5351.h └── TimerOne ├── TimerOne.cpp ├── TimerOne.h ├── examples ├── ISRBlink │ └── ISRBlink.pde └── ReadReciver │ ├── .svn │ ├── all-wcprops │ ├── dir-prop-base │ ├── entries │ └── text-base │ │ └── ReadReciver.pde.svn-base │ └── ReadReciver.pde └── keywords.txt /COURSE KITS/Kits Order.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE KITS/Kits Order.pdf -------------------------------------------------------------------------------- /COURSE NOTES (PDF)/Concept S1 - Arduino.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE NOTES (PDF)/Concept S1 - Arduino.pdf -------------------------------------------------------------------------------- /COURSE NOTES (PDF)/Concept S2 - VFO RTC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE NOTES (PDF)/Concept S2 - VFO RTC.pdf -------------------------------------------------------------------------------- /COURSE NOTES (PDF)/Concept S3 - EagleCAD.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE NOTES (PDF)/Concept S3 - EagleCAD.pdf -------------------------------------------------------------------------------- /COURSE NOTES (PDF)/Concept S4 - ENC LCD.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE NOTES (PDF)/Concept S4 - ENC LCD.pdf -------------------------------------------------------------------------------- /COURSE NOTES (PDF)/Concept S5 - VFH kit build.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE NOTES (PDF)/Concept S5 - VFH kit build.pdf -------------------------------------------------------------------------------- /COURSE NOTES (PDF)/Concept S6 - SDR Design.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE NOTES (PDF)/Concept S6 - SDR Design.pdf -------------------------------------------------------------------------------- /COURSE NOTES (PDF)/Concept S7 - SDR Kit build.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE NOTES (PDF)/Concept S7 - SDR Kit build.pdf -------------------------------------------------------------------------------- /COURSE SLIDES (PDF)/Concept S1 Arduino.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE SLIDES (PDF)/Concept S1 Arduino.pdf -------------------------------------------------------------------------------- /COURSE SLIDES (PDF)/Concept S2 VFO RTC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE SLIDES (PDF)/Concept S2 VFO RTC.pdf -------------------------------------------------------------------------------- /COURSE SLIDES (PDF)/Concept S3 Eagle.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE SLIDES (PDF)/Concept S3 Eagle.pdf -------------------------------------------------------------------------------- /COURSE SLIDES (PDF)/Concept S4 ENC LCD.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE SLIDES (PDF)/Concept S4 ENC LCD.pdf -------------------------------------------------------------------------------- /COURSE SLIDES (PDF)/Concept S5 VFO kit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE SLIDES (PDF)/Concept S5 VFO kit.pdf -------------------------------------------------------------------------------- /COURSE SLIDES (PDF)/Concept S6 SDRX Design.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE SLIDES (PDF)/Concept S6 SDRX Design.pdf -------------------------------------------------------------------------------- /COURSE SLIDES (PDF)/Concept S7 SDR kit.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/COURSE SLIDES (PDF)/Concept S7 SDR kit.pdf -------------------------------------------------------------------------------- /EAGLE/ARDUINO SHIELDS/SDR_40M1/eagle.epf: -------------------------------------------------------------------------------- 1 | [Eagle] 2 | Version="07 04 00" 3 | Platform="Mac OS X" 4 | Serial="7302F19AE5-LSR-WLM-1CL" 5 | Globals="Globals" 6 | Desktop="Desktop" 7 | 8 | [Globals] 9 | AutoSaveProject=1 10 | UsedLibrary="/Applications/EAGLE-7.3.0/lbr/74xx-us.lbr" 11 | UsedLibrary="/Applications/EAGLE-7.3.0/lbr/Arduino-M6KWH.lbr" 12 | UsedLibrary="/Applications/EAGLE-7.3.0/lbr/m6kwh.lbr" 13 | UsedLibrary="/Applications/EAGLE-7.3.0/lbr/pinhead.lbr" 14 | UsedLibrary="/Applications/EAGLE-7.3.0/lbr/rcl.lbr" 15 | UsedLibrary="/Applications/EAGLE-7.3.0/lbr/supply1.lbr" 16 | 17 | [Win_1] 18 | Type="Control Panel" 19 | Loc="480 302 1079 701" 20 | State=2 21 | Number=0 22 | 23 | [Desktop] 24 | Screen="1920 1080" 25 | Window="Win_1" 26 | -------------------------------------------------------------------------------- /HELP/HELP I2C LCD module.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/HELP/HELP I2C LCD module.pdf -------------------------------------------------------------------------------- /HELP/HELP MorseEnDecoder.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/HELP/HELP MorseEnDecoder.pdf -------------------------------------------------------------------------------- /HELP/HELP RTC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/HELP/HELP RTC.pdf -------------------------------------------------------------------------------- /HELP/HELP Rotary Encoder.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/HELP/HELP Rotary Encoder.pdf -------------------------------------------------------------------------------- /HELP/HELP SI5351 module.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/HELP/HELP SI5351 module.pdf -------------------------------------------------------------------------------- /HELP/HELP Si5351 Library.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/HELP/HELP Si5351 Library.pdf -------------------------------------------------------------------------------- /HELP/HELP Wire.h.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/HELP/HELP Wire.h.pdf -------------------------------------------------------------------------------- /My_Blink/My_Blink.ino: -------------------------------------------------------------------------------- 1 | // My_Blink 2 | // flashes a LED on pin 13 3 | 4 | // pin number 5 | #define LED 13 6 | 7 | // the setup routine runs once when you upload (->) the sketch 8 | void setup() { 9 | // initialise the digital pin 13 as an output 10 | pinMode(LED, OUTPUT); 11 | } 12 | 13 | // the loop runs over and over again, forever 14 | void loop() { 15 | digitalWrite(LED, HIGH); // turn the LED on (HIGH voltage level) 16 | delay(1000); // wait for 1 second (1000ms) 17 | digitalWrite(LED, LOW); // turn the LED off (LOW voltage leve) 18 | delay(1000); // wait for 1 second 19 | } 20 | 21 | -------------------------------------------------------------------------------- /My_Do_Nothing/My_Do_Nothing.ino: -------------------------------------------------------------------------------- 1 | // My_Do_Nothing is a sketch outline, the sketch does nothing 2 | 3 | // example of an included library 4 | #include 5 | 6 | // example of a constant define 7 | #define LED 13 8 | 9 | // setup function, executed once on upload (->) 10 | void setup() { 11 | 12 | } 13 | 14 | // loop function, executed over and over 15 | void loop() { 16 | 17 | c = myFunction(a, b); // call a user function 18 | 19 | } 20 | 21 | // your own function, called by loop() 22 | int myFunction(int a, int b) { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /My_LCD_Test/My_LCD_Test.ino: -------------------------------------------------------------------------------- 1 | // My_LCD_Test 2 | // displays a test message on the LCD 3 | 4 | // include libraries for I2C comms and LCD driver 5 | #include 6 | #include 7 | 8 | // LCD I2C address, cols, rows 9 | #define LCDADDR 0x27 10 | #define LCDCOLS 16 11 | #define LCDROWS 2 12 | 13 | // create an LCD object "lcd" 14 | LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); 15 | 16 | // setup runs once on upload 17 | void setup() { 18 | // initialise the LCD & switch the backlight on 19 | lcd.init(); 20 | lcd.backlight(); 21 | 22 | // move the cursor to col, row and output text 23 | lcd.setCursor(3, 0); 24 | lcd.print(" Concept "); 25 | 26 | // wait 2 sec (2000ms) 27 | delay(2000); 28 | 29 | // move the cursor to col, row and output text 30 | lcd.setCursor(3, 1); 31 | lcd.print(" Program "); 32 | } 33 | 34 | // loop does nothing, but must be here 35 | void loop() { 36 | 37 | } 38 | -------------------------------------------------------------------------------- /My_Morse_KB/My_Morse_KB.ino: -------------------------------------------------------------------------------- 1 | // My_Morse_KB is a morse morse sender with KB input 2 | // active piezo buzzer on pin 7 3 | 4 | // include the special llibrary to generate morse dit/dah 5 | #include "MorseEnDecoder.h" 6 | 7 | // define a constant for words per minute 8 | #define WPM 5 9 | 10 | // define a constant for the buzzer pin 11 | #define BUZZER 7 12 | 13 | // create a morseOut object 14 | morseEncoder morseOut(BUZZER); 15 | 16 | // setup runs once on upload 17 | void setup() { 18 | // set BUZZER pin as an output 19 | pinMode(BUZZER, OUTPUT); 20 | 21 | // start serial comms with Arduino IDE monitor window, over USB 22 | Serial.begin(9600); 23 | while (!Serial); // wait for USB connection 24 | 25 | // call morseOUT object to set the morse speed 26 | morseOut.setspeed(WPM); 27 | } 28 | 29 | // loop repeats over and over 30 | void loop() { 31 | // char variable to hold a character of input 32 | char text; 33 | 34 | // set morseOut encode mode 35 | morseOut.encode(); 36 | 37 | // if characters in the input buffer & morse object available 38 | if (Serial.available() && morseOut.available()) { 39 | text = Serial.read(); // read a character 40 | Serial.write(text); // echo it 41 | morseOut.write(text); // send out as morse 42 | } 43 | } 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /My_RTC_LCD/My_RTC_LCD.ino: -------------------------------------------------------------------------------- 1 | // My_RTC_LCD 2 | // display time on LCD I2C 3 | 4 | // CONNECTIONS 5 | // RTC DS1307 or DS3231 6 | // SCL = A5 7 | // SDA = A4 8 | // I2C address 0x57 9 | // ------ 10 | // display LCD I2C 11 | // o A5 SCL 12 | // o A4 SDA 13 | // o +5 14 | // o GND 15 | // I2C address 0x27 16 | 17 | // libraries 18 | #include "Wire.h" 19 | #include "LiquidCrystal_I2C.h" 20 | 21 | // RTC I2C address 22 | #define RTCADDR 0x68 23 | 24 | // LCD 25 | #define LCDADDR 0x27 26 | #define LCDCOLS 16 27 | #define LCDROWS 2 28 | 29 | // LCD object 30 | LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); 31 | 32 | // RTC time and date 33 | byte Second, prevSecond, Minute, Hour, DoW, Date, prevDate, Month, Year; 34 | 35 | void setup() { 36 | // initialise the wire library for I2C comms 37 | Wire.begin(); 38 | 39 | // init LCD & backlight on 40 | lcd.init(); 41 | lcd.backlight(); 42 | 43 | getRTC(); 44 | dispDate(0, 0); // display date & time 45 | dispTime(4, 1); 46 | prevSecond = Second; // save current second & date 47 | prevDate = Date; 48 | } 49 | 50 | void loop() { 51 | getRTC(); // get time 52 | if (Second != prevSecond) { 53 | dispTime(4, 1); // display it, if changed 54 | prevSecond = Second; 55 | } 56 | if (Date != prevDate) { 57 | dispDate(0, 0); 58 | prevDate = Date; 59 | } 60 | } 61 | 62 | // get time from RTC, convert bcd to decimal 63 | void getRTC() { 64 | // Reset the RTC register pointer 65 | Wire.beginTransmission(RTCADDR); 66 | byte zero = 0x00; 67 | Wire.write(zero); 68 | Wire.endTransmission(); 69 | 70 | // request 7 bytes from the RTC address 71 | Wire.requestFrom(RTCADDR, 7); 72 | 73 | // get the time data 74 | Second = bcdToDec(Wire.read()); // 0 - 59 75 | Minute = bcdToDec(Wire.read()); // 0 - 59 76 | Hour = bcdToDec(Wire.read() & 0b111111); // mask 12/24 bit 77 | DoW = bcdToDec(Wire.read()); //0 - 6 = Sunday - Saturday 78 | Date = bcdToDec(Wire.read()); // 1 - 31 79 | Month = bcdToDec(Wire.read()); // 0 = jan 80 | Year = bcdToDec(Wire.read()); // 20xx 81 | } 82 | 83 | // Convert binary coded decimal to normal decimal numbers 84 | byte bcdToDec(byte val) { 85 | return ( (val / 16 * 10) + (val % 16) ); 86 | } 87 | 88 | // display date and time 89 | void dispDate(byte c, byte r) { 90 | lcd.clear(); 91 | 92 | lcd.setCursor(c, r); 93 | switch (DoW) { 94 | case 1: 95 | lcd.print("Mon"); 96 | break; 97 | case 2: 98 | lcd.print("Tue"); 99 | break; 100 | case 3: 101 | lcd.print("Wed"); 102 | break; 103 | case 4: 104 | lcd.print("Thu"); 105 | break; 106 | case 5: 107 | lcd.print("Fri"); 108 | break; 109 | case 6: 110 | lcd.print("Sat"); 111 | break; 112 | case 7: 113 | lcd.print("Sun"); 114 | break; 115 | } 116 | 117 | lcd.print(" "); 118 | lcd.print(Date); 119 | 120 | lcd.print(" "); 121 | switch (Month) 122 | { 123 | case 1: 124 | lcd.print("Jan"); 125 | break; 126 | case 2: 127 | lcd.print("Feb"); 128 | break; 129 | case 3: 130 | lcd.print("Mar"); 131 | break; 132 | case 4: 133 | lcd.print("Apr"); 134 | break; 135 | case 5: 136 | lcd.print("May"); 137 | break; 138 | case 6: 139 | lcd.print("Jun"); 140 | break; 141 | case 7: 142 | lcd.print("Jul"); 143 | break; 144 | case 8: 145 | lcd.print("Aug"); 146 | break; 147 | case 9: 148 | lcd.print("Sep"); 149 | break; 150 | case 10: 151 | lcd.print("Oct"); 152 | break; 153 | case 11: 154 | lcd.print("Nov"); 155 | break; 156 | case 12: 157 | lcd.print("Dec"); 158 | break; 159 | } 160 | lcd.print(" "); 161 | lcd.print("20"); 162 | lcd.print(Year); 163 | } 164 | 165 | void dispTime(byte c, byte r) { 166 | lcd.setCursor(c, r); 167 | if (Hour < 10) 168 | lcd.print("0"); 169 | lcd.print(Hour); 170 | lcd.print(":"); 171 | if (Minute < 10) 172 | lcd.print("0"); 173 | lcd.print(Minute); 174 | lcd.print(":"); 175 | if (Second < 10) 176 | lcd.print("0"); 177 | lcd.print(Second); 178 | } 179 | 180 | -------------------------------------------------------------------------------- /My_RTC_Set/My_RTC_Set.ino: -------------------------------------------------------------------------------- 1 | // My_RTC set 2 | // enter YYMMDDwHHMMSS on Monitor, w = week day 3 | // note 1 = mon. 01 = Jan 4 | // hit ENTER exactly on the time you want to set 5 | 6 | #include "Wire.h" 7 | #include "DS3231.h" 8 | #include "LiquidCrystal_I2C.h" 9 | 10 | // LCD address, cols, rows 11 | #define LCDADDR 0x27 12 | #define LCDCOLS 16 13 | #define LCDROWS 2 14 | 15 | // RTC address 16 | #define RTCADDR 0x68 17 | 18 | // LCD object 19 | LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); 20 | 21 | // rtc object 22 | DS3231 rtc; 23 | 24 | // RTC time and date 25 | byte Second, prevSecond, Minute, Hour, DoW, Date, prevDate, Month, Year; 26 | 27 | bool gotString; 28 | 29 | void setup() { 30 | // Start the serial port 31 | Serial.begin(9600); 32 | 33 | // init LCD & backlight on 34 | lcd.init(); 35 | lcd.backlight(); 36 | 37 | // Start the I2C interface 38 | Wire.begin(); 39 | 40 | dispMsg(0, 0, "Enter time: "); 41 | dispMsg(0, 1, "\"YYMMDDwHHMMSS\""); 42 | 43 | gotString = false; 44 | } 45 | 46 | void loop() { 47 | char inString[20] = ""; 48 | byte j = 0; 49 | 50 | while (!gotString) { 51 | if (Serial.available()) { 52 | inString[j] = Serial.read(); 53 | 54 | if (inString[j] == '\n') { 55 | gotString = true; 56 | 57 | Serial.println(inString); 58 | 59 | // convert ASCII codes to bytes 60 | Year = ((byte)inString[0] - 48) * 10 + (byte)inString[1] - 48; 61 | Month = ((byte)inString[2] - 48) * 10 + (byte)inString[3] - 48; 62 | Date = ((byte)inString[4] - 48) * 10 + (byte)inString[5] - 48; 63 | DoW = ((byte)inString[6] - 48); 64 | Hour = ((byte)inString[7] - 48) * 10 + (byte)inString[8] - 48; 65 | Minute = ((byte)inString[9] - 48) * 10 + (byte)inString[10] - 48; 66 | Second = ((byte)inString[11] - 48) * 10 + (byte)inString[12] - 48; 67 | 68 | rtc.setYear(Year); 69 | rtc.setMonth(Month); 70 | rtc.setDate(Date); 71 | rtc.setDoW(DoW); 72 | rtc.setHour(Hour); 73 | rtc.setMinute(Minute); 74 | rtc.setSecond(Second); 75 | } 76 | j += 1; 77 | } 78 | } 79 | 80 | getRTC(); // get time 81 | 82 | if(Second != prevSecond) { 83 | dispTime(4, 1); // display it, if changed 84 | prevSecond = Second; 85 | } 86 | if(Date != prevDate) { 87 | dispDate(0, 0); 88 | prevDate = Date; 89 | } 90 | } 91 | 92 | // get time from RTC, convert bcd to decimal 93 | void getRTC() { 94 | // Reset the RTC register pointer 95 | Wire.beginTransmission(RTCADDR); 96 | byte zero = 0x00; 97 | Wire.write(zero); 98 | Wire.endTransmission(); 99 | 100 | // request 7 bytes from the RTC address 101 | Wire.requestFrom(RTCADDR, 7); 102 | 103 | // get the time data 104 | Second = bcdToDec(Wire.read()); // 0 - 59 105 | Minute = bcdToDec(Wire.read()); // 0 - 59 106 | Hour = bcdToDec(Wire.read() & 0b111111); //mask 12/24 bit 107 | DoW = bcdToDec(Wire.read()); //0 - 6 = Sunday - Saturday 108 | Date = bcdToDec(Wire.read()); // 1 - 31 109 | Month = bcdToDec(Wire.read()); // 0 = jan 110 | Year = bcdToDec(Wire.read()); // 20xx 111 | } 112 | 113 | // Convert binary coded decimal to normal decimal numbers 114 | byte bcdToDec(byte val) { 115 | return ( (val / 16 * 10) + (val % 16) ); 116 | } 117 | 118 | // display char msg at col c, row r 119 | void dispMsg(uint8_t c, uint8_t r, char *m) { 120 | lcd.setCursor(c, r); 121 | lcd.print(m); 122 | } 123 | 124 | // display date and time 125 | void dispDate(byte c, byte r) { 126 | lcd.clear(); 127 | 128 | lcd.setCursor(c, r); 129 | switch (DoW) { 130 | case 1: 131 | lcd.print("Mon"); 132 | break; 133 | case 2: 134 | lcd.print("Tue"); 135 | break; 136 | case 3: 137 | lcd.print("Wed"); 138 | break; 139 | case 4: 140 | lcd.print("Thu"); 141 | break; 142 | case 5: 143 | lcd.print("Fri"); 144 | break; 145 | case 6: 146 | lcd.print("Sat"); 147 | break; 148 | case 7: 149 | lcd.print("Sun"); 150 | break; 151 | } 152 | 153 | lcd.print(" "); 154 | lcd.print(Date); 155 | 156 | lcd.print(" "); 157 | switch (Month) 158 | { 159 | case 1: 160 | lcd.print("Jan"); 161 | break; 162 | case 2: 163 | lcd.print("Feb"); 164 | break; 165 | case 3: 166 | lcd.print("Mar"); 167 | break; 168 | case 4: 169 | lcd.print("Apr"); 170 | break; 171 | case 5: 172 | lcd.print("May"); 173 | break; 174 | case 6: 175 | lcd.print("Jun"); 176 | break; 177 | case 7: 178 | lcd.print("Jul"); 179 | break; 180 | case 8: 181 | lcd.print("Aug"); 182 | break; 183 | case 9: 184 | lcd.print("Sep"); 185 | break; 186 | case 10: 187 | lcd.print("Oct"); 188 | break; 189 | case 11: 190 | lcd.print("Nov"); 191 | break; 192 | case 12: 193 | lcd.print("Dec"); 194 | break; 195 | } 196 | lcd.print(" "); 197 | lcd.print("20"); 198 | lcd.print(Year); 199 | } 200 | 201 | void dispTime(byte c, byte r) { 202 | lcd.setCursor(c, r); 203 | if (Hour < 10) 204 | lcd.print("0"); 205 | lcd.print(Hour); 206 | lcd.print(":"); 207 | if (Minute < 10) 208 | lcd.print("0"); 209 | lcd.print(Minute); 210 | lcd.print(":"); 211 | if (Second < 10) 212 | lcd.print("0"); 213 | lcd.print(Second); 214 | } 215 | 216 | -------------------------------------------------------------------------------- /My_SDR_40M/My_SDR_40M.ino: -------------------------------------------------------------------------------- 1 | // My_SDR_40M 2 | // for 40m, with TX/RX control and bandplan display 3 | // Si5351 I2C bus 4 | // SDA = A4 5 | // SCL = A5 6 | // LCD I2C bus 7 | // SDA = A4 8 | // SCL = A5 9 | // rotary encoder pins 10 | // DT = 2 11 | // CLK = 3 12 | // SW = 4 13 | 14 | // I2C, Si5351, LCD and rotary Encoder libraries 15 | #include "Wire.h" 16 | #include "si5351.h" 17 | #include "LiquidCrystal_I2C.h" 18 | #include "Rotary.h" 19 | 20 | // LCD 21 | #define LCDADDR 0x27 22 | #define LCDCOLS 16 23 | #define LCDROWS 2 24 | 25 | // rotary Encoder pins 2 & 3 (DT & CLK), step change pin 4 (SW) 26 | #define DT 2 27 | #define CLK 3 28 | #define SW 4 29 | 30 | // Rx & Tx signals 31 | #define RX 13 32 | #define TX 12 33 | #define KEY 8 34 | 35 | // number of band plans 36 | #define PLANS 12 37 | 38 | // dds object 39 | Si5351 dds; 40 | 41 | // LCD object 42 | LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); 43 | 44 | // rotary Encoder object 45 | Rotary rot = Rotary(DT, CLK); 46 | 47 | // define plan structure 48 | typedef struct { 49 | uint32_t lower; 50 | uint32_t upper; 51 | char alloc[30]; 52 | } plan; 53 | 54 | // band plan array contents cHz/cHz/Text 55 | plan bp[PLANS] = { 56 | {700000000, 700100000, "CW QRSS 7000.7 "}, 57 | {700100000, 703990000, "CW QRP 7030 "}, 58 | {703990000, 704690000, "NB WSPR 7040 "}, 59 | {704600000, 704990000, "NB Auto "}, 60 | {704990000, 705290000, "ALL Auto "}, 61 | {705290000, 705990000, "ALL Digital "}, 62 | {705990000, 706990000, "ALL "}, 63 | {706990000, 707990000, "ALL HELL 7077 "}, 64 | {707990000, 709990000, "ALL SSB QRP 7090"}, 65 | {709990000, 712990000, "ALL EMGCY 7110 "}, 66 | {712990000, 717490000, "ALL SSB CON 7165"}, 67 | {717490000, 720010000, "ALL DX INTNL "}, 68 | }; 69 | 70 | uint32_t freq = 700000000; // cHz, start frequency 71 | uint32_t step = 10000; // cHz, init 100Hz step 72 | 73 | void setup() { 74 | // init LCD & backlight on 75 | lcd.init(); 76 | lcd.backlight(); 77 | 78 | // init dds si5351 module, "0" = default 25MHz XTAL 79 | dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); 80 | 81 | // set 8mA output drive (max possible) 82 | dds.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA); 83 | 84 | // can insert Si5351 calibration here if required 85 | 86 | // enable SDR output CLK2, disable CLK0 & 1 87 | dds.output_enable(SI5351_CLK0, 0); 88 | dds.output_enable(SI5351_CLK1, 0); 89 | dds.output_enable(SI5351_CLK2, 1); 90 | 91 | // encoder, button, RX, TX, band and KEY pins 92 | pinMode(DT, INPUT_PULLUP); 93 | pinMode(CLK, INPUT_PULLUP); 94 | pinMode(SW, INPUT_PULLUP); 95 | 96 | pinMode(RX, OUTPUT); 97 | pinMode(TX, OUTPUT); 98 | pinMode(KEY, INPUT_PULLUP); 99 | 100 | xmit(digitalRead(KEY)); // set RX|TX, KEY = LOW is TX 101 | 102 | freqOut(freq); // cHz, output freq 103 | 104 | dispFreq(4, 0, freq, 1); // display freq kHz col 4 row 0 105 | dispMsg(0, 1, scanPlan()); // display band plan col 0 row 1 106 | } 107 | 108 | void loop() { 109 | // tune? 110 | if (tune()) { 111 | freqOut(freq); // output freq 112 | dispFreq(4, 0, freq, 1); // update freq display 113 | dispMsg(0, 1, scanPlan()); // update band plan display 114 | } 115 | 116 | // step? 117 | if (button()) { 118 | dispStep(step, 14, 0); 119 | } 120 | xmit(digitalRead(KEY)); // RX|TX 121 | } 122 | 123 | // tune? 124 | bool tune() { 125 | unsigned char dir; // tuning direction CW/CCW 126 | 127 | dir = rot.process(); // read encoder 128 | if (dir != DIR_NONE) { // turned? 129 | if (dir == DIR_CW && (freq < bp[PLANS - 1].upper - step)) freq += step; 130 | if (dir == DIR_CCW && (freq >= bp[0].lower + step)) freq -= step; 131 | return true; 132 | } 133 | return false; 134 | } 135 | 136 | // change step? 137 | bool button() { 138 | if (digitalRead(SW) == LOW) { // button pressed? 139 | while (!digitalRead(SW)); // wait for release 140 | if (step == 1000000) step = 10000; // reset 141 | else step = step * 10; // or increment by x10 142 | return true; 143 | } 144 | return false; 145 | } 146 | 147 | // search for band info 148 | char *scanPlan() { 149 | for (int i = 0; i < 15; i++) { 150 | if (freq >= bp[i].lower && freq < bp[i].upper) // find plan 151 | return bp[i].alloc; // return when found 152 | } 153 | } 154 | 155 | // Output Freq for SDR, on CLK2, f cHz 156 | void freqOut(uint32_t f) { 157 | dds.set_freq(f * 4ULL, 0ULL, SI5351_CLK2); 158 | } 159 | 160 | // Tx/Rx KEY HIGH = RX, LOW = TX 161 | void xmit(bool x) 162 | { 163 | if (x == LOW) // TX 164 | { 165 | dispMsg(0, 0, "TX "); 166 | digitalWrite(RX, HIGH); // Rx off 167 | digitalWrite(TX, LOW); // Tx on 168 | } 169 | else 170 | { 171 | dispMsg(0, 0, "SDR"); 172 | digitalWrite(RX, LOW); // Rx on 173 | digitalWrite(TX, HIGH); // Tx off 174 | } 175 | } 176 | 177 | // display char msg at col c, row r 178 | void dispMsg(uint8_t c, uint8_t r, char *m) { 179 | lcd.setCursor(c, r); 180 | lcd.print(m); 181 | } 182 | 183 | // display freq in kHz at col c, row r, f cHz, d decimal places 184 | void dispFreq(uint8_t c, uint8_t r, uint32_t f, uint8_t d) { 185 | lcd.setCursor(c, r); 186 | lcd.print((float)f / 100000, d); // convert to float & kHz 187 | lcd.print("kHz "); 188 | } 189 | 190 | // display step 191 | void dispStep(uint32_t s, byte c, byte r) 192 | { 193 | switch (s) // display step 194 | { 195 | case 10000: 196 | dispMsg(c, r, " "); 197 | break; 198 | case 100000: 199 | dispMsg(c, r, " +"); 200 | break; 201 | case 1000000: 202 | dispMsg(c, r, "++"); 203 | break; 204 | } 205 | } 206 | 207 | -------------------------------------------------------------------------------- /My_SDR_40M_4/My_SDR_40M_4.ino: -------------------------------------------------------------------------------- 1 | // My_SDR_40M_4 2 | // 20 x 4 display 3 | // for 40m, with TX/RX control and bandplan display 4 | // Si5351 I2C bus 5 | // SDA = A4 6 | // SCL = A5 7 | // LCD I2C bus 8 | // SDA = A4 9 | // SCL = A5 10 | // rotary encoder pins§ §§§ 11 | // DT = 2 12 | // CLK = 3 13 | // SW = 4 14 | 15 | // I2C, Si5351, LCD and rotary Encoder libraries 16 | #include "Wire.h" 17 | #include "si5351.h" 18 | #include "LiquidCrystal_I2C.h" 19 | #include "Rotary.h" 20 | 21 | // RTC I2C address 22 | #define RTCADDR 0x68 23 | 24 | // LCD 25 | #define LCDADDR 0x27 26 | #define LCDCOLS 20 27 | #define LCDROWS 4 28 | 29 | // rotary Encoder pins 2 & 3 (DT & CLK), step change pin 4 (SW) 30 | #define DT 2 31 | #define CLK 3 32 | #define SW 4 33 | 34 | // Rx & Tx signals 35 | #define RX 13 36 | #define TX 12 37 | #define KEY 8 38 | 39 | // number of band plans 40 | #define PLANS 12 41 | 42 | // dds object 43 | Si5351 dds; 44 | 45 | // LCD object 46 | LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); 47 | 48 | // rotary Encoder object 49 | Rotary rot = Rotary(DT, CLK); 50 | 51 | // define plan structure 52 | typedef struct { 53 | uint32_t lower; 54 | uint32_t upper; 55 | char alloc[30]; 56 | } plan; 57 | 58 | // band plan array contents cHz/cHz/Text 59 | plan bp[PLANS] = { 60 | {700000000, 700100000, "CW QRSS 7000.7 "}, 61 | {700100000, 703990000, "CW PSK31 QRP 7030"}, 62 | {703990000, 704690000, "NB WSPR 7040 "}, 63 | {704600000, 704990000, "NB Auto "}, 64 | {704990000, 705290000, "All Auto "}, 65 | {705290000, 705990000, "All Digital "}, 66 | {705990000, 706990000, "All "}, 67 | {706990000, 707990000, "All HELL 7077 "}, 68 | {707990000, 709990000, "All SSB QRP 7090 "}, 69 | {709990000, 712990000, "All EMGCY 7110 "}, 70 | {712990000, 717490000, "All SSB CON 7165 "}, 71 | {717490000, 720010000, "All DX Intnl "}, 72 | }; 73 | 74 | // start freq & step 75 | uint32_t freq = 700000000; // cHz, start frequency 76 | uint32_t step = 10000; // cHz, init 100Hz step 77 | 78 | // RTC time and date 79 | byte Second, prevSecond, Minute, Hour, DoW, Date, prevDate, Month, Year; 80 | 81 | void setup() { 82 | // init LCD & backlight on 83 | lcd.init(); 84 | lcd.backlight(); 85 | 86 | // init dds si5351 module, "0" = default 25MHz XTAL 87 | dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); 88 | 89 | // set 8mA output drive (max possible) 90 | dds.drive_strength(SI5351_CLK2, SI5351_DRIVE_8MA); 91 | 92 | // can insert Si5351 calibration here if required 93 | 94 | // enable SDR output CLK2, disable CLK0 & 1 95 | dds.output_enable(SI5351_CLK0, 0); 96 | dds.output_enable(SI5351_CLK1, 0); 97 | dds.output_enable(SI5351_CLK2, 1); 98 | 99 | // encoder, button, RX, TX, band and KEY pins 100 | pinMode(DT, INPUT_PULLUP); 101 | pinMode(CLK, INPUT_PULLUP); 102 | pinMode(SW, INPUT_PULLUP); 103 | 104 | pinMode(RX, OUTPUT); 105 | pinMode(TX, OUTPUT); 106 | pinMode(KEY, INPUT_PULLUP); 107 | 108 | xmit(digitalRead(KEY)); // set RX|TX, KEY = LOW is TX 109 | getRTC(); // get time 110 | 111 | freqOut(freq); // cHz, output freq 112 | 113 | dispDate(0, 0); 114 | dispTime(12, 0); 115 | dispFreq(6, 2, freq, 1); // display freq kHz col 4 row 2 116 | dispMsg(0, 3, scanPlan()); // display band plan col 0 row 3 117 | } 118 | 119 | void loop() { 120 | getRTC(); // get time 121 | if (Date != prevDate) { 122 | dispDate(0, 0); 123 | prevDate = Date; 124 | } 125 | if (Second != prevSecond) { 126 | dispTime(12, 0); // display it, if changed 127 | prevSecond = Second; 128 | } 129 | 130 | // tune? 131 | if (tune()) { 132 | freqOut(freq); // output freq 133 | dispFreq(6, 2, freq, 1); // update freq display 134 | dispMsg(0, 3, scanPlan()); // update band plan display 135 | } 136 | 137 | // step? 138 | if (button()) { 139 | dispStep(step, 17, 2); 140 | } 141 | xmit(digitalRead(KEY)); // RX|TX 142 | } 143 | 144 | // tune? 145 | bool tune() { 146 | unsigned char dir; // tuning direction CW/CCW 147 | 148 | dir = rot.process(); // read encoder 149 | if (dir != DIR_NONE) { // turned? 150 | if (dir == DIR_CW && (freq < bp[PLANS - 1].upper - step)) freq += step; 151 | if (dir == DIR_CCW && (freq >= bp[0].lower + step)) freq -= step; 152 | return true; 153 | } 154 | return false; 155 | } 156 | 157 | // change step? 158 | bool button() { 159 | if (digitalRead(SW) == LOW) { // button pressed? 160 | while (!digitalRead(SW)); // wait for release 161 | if (step == 1000000) step = 10000; // reset 162 | else step = step * 10; // or increment by x10 163 | return true; 164 | } 165 | return false; 166 | } 167 | 168 | // search for band info 169 | char *scanPlan() { 170 | for (int i = 0; i < 15; i++) { 171 | if (freq >= bp[i].lower && freq < bp[i].upper) // find plan 172 | return bp[i].alloc; // return when found 173 | } 174 | } 175 | 176 | // Output Freq for SDR, on CLK2, f cHz 177 | void freqOut(uint32_t f) { 178 | dds.set_freq(f * 4ULL, 0ULL, SI5351_CLK2); 179 | } 180 | 181 | // Tx/Rx KEY HIGH = RX, LOW = TX 182 | void xmit(bool x) 183 | { 184 | if (x == LOW) // TX 185 | { 186 | dispMsg(0, 2, "TX "); 187 | digitalWrite(RX, HIGH); // Rx off 188 | digitalWrite(TX, LOW); // Tx on 189 | } 190 | else 191 | { 192 | dispMsg(0, 2, "SDR"); 193 | digitalWrite(RX, LOW); // Rx on 194 | digitalWrite(TX, HIGH); // Tx off 195 | } 196 | } 197 | 198 | // display char msg at col c, row r 199 | void dispMsg(uint8_t c, uint8_t r, char *m) { 200 | lcd.setCursor(c, r); 201 | lcd.print(m); 202 | } 203 | 204 | // get time from RTC, convert bcd to decimal 205 | void getRTC() { 206 | // Reset the RTC register pointer 207 | Wire.beginTransmission(RTCADDR); 208 | byte zero = 0x00; 209 | Wire.write(zero); 210 | Wire.endTransmission(); 211 | 212 | // request 7 bytes from the RTC address 213 | Wire.requestFrom(RTCADDR, 7); 214 | 215 | // get the time data 216 | Second = bcdToDec(Wire.read()); // 0 - 59 217 | Minute = bcdToDec(Wire.read()); // 0 - 59 218 | Hour = bcdToDec(Wire.read() & 0b111111); // mask 12/24 bit 219 | DoW = bcdToDec(Wire.read()); //0 - 6 = Sunday - Saturday 220 | Date = bcdToDec(Wire.read()); // 1 - 31 221 | Month = bcdToDec(Wire.read()); // 0 = jan 222 | Year = bcdToDec(Wire.read()); // 20xx 223 | } 224 | 225 | // Convert binary coded decimal to normal decimal numbers 226 | byte bcdToDec(byte val) { 227 | return ( (val / 16 * 10) + (val % 16) ); 228 | } 229 | 230 | // display freq in kHz at col c, row r, f cHz, d decimal places 231 | void dispFreq(uint8_t c, uint8_t r, uint32_t f, uint8_t d) { 232 | lcd.setCursor(c, r); 233 | lcd.print((float)f / 100000, d); // convert to float & kHz 234 | lcd.print("kHz "); 235 | } 236 | 237 | // display step 238 | void dispStep(uint32_t s, byte c, byte r) 239 | { 240 | switch (s) // display step 241 | { 242 | case 10000: 243 | dispMsg(c, r, " "); 244 | break; 245 | case 100000: 246 | dispMsg(c, r, " +"); 247 | break; 248 | case 1000000: 249 | dispMsg(c, r, "++"); 250 | break; 251 | } 252 | } 253 | 254 | 255 | // display date and time 256 | void dispDate(byte c, byte r) { 257 | lcd.setCursor(c, r); 258 | switch (DoW) { 259 | case 1: 260 | lcd.print("Mon"); 261 | break; 262 | case 2: 263 | lcd.print("Tue"); 264 | break; 265 | case 3: 266 | lcd.print("Wed"); 267 | break; 268 | case 4: 269 | lcd.print("Thu"); 270 | break; 271 | case 5: 272 | lcd.print("Fri"); 273 | break; 274 | case 6: 275 | lcd.print("Sat"); 276 | break; 277 | case 7: 278 | lcd.print("Sun"); 279 | break; 280 | } 281 | 282 | lcd.print(" "); 283 | lcd.print(Date); 284 | 285 | lcd.print(" "); 286 | switch (Month) 287 | { 288 | case 1: 289 | lcd.print("Jan"); 290 | break; 291 | case 2: 292 | lcd.print("Feb"); 293 | break; 294 | case 3: 295 | lcd.print("Mar"); 296 | break; 297 | case 4: 298 | lcd.print("Apr"); 299 | break; 300 | case 5: 301 | lcd.print("May"); 302 | break; 303 | case 6: 304 | lcd.print("Jun"); 305 | break; 306 | case 7: 307 | lcd.print("Jul"); 308 | break; 309 | case 8: 310 | lcd.print("Aug"); 311 | break; 312 | case 9: 313 | lcd.print("Sep"); 314 | break; 315 | case 10: 316 | lcd.print("Oct"); 317 | break; 318 | case 11: 319 | lcd.print("Nov"); 320 | break; 321 | case 12: 322 | lcd.print("Dec"); 323 | break; 324 | } 325 | } 326 | 327 | void dispTime(byte c, byte r) { 328 | lcd.setCursor(c, r); 329 | if (Hour < 10) 330 | lcd.print("0"); 331 | lcd.print(Hour); 332 | lcd.print(":"); 333 | if (Minute < 10) 334 | lcd.print("0"); 335 | lcd.print(Minute); 336 | lcd.print(":"); 337 | if (Second < 10) 338 | lcd.print("0"); 339 | lcd.print(Second); 340 | } 341 | 342 | -------------------------------------------------------------------------------- /My_VFO_40M/My_VFO_40M.ino: -------------------------------------------------------------------------------- 1 | // My_VFO_40M 2 | // for 40m, with TX/RX control and bandplan display 3 | // Si5351 I2C bus 4 | // SDA = A4 5 | // SCL = A5 6 | // LCD I2C bus 7 | // SDA = A4 8 | // SCL = A5 9 | // rotary encoder pins 10 | // DT = 2 11 | // CLK = 3 12 | // SW = 4 13 | 14 | // I2C, Si5351, LCD and rotary Encoder libraries 15 | #include "Wire.h" 16 | #include "si5351.h" 17 | #include "LiquidCrystal_I2C.h" 18 | #include "Rotary.h" 19 | 20 | // LCD 21 | #define LCDADDR 0x27 22 | #define LCDCOLS 16 23 | #define LCDROWS 2 24 | 25 | // rotary Encoder pins 2 & 3 (DT & CLK), step change pin 4 (SW) 26 | #define DT 2 27 | #define CLK 3 28 | #define SW 4 29 | 30 | // Rx & Tx signals 31 | #define RX 13 32 | #define TX 12 33 | #define KEY 8 34 | 35 | // number of band plans 36 | #define PLANS 12 37 | 38 | // dds object 39 | Si5351 dds; 40 | 41 | // LCD object 42 | LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); 43 | 44 | // rotary Encoder object 45 | Rotary rot = Rotary(DT, CLK); 46 | 47 | // define plan structure 48 | typedef struct { 49 | uint32_t lower; 50 | uint32_t upper; 51 | char alloc[30]; 52 | } plan; 53 | 54 | // band plan array contents cHz/cHz/Text 55 | plan bp[PLANS] = { 56 | {700000000, 700100000, "CW QRSS 7000.7 "}, 57 | {700100000, 703990000, "CW QRP 7030 "}, 58 | {703990000, 704690000, "NB WSPR 7040 "}, 59 | {704600000, 704990000, "NB Auto "}, 60 | {704990000, 705290000, "ALL Auto "}, 61 | {705290000, 705990000, "ALL Digital "}, 62 | {705990000, 706990000, "ALL "}, 63 | {706990000, 707990000, "ALL HELL 7077 "}, 64 | {707990000, 709990000, "ALL SSB QRP 7090"}, 65 | {709990000, 712990000, "ALL EMGCY 7110 "}, 66 | {712990000, 717490000, "ALL SSB CON 7165"}, 67 | {717490000, 720010000, "ALL DX INTNL "}, 68 | }; 69 | 70 | uint32_t freq = 700000000; // start frequency cHz 71 | uint32_t step = 10000; // init 100Hz step 72 | 73 | void setup() { 74 | // init LCD & backlight on 75 | lcd.init(); 76 | lcd.backlight(); 77 | 78 | // init dds si5351 module, "0" = default 25MHz XTAL 79 | dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); 80 | 81 | // set 8mA output drive (max possible) 82 | dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); 83 | 84 | // can insert Si5351 calibration here if required 85 | 86 | // enable VFO output CLK0, disable CLK1 & 2 87 | dds.output_enable(SI5351_CLK0, 1); 88 | dds.output_enable(SI5351_CLK1, 0); 89 | dds.output_enable(SI5351_CLK2, 0); 90 | 91 | // encoder, button, RX, TX, band and KEY pins 92 | pinMode(DT, INPUT_PULLUP); 93 | pinMode(CLK, INPUT_PULLUP); 94 | pinMode(SW, INPUT_PULLUP); 95 | 96 | pinMode(RX, OUTPUT); 97 | pinMode(TX, OUTPUT); 98 | pinMode(KEY, INPUT_PULLUP); 99 | 100 | xmit(digitalRead(KEY)); // set RX|TX, KEY = LOW is TX 101 | 102 | freqOut(freq); // cHz, output freq 103 | 104 | dispFreq(4, 0, freq, 1); // display freq kHz col 4 row 0 105 | dispMsg(0, 1, scanPlan()); // display band plan col 0 row 1 106 | } 107 | 108 | void loop() { 109 | // tune? 110 | if (tune()) { 111 | freqOut(freq); // output freq 112 | dispFreq(4, 0, freq, 1); // update freq display 113 | dispMsg(0, 1, scanPlan()); // update band plan display 114 | } 115 | 116 | // step? 117 | if (button()) { 118 | dispStep(step, 14, 0); 119 | } 120 | 121 | xmit(digitalRead(KEY)); // RX|TX 122 | } 123 | 124 | // tune? 125 | bool tune() { 126 | unsigned char dir; // tuning direction CW/CCW 127 | 128 | dir = rot.process(); // read encoder 129 | if (dir != DIR_NONE) { // turned? 130 | if (dir == DIR_CW && (freq < bp[PLANS - 1].upper - step)) freq += step; 131 | if (dir == DIR_CCW && (freq >= bp[0].lower + step)) freq -= step; 132 | return true; 133 | } 134 | return false; 135 | } 136 | 137 | // change step? 138 | bool button() { 139 | if (digitalRead(SW) == LOW) { // button pressed? 140 | while (!digitalRead(SW)); // wait for release 141 | if (step == 1000000) step = 10000; // reset 142 | else step = step * 10; // or increment by x10 143 | return true; 144 | } 145 | return false; 146 | } 147 | 148 | // search for band info 149 | char *scanPlan() { 150 | for (int i = 0; i < 15; i++) { 151 | if (freq >= bp[i].lower && freq < bp[i].upper) // find plan 152 | return bp[i].alloc; // return when found 153 | } 154 | } 155 | // Output Freq for VFO, on CLK0, f cHz 156 | void freqOut(uint32_t f) { 157 | dds.set_freq(f, 0ULL, SI5351_CLK0); 158 | } 159 | 160 | // Tx/Rx KEY HIGH = RX, LOW = TX 161 | void xmit(bool x) 162 | { 163 | if (x == LOW) // TX 164 | { 165 | dispMsg(0, 0, "TX "); 166 | digitalWrite(RX, HIGH); // RX off 167 | digitalWrite(TX, LOW); // TX on 168 | } 169 | else 170 | { 171 | dispMsg(0, 0, "VFO"); 172 | digitalWrite(RX, LOW); // RX on 173 | digitalWrite(TX, HIGH); // TX off 174 | } 175 | } 176 | 177 | // display char msg at col c, row r 178 | void dispMsg(uint8_t c, uint8_t r, char *m) { 179 | lcd.setCursor(c, r); 180 | lcd.print(m); 181 | } 182 | 183 | // display freq in kHz at col c, row r, f cHz, d decimal places 184 | void dispFreq(uint8_t c, uint8_t r, uint32_t f, uint8_t d) { 185 | lcd.setCursor(c, r); 186 | lcd.print((float)f / 100000, d); // convert to float & kHz 187 | lcd.print("kHz "); 188 | } 189 | 190 | // display step 191 | void dispStep(uint32_t s, byte c, byte r) 192 | { 193 | switch (s) // display step 194 | { 195 | case 10000: 196 | dispMsg(c, r, " "); 197 | break; 198 | case 100000: 199 | dispMsg(c, r, " +"); 200 | break; 201 | case 1000000: 202 | dispMsg(c, r, "++"); 203 | break; 204 | } 205 | } 206 | 207 | -------------------------------------------------------------------------------- /My_VFO_40M_4/My_VFO_40M_4.ino: -------------------------------------------------------------------------------- 1 | // My_VFO_40M_4 2 | // 20 x 4 display 3 | // for 40m, with TX/RX control and bandplan display 4 | // Si5351 I2C bus 5 | // SDA = A4 6 | // SCL = A5 7 | // LCD I2C bus 8 | // SDA = A4 9 | // SCL = A5 10 | // rotary encoder pins§ 11 | // DT = 2 12 | // CLK = 3 13 | // SW = 4 14 | 15 | // I2C, Si5351, LCD and rotary Encoder libraries 16 | #include "Wire.h" 17 | #include "si5351.h" 18 | #include "LiquidCrystal_I2C.h" 19 | #include "Rotary.h" 20 | 21 | // RTC I2C address 22 | #define RTCADDR 0x68 23 | 24 | // LCD 25 | #define LCDADDR 0x27 26 | #define LCDCOLS 20 27 | #define LCDROWS 4 28 | 29 | // rotary Encoder pins 2 & 3 (DT & CLK), step change pin 4 (SW) 30 | #define DT 2 31 | #define CLK 3 32 | #define SW 4 33 | 34 | // Rx & Tx signals 35 | #define RX 13 36 | #define TX 12 37 | #define KEY 8 38 | 39 | // number of band plans 40 | #define PLANS 12 41 | 42 | // dds object 43 | Si5351 dds; 44 | 45 | // LCD object 46 | LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); 47 | 48 | // rotary Encoder object 49 | Rotary rot = Rotary(DT, CLK); 50 | 51 | // define plan structure 52 | typedef struct { 53 | uint32_t lower; 54 | uint32_t upper; 55 | char alloc[30]; 56 | } plan; 57 | 58 | // band plan array contents cHz/cHz/Text 59 | plan bp[PLANS] = { 60 | {700000000, 700100000, "CW QRSS 7000.7 "}, 61 | {700100000, 703990000, "CW PSK31 QRP 7030"}, 62 | {703990000, 704690000, "NB WSPR 7040 "}, 63 | {704600000, 704990000, "NB Auto "}, 64 | {704990000, 705290000, "All Auto "}, 65 | {705290000, 705990000, "All Digital "}, 66 | {705990000, 706990000, "All "}, 67 | {706990000, 707990000, "All HELL 7077 "}, 68 | {707990000, 709990000, "All SSB QRP 7090 "}, 69 | {709990000, 712990000, "All EMGCY 7110 "}, 70 | {712990000, 717490000, "All SSB CON 7165 "}, 71 | {717490000, 720010000, "All DX Intnl "}, 72 | }; 73 | 74 | // start freq & step 75 | uint32_t freq = 700000000; // cHz, start frequency 76 | uint32_t step = 10000; // cHz, init 100Hz step 77 | 78 | // RTC time and date 79 | byte Second, prevSecond, Minute, Hour, DoW, Date, prevDate, Month, Year; 80 | 81 | void setup() { 82 | // init LCD & backlight on 83 | lcd.init(); 84 | lcd.backlight(); 85 | 86 | // init dds si5351 module, "0" = default 25MHz XTAL 87 | dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); 88 | 89 | // set 8mA output drive (max possible) 90 | dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); 91 | 92 | // can insert Si5351 calibration here if required 93 | 94 | // enable VFO output CLK0, disable CLK1 & 2 95 | dds.output_enable(SI5351_CLK0, 1); 96 | dds.output_enable(SI5351_CLK1, 0); 97 | dds.output_enable(SI5351_CLK2, 0); 98 | 99 | // encoder, button, RX, TX, band and KEY pins 100 | pinMode(DT, INPUT_PULLUP); 101 | pinMode(CLK, INPUT_PULLUP); 102 | pinMode(SW, INPUT_PULLUP); 103 | 104 | pinMode(RX, OUTPUT); 105 | pinMode(TX, OUTPUT); 106 | pinMode(KEY, INPUT_PULLUP); 107 | 108 | xmit(digitalRead(KEY)); // set RX|TX, KEY = LOW is TX 109 | getRTC(); // get time 110 | 111 | freqOut(freq); // cHz, output freq 112 | 113 | dispDate(0, 0); 114 | dispTime(12, 0); 115 | dispFreq(6, 2, freq, 1); // display freq kHz col 4 row 2 116 | dispMsg(0, 3, scanPlan()); // display band plan col 0 row 3 117 | } 118 | 119 | void loop() { 120 | getRTC(); // get time 121 | if (Date != prevDate) { 122 | dispDate(0, 0); 123 | prevDate = Date; 124 | } 125 | if (Second != prevSecond) { 126 | dispTime(12, 0); // display it, if changed 127 | prevSecond = Second; 128 | } 129 | 130 | // tune? 131 | if (tune()) { 132 | freqOut(freq); // output freq 133 | dispFreq(6, 2, freq, 1); // update freq display 134 | dispMsg(0, 3, scanPlan()); // update band plan display 135 | } 136 | 137 | // step? 138 | if (button()) { 139 | dispStep(step, 17, 2); 140 | } 141 | xmit(digitalRead(KEY)); // RX|TX 142 | } 143 | 144 | // tune? 145 | bool tune() { 146 | unsigned char dir; // tuning direction CW/CCW 147 | 148 | dir = rot.process(); // read encoder 149 | if (dir != DIR_NONE) { // turned? 150 | if (dir == DIR_CW && (freq < bp[PLANS - 1].upper - step)) freq += step; 151 | if (dir == DIR_CCW && (freq >= bp[0].lower + step)) freq -= step; 152 | return true; 153 | } 154 | return false; 155 | } 156 | 157 | // change step? 158 | bool button() { 159 | if (digitalRead(SW) == LOW) { // button pressed? 160 | while (!digitalRead(SW)); // wait for release 161 | if (step == 1000000) step = 10000; // reset 162 | else step = step * 10; // or increment by x10 163 | return true; 164 | } 165 | return false; 166 | } 167 | 168 | // search for band info 169 | char *scanPlan() { 170 | for (int i = 0; i < 15; i++) { 171 | if (freq >= bp[i].lower && freq < bp[i].upper) // find plan 172 | return bp[i].alloc; // return when found 173 | } 174 | } 175 | 176 | // Output Freq for VFO, on CLK0, f cHz 177 | void freqOut(uint32_t f) { 178 | dds.set_freq(f, 0ULL, SI5351_CLK0); 179 | } 180 | 181 | // Tx/Rx KEY HIGH = RX, LOW = TX 182 | void xmit(bool x) 183 | { 184 | if (x == LOW) // TX 185 | { 186 | dispMsg(0, 2, "TX "); 187 | digitalWrite(RX, HIGH); // Rx off 188 | digitalWrite(TX, LOW); // Tx on 189 | } 190 | else 191 | { 192 | dispMsg(0, 2, "VFO"); 193 | digitalWrite(RX, LOW); // Rx on 194 | digitalWrite(TX, HIGH); // Tx off 195 | } 196 | } 197 | 198 | // display char msg at col c, row r 199 | void dispMsg(uint8_t c, uint8_t r, char *m) { 200 | lcd.setCursor(c, r); 201 | lcd.print(m); 202 | } 203 | 204 | // get time from RTC, convert bcd to decimal 205 | void getRTC() { 206 | // Reset the RTC register pointer 207 | Wire.beginTransmission(RTCADDR); 208 | byte zero = 0x00; 209 | Wire.write(zero); 210 | Wire.endTransmission(); 211 | 212 | // request 7 bytes from the RTC address 213 | Wire.requestFrom(RTCADDR, 7); 214 | 215 | // get the time data 216 | Second = bcdToDec(Wire.read()); // 0 - 59 217 | Minute = bcdToDec(Wire.read()); // 0 - 59 218 | Hour = bcdToDec(Wire.read() & 0b111111); // mask 12/24 bit 219 | DoW = bcdToDec(Wire.read()); //0 - 6 = Sunday - Saturday 220 | Date = bcdToDec(Wire.read()); // 1 - 31 221 | Month = bcdToDec(Wire.read()); // 0 = jan 222 | Year = bcdToDec(Wire.read()); // 20xx 223 | } 224 | 225 | // Convert binary coded decimal to normal decimal numbers 226 | byte bcdToDec(byte val) { 227 | return ( (val / 16 * 10) + (val % 16) ); 228 | } 229 | 230 | // display freq in kHz at col c, row r, f cHz, d decimal places 231 | void dispFreq(uint8_t c, uint8_t r, uint32_t f, uint8_t d) { 232 | lcd.setCursor(c, r); 233 | lcd.print((float)f / 100000, d); // convert to float & kHz 234 | lcd.print("kHz "); 235 | } 236 | 237 | // display step 238 | void dispStep(uint32_t s, byte c, byte r) 239 | { 240 | switch (s) // display step 241 | { 242 | case 10000: 243 | dispMsg(c, r, " "); 244 | break; 245 | case 100000: 246 | dispMsg(c, r, " +"); 247 | break; 248 | case 1000000: 249 | dispMsg(c, r, "++"); 250 | break; 251 | } 252 | } 253 | 254 | 255 | // display date and time 256 | void dispDate(byte c, byte r) { 257 | lcd.setCursor(c, r); 258 | switch (DoW) { 259 | case 1: 260 | lcd.print("Mon"); 261 | break; 262 | case 2: 263 | lcd.print("Tue"); 264 | break; 265 | case 3: 266 | lcd.print("Wed"); 267 | break; 268 | case 4: 269 | lcd.print("Thu"); 270 | break; 271 | case 5: 272 | lcd.print("Fri"); 273 | break; 274 | case 6: 275 | lcd.print("Sat"); 276 | break; 277 | case 7: 278 | lcd.print("Sun"); 279 | break; 280 | } 281 | 282 | lcd.print(" "); 283 | lcd.print(Date); 284 | 285 | lcd.print(" "); 286 | switch (Month) 287 | { 288 | case 1: 289 | lcd.print("Jan"); 290 | break; 291 | case 2: 292 | lcd.print("Feb"); 293 | break; 294 | case 3: 295 | lcd.print("Mar"); 296 | break; 297 | case 4: 298 | lcd.print("Apr"); 299 | break; 300 | case 5: 301 | lcd.print("May"); 302 | break; 303 | case 6: 304 | lcd.print("Jun"); 305 | break; 306 | case 7: 307 | lcd.print("Jul"); 308 | break; 309 | case 8: 310 | lcd.print("Aug"); 311 | break; 312 | case 9: 313 | lcd.print("Sep"); 314 | break; 315 | case 10: 316 | lcd.print("Oct"); 317 | break; 318 | case 11: 319 | lcd.print("Nov"); 320 | break; 321 | case 12: 322 | lcd.print("Dec"); 323 | break; 324 | } 325 | } 326 | 327 | void dispTime(byte c, byte r) { 328 | lcd.setCursor(c, r); 329 | if (Hour < 10) 330 | lcd.print("0"); 331 | lcd.print(Hour); 332 | lcd.print(":"); 333 | if (Minute < 10) 334 | lcd.print("0"); 335 | lcd.print(Minute); 336 | lcd.print(":"); 337 | if (Second < 10) 338 | lcd.print("0"); 339 | lcd.print(Second); 340 | } 341 | 342 | -------------------------------------------------------------------------------- /My_VFO_KB/My_VFO_KB.ino: -------------------------------------------------------------------------------- 1 | // My_VFO_KB is a keyboard input/screen display VFO 2 | // Starter kit VFO using Si5351 module, freq in cHz 3 | // Si5351 I2C bus 4 | // SDA = A4 5 | // SCL = A5 6 | 7 | // I2C and Si5351 Libraries 8 | #include "Wire.h" 9 | #include "si5351.h" 10 | 11 | // create dds object 12 | Si5351 dds; 13 | 14 | // start frequency (cHz) 15 | uint32_t freq = 700000000; // 7MHz 16 | uint32_t prevFreq = freq; 17 | 18 | // setup runs once on upload 19 | void setup(){ 20 | // start serial (monitor "NEWLINE" & 9600 baud) 21 | Serial.begin(9600); 22 | 23 | // init dds si5351 module, "0" = default 25MHz XTAL 24 | dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); 25 | 26 | // set 8mA output drive 27 | dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); 28 | 29 | // enable VFO output CLK0, disable CLK1 & 2 30 | dds.output_enable(SI5351_CLK0, 1); 31 | dds.output_enable(SI5351_CLK1, 0); 32 | dds.output_enable(SI5351_CLK2, 0); 33 | 34 | freqOut(freq); // output freq 35 | dispFreq(freq); // display freq in Hz 36 | } 37 | 38 | void loop(){ 39 | freq = getIn(); // get input freq cHz 40 | 41 | // new freq? 42 | if(freq != prevFreq) 43 | { 44 | freqOut(freq); // output freq 45 | dispFreq(freq); // display in Hz 46 | prevFreq = freq; // remember as previous freq 47 | } 48 | } 49 | 50 | // freq output in cHz on CLK0 51 | void freqOut(uint32_t freq){ 52 | dds.set_freq(freq, 0, SI5351_CLK0); // cHz 53 | } 54 | 55 | // get input Hz, return cHz 56 | uint32_t getIn(){ 57 | uint32_t in; 58 | 59 | while(Serial.available() > 0) // flush buffer 60 | Serial.read(); 61 | 62 | while(Serial.available() == 0) // wait for input 63 | in = Serial.parseInt(); // read input in Hz and parse to integer 64 | 65 | return in * 100UL; // return in cHz 66 | } 67 | 68 | // display frequency on monitor 69 | void dispFreq(uint32_t f){ 70 | // display freq 71 | Serial.print("My_VFO = "); 72 | Serial.print((float)f / 100, 0); // convert to float & display in Hz 73 | Serial.println(" Hz"); 74 | } 75 | -------------------------------------------------------------------------------- /My_VFO_ROTARY/My_VFO_ROTARY.ino: -------------------------------------------------------------------------------- 1 | // My_VFO_ROTARY controls the freq by rotary encoder, freq display on monitor 2 | // button changes band 3 | // Si5351 I2C bus 4 | // SDA = A4 5 | // SCL = A5 6 | // LCD I2C bus 7 | // SDA = A4 8 | // SCL = A5 9 | // rotary encoder pins 10 | // DT = 2 11 | // CLK = 3 12 | // SW = 4 13 | 14 | // I2C, Si5351, LCD and rotary Encoder libraries 15 | #include "Wire.h" 16 | #include "si5351.h" 17 | #include "Rotary.h" 18 | 19 | // tuning freq STEPS (cHz), 100Hz 20 | #define STEPS 10000 21 | 22 | // rotary Encoder pins 2 & 3 (DT & CLK), band change pin 4 (SW) 23 | #define DT 2 24 | #define CLK 3 25 | #define SW 4 26 | 27 | // dds object 28 | Si5351 dds; 29 | 30 | // rotary Encoder object 31 | Rotary rot = Rotary(DT, CLK); 32 | 33 | // start frequencies (cHz), band names 34 | uint32_t freqStart[3] = { 35 | 710000000, 1014000000, 1410000000 36 | }; 37 | 38 | // band, freq (cHz) 39 | byte band = 0; 40 | uint32_t freq = freqStart[band]; 41 | 42 | void setup() { 43 | Serial.begin(9600); 44 | 45 | // init dds si5351 module, "0" = default 25MHz XTAL 46 | dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); 47 | 48 | // set 8mA output drive 49 | dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); 50 | 51 | // enable VFO output CLK0, disable CLK1 & 2 52 | dds.output_enable(SI5351_CLK0, 1); 53 | dds.output_enable(SI5351_CLK1, 0); 54 | dds.output_enable(SI5351_CLK2, 0); 55 | 56 | // encoder, button, RX, TX, band and XMIT pins 57 | pinMode(DT, INPUT_PULLUP); 58 | pinMode(CLK, INPUT_PULLUP); 59 | pinMode(SW, INPUT_PULLUP); 60 | 61 | freqOut(freq); // output freq 62 | dispFreq(freq); // display freq 63 | } 64 | 65 | void loop() { 66 | // tune? 67 | if (tune()) { 68 | freqOut(freq); 69 | dispFreq(freq); 70 | } 71 | 72 | // band? 73 | if (button()) { 74 | freq = freqStart[band]; 75 | freqOut(freq); 76 | dispFreq(freq); 77 | } 78 | } 79 | 80 | // tune? 81 | bool tune() { 82 | unsigned char dir; // tuning direction CW/CCW 83 | 84 | // turned? 85 | dir = rot.process(); // read encoder 86 | if (dir != DIR_NONE) { // turned? 87 | if (dir == DIR_CW) freq += STEPS; // increment freq +/- STEPS 88 | if (dir == DIR_CCW) freq -= STEPS; 89 | return true; 90 | } 91 | return false; 92 | } 93 | 94 | // band? 95 | bool button() { 96 | if (digitalRead(SW) == LOW) { // button pressed? 97 | while (!digitalRead(SW)); // wait for release 98 | if (band == 2) band = 0; // loop 99 | else band++; 100 | return true; 101 | } 102 | return false; 103 | } 104 | 105 | // frequency (in cHz) for VFO, on CLK0 106 | void freqOut(uint32_t f) { 107 | dds.set_freq(f, 0ULL, SI5351_CLK0); // converted to cHz 108 | } 109 | 110 | // display freq in cHz 111 | void dispFreq(uint32_t f) { 112 | Serial.print("My VFO = "); 113 | Serial.print((float)f / 100000, 1); // convert to float for print function 114 | Serial.println(" kHz"); 115 | } 116 | -------------------------------------------------------------------------------- /My_VFO_ROTARY_LCD/My_VFO_ROTARY_LCD.ino: -------------------------------------------------------------------------------- 1 | // My_VFO_ROTARY_LCD controls the freq by rotary encoder, freq display on LCD 2 | // button changes band 3 | // Si5351 I2C bus 4 | // SDA = A4 5 | // SCL = A5 6 | // LCD I2C bus 7 | // SDA = A4 8 | // SCL = A5 9 | // rotary encoder pins 10 | // DT = 2 11 | // CLK = 3 12 | // SW = 4 13 | 14 | // I2C, Si5351, LCD and rotary Encoder libraries 15 | #include "Wire.h" 16 | #include "si5351.h" 17 | #include "Rotary.h" 18 | #include "LiquidCrystal_I2C.h" 19 | 20 | // tuning freq STEPS (cHz), 100Hz 21 | #define STEPS 10000 22 | 23 | // rotary Encoder pins 2 & 3 (DT & CLK), band change pin 4 (SW) 24 | #define DT 2 25 | #define CLK 3 26 | #define SW 4 27 | 28 | // dds object 29 | Si5351 dds; 30 | 31 | // rotary Encoder object 32 | Rotary rot = Rotary(DT, CLK); 33 | 34 | // lcd object 35 | LiquidCrystal_I2C lcd(0x27, 16, 2); 36 | 37 | // start frequencies (cHz), band names 38 | uint32_t freqStart[3] = { 39 | 710000000, 1014000000, 1410000000}; 40 | 41 | // band, freq (cHz) 42 | byte band = 0; 43 | uint32_t freq = freqStart[band]; 44 | 45 | void setup() { 46 | 47 | // init LCD & backlight on 48 | lcd.init(); 49 | lcd.backlight(); 50 | 51 | // init dds si5351 module, "0" = default 25MHz XTAL 52 | dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); 53 | 54 | // set 8mA output drive 55 | dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); 56 | 57 | // enable VFO output CLK0, disable CLK1 & 2 58 | dds.output_enable(SI5351_CLK0, 1); 59 | dds.output_enable(SI5351_CLK1, 0); 60 | dds.output_enable(SI5351_CLK2, 0); 61 | 62 | // encoder, button, RX, TX, band and XMIT pins 63 | pinMode(DT, INPUT_PULLUP); 64 | pinMode(CLK, INPUT_PULLUP); 65 | pinMode(SW, INPUT_PULLUP); 66 | 67 | freqOut(freq); // output freq 68 | dispFreq(freq); // display freq 69 | } 70 | 71 | void loop() { 72 | // tune? 73 | if (tune()) { 74 | freqOut(freq); 75 | dispFreq(freq); 76 | } 77 | 78 | // band? 79 | if (button()) { 80 | freq = freqStart[band]; 81 | freqOut(freq); 82 | dispFreq(freq); 83 | } 84 | } 85 | 86 | // tune? 87 | bool tune() { 88 | unsigned char dir; // tuning direction CW/CCW 89 | 90 | // turned? 91 | dir = rot.process(); // read encoder 92 | if (dir != DIR_NONE) { // turned? 93 | if (dir == DIR_CW) freq += STEPS; // increment freq +/- STEPS 94 | if (dir == DIR_CCW) freq -= STEPS; 95 | return true; 96 | } 97 | return false; 98 | } 99 | 100 | // band? 101 | bool button() { 102 | if (digitalRead(SW) == LOW) { // button pressed? 103 | while (!digitalRead(SW)); // wait for release 104 | if (band == 2) band = 0; // loop 105 | else band++; 106 | return true; 107 | } 108 | return false; 109 | } 110 | 111 | // frequency (in cHz) for VFO, on CLK0 112 | void freqOut(uint32_t f) { 113 | dds.set_freq(f, 0ULL, SI5351_CLK0); // converted to cHz 114 | } 115 | 116 | // display freq in cHz 117 | void dispFreq(uint32_t f) { 118 | lcd.setCursor(0, 0); 119 | lcd.print("VFO "); 120 | lcd.setCursor(4, 0); 121 | lcd.print((float)f / 100000, 1); // convert to float for print function 122 | lcd.setCursor(13, 0); 123 | lcd.print("kHz"); 124 | } 125 | -------------------------------------------------------------------------------- /My_WSPR_40M/My_WSPR_40M.ino: -------------------------------------------------------------------------------- 1 | // My_WSPR_40M 2 | // transmits WSPR on 40m 3 | // use WSPR_Symbol_Generator sketch to make symbol tone table 4 | // insert symbols and msgtxt below 5 | // it is hard coded here for msgtxt " M6KWH IO92 20", note leading space, 3rd char must be number 6 | // tuning in 10Hz steps 7 | // output on CLK0, VFO_RTC_IQ shield "G0" pin 8 | // Interface by I2C bus to RTC, init RTC time before use 9 | 10 | 11 | // CONNECTIONS 12 | // RTC 13 | // SCL = A5 14 | // SDA = A4 15 | // I2C address 0x68 16 | // ----- 17 | // DDS I2C SI5351 18 | // SCL = A5 19 | // SDA = A4 20 | // I2C address 0x60 21 | // ------ 22 | // display I2C LCD 16 * 2 23 | // o A5 SCL (y) 24 | // o A4 SDA (or) 25 | // o +5 (r) 26 | // o GND (bwn) 27 | // I2C address 0x27 28 | // ----- 29 | // encoder KY-040 30 | // o D2 DT (y) 31 | // o D3 CLK (g) 32 | // o D4 SW (or) 33 | // o +5 (r) 34 | // o GND (bwn) 35 | // ----- 36 | 37 | // libraries 38 | #include "Wire.h" 39 | #include "si5351.h" 40 | #include "LiquidCrystal_I2C.h" 41 | #include "Rotary.h" 42 | #include "TimerOne.h" 43 | 44 | // RTC I2C address 45 | #define RTCADDR 0x68 46 | 47 | // LCD 48 | #define LCDADDR 0x27 49 | #define LCDCOLS 16 50 | #define LCDROWS 2 51 | 52 | // rotary Encoder pins 2 & 3 (DT & CLK), button 4 (SW) 53 | #define DT 2 54 | #define CLK 3 55 | #define SW 4 56 | 57 | // dds object 58 | Si5351 dds; 59 | 60 | // LCD object 61 | LiquidCrystal_I2C lcd(LCDADDR, LCDCOLS, LCDROWS); 62 | 63 | // rotary sncoder object 64 | Rotary rot = Rotary(DT, CLK); 65 | 66 | uint8_t tone_ptr = 0; // Pointer to the current symbol 67 | 68 | // start freq (mid band) cHz, step 10Hz, WSPR Tx is 704000000 - 704020000, 69 | // note standard is dial 70386000 + 150000 = 704010000 or "100" in WSPR.app software 70 | uint32_t freq = 704010000; 71 | uint32_t steps = 1000; 72 | 73 | // ====================== insert your message text & symbol 74 | char msgtxt[] = {" M6KWH IO92 20 "}; 75 | // symbols - use WSSPR Symbol Generator program to create/paste here 76 | uint32_t WSPR_DATA[162] = 77 | { 3, 1, 2, 0, 0, 0, 2, 2, 1, 2, 0, 2, 3, 1, 3, 0, 2, 2, 1, 2, 0, 3, 0, 1, 3, 1, 1, 0, 2, 0, 0, 2, 78 | 0, 0, 1, 0, 0, 1, 0, 1, 2, 0, 0, 0, 0, 2, 1, 2, 1, 3, 0, 0, 1, 3, 0, 1, 2, 0, 0, 1, 3, 2, 1, 0, 79 | 2, 2, 0, 3, 3, 2, 3, 2, 3, 0, 3, 0, 3, 2, 0, 3, 2, 0, 1, 2, 1, 3, 0, 0, 0, 3, 1, 0, 1, 0, 1, 0, 80 | 2, 2, 3, 0, 0, 0, 0, 0, 1, 0, 2, 1, 0, 2, 1, 3, 1, 2, 1, 1, 0, 0, 3, 3, 2, 1, 2, 0, 0, 1, 1, 1, 81 | 2, 2, 2, 0, 0, 3, 0, 3, 2, 0, 3, 1, 2, 2, 2, 0, 2, 0, 2, 3, 1, 0, 1, 0, 1, 1, 2, 0, 0, 3, 1, 0, 82 | 2, 0 83 | }; 84 | // ====================== 85 | 86 | // RTC time seconds, minutes, hours 87 | byte sec, mns, hr; 88 | 89 | // repeat interval 2,4,6,8 min 90 | uint8_t repeat; 91 | 92 | void setup() 93 | { 94 | // initialise the wire library for I2C comms 95 | Wire.begin(); 96 | 97 | // init LCD & backlight on 98 | lcd.init(); 99 | lcd.backlight(); 100 | 101 | // init dds si5351 module, "0" = default 25MHz XTAL 102 | dds.init(SI5351_CRYSTAL_LOAD_8PF, 0); 103 | 104 | // put calibration here... 105 | 106 | // set 8mA output drive 107 | dds.drive_strength(SI5351_CLK0, SI5351_DRIVE_8MA); 108 | 109 | // disable all outputs 110 | dds.output_enable(SI5351_CLK0, 0); 111 | dds.output_enable(SI5351_CLK1, 0); 112 | dds.output_enable(SI5351_CLK2, 0); 113 | 114 | // encoder, button 115 | pinMode(DT, INPUT_PULLUP); 116 | pinMode(CLK, INPUT_PULLUP); 117 | pinMode(SW, INPUT_PULLUP); 118 | 119 | repeat = 2; // init to send every 2 mins 120 | 121 | dispMsg(0, 0, "WSPR "); 122 | dispFreq(5, 0, freq, 2); // display freq b 123 | dispMsg(1, 1, " min "); 124 | dispNum(0, 1, repeat); 125 | } 126 | 127 | void loop() 128 | { 129 | if (tune()) { 130 | dispFreq(5, 0, freq, 2); // display freq; 131 | } 132 | 133 | if (event()) { 134 | dispMsg(1, 1, " min"); 135 | dispNum(0, 1, repeat); 136 | } 137 | 138 | getRTC(); // read RTC, display time 139 | dispTime(8, 1); 140 | 141 | // send WSPR now? 142 | if (mns % repeat == 0 && sec == 0) 143 | { 144 | // display message 145 | dispMsg(0, 0, msgtxt); 146 | dispMsg(8, 1, " TX "); // show transmit 147 | 148 | txWspr(); // transmit on freq 149 | 150 | // restore display 151 | dispMsg(0, 0, "WSPR "); 152 | dispFreq(5, 0, freq, 2); // display freq 153 | dispMsg(1, 1, " min "); 154 | dispNum(0, 1, repeat); 155 | } 156 | } 157 | 158 | // tune freq 159 | bool tune() 160 | { 161 | unsigned char dir; // tuning direction CW/CCW 162 | 163 | dir = rot.process(); // read encoder 164 | if (dir != DIR_NONE) // turned? 165 | { 166 | if (dir == DIR_CW) freq += steps;; // increment freq 167 | if (dir == DIR_CCW) freq -= steps; 168 | return true; 169 | } 170 | return false; 171 | } 172 | 173 | // set event time 2,4,6,8 min 174 | bool event() 175 | { 176 | if (digitalRead(SW) == LOW) 177 | { 178 | while (!digitalRead(SW)); // wait for release 179 | if (repeat == 8) repeat = 2; 180 | else repeat += 2; 181 | return true; 182 | } 183 | return false; 184 | } 185 | 186 | 187 | // get time from RTC, convert bcd to decimal 188 | void getRTC() 189 | { 190 | // Reset the register pointer 191 | Wire.beginTransmission(RTCADDR); 192 | byte zero = 0x00; 193 | Wire.write(zero); 194 | Wire.endTransmission(); 195 | 196 | // request 1st 3 bytes from the RTC address 197 | Wire.requestFrom(RTCADDR, 3); 198 | 199 | // get the s/m/h time data 200 | sec = bcdToDec(Wire.read()); 201 | mns = bcdToDec(Wire.read()); 202 | hr = bcdToDec(Wire.read() & 0b111111); // mask 24 hour time bit 203 | } 204 | 205 | // Convert binary coded decimal to normal decimal numbers 206 | byte bcdToDec(byte val) 207 | { 208 | return ( (val / 16 * 10) + (val % 16) ); 209 | } 210 | 211 | void txWspr() { 212 | int i; 213 | 214 | dds.output_enable(SI5351_CLK0, 1); // CLK0 on 215 | 216 | for(i = 0; i < 162; i++) { 217 | freqOut(freq + WSPR_DATA[i] * 146ULL); 218 | delay(682); // set empirically for TX lasting 110sec 219 | } 220 | 221 | dds.output_enable(SI5351_CLK0, 0); // CLK0 off 222 | } 223 | 224 | // output freq cHz 225 | void freqOut(uint32_t f) { 226 | dds.set_freq(f, 0ULL, SI5351_CLK0); 227 | } 228 | 229 | // display char msg at col c, row r 230 | void dispMsg(uint8_t c, uint8_t r, char *m) 231 | { 232 | lcd.setCursor(c, r); 233 | lcd.print(m); 234 | } 235 | 236 | // display a number at col c, row r 237 | void dispNum(uint8_t c, uint8_t r, uint16_t n) 238 | { 239 | lcd.setCursor(c, r); 240 | lcd.print(n); 241 | } 242 | 243 | // display freq in kHz,col c, row r, d decimal places 244 | void dispFreq(uint8_t c, uint8_t r, uint32_t f, uint8_t d) 245 | { 246 | lcd.setCursor(c, r); // clear last freq display 247 | lcd.print((float)f / 100000, d); // convert to float for print function 248 | lcd.print("kHz "); // + trailing spaces to clear previous display 249 | } 250 | 251 | // display time at col, row 252 | void dispTime(byte c, byte r) { 253 | lcd.setCursor(c, r); 254 | if (hr < 10) 255 | lcd.print("0"); 256 | lcd.print(hr); 257 | lcd.print(":"); 258 | if (mns < 10) 259 | lcd.print("0"); 260 | lcd.print(mns); 261 | lcd.print(":"); 262 | if (sec < 10) 263 | lcd.print("0"); 264 | lcd.print(sec); 265 | } 266 | 267 | 268 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Concept 2 | Arduino Concept SDR 3 | -------------------------------------------------------------------------------- /WSPR_Symbol_Generator/WSPR_Symbol_Generator.ino: -------------------------------------------------------------------------------- 1 | // WSPR_symbol_generator input coded, output on monitor 2 | // based on code from Martin Nawrath, Acedemy of Media Arts, Cologne 3 | // enter your call signe, locator and power dB *0 or *7 only 4 | // open monitor and hit ENTER 5 | 6 | const char SyncVec[162] = { 7 | 1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,0,0,0,0,0,0,1,0, 8 | 1,1,0,0,1,1,0,1,0,0,0,1,1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0, 9 | 0,0,1,0,0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1,0,1,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,0, 10 | 0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,0,0 11 | }; 12 | 13 | unsigned long n1; // encoded callsign 14 | unsigned long m1; // encodes locator 15 | 16 | byte c[11]; // encoded message 17 | byte sym[170]; // symbol table 162 18 | byte symt[170]; // symbol table temp 19 | 20 | // put your data here 21 | char call[] = " M6KWH"; // default values, 6 chars. 3rd numeric 22 | char locator[] = "IO92"; // default value 4 chars 23 | byte power = 20; // default value 2 numberic 24 | 25 | int ii, bb; 26 | 27 | void setup() 28 | { 29 | Serial.begin(9600); // connect to the serial port 30 | } 31 | 32 | void loop() 33 | { 34 | while(Serial.available() == 0); 35 | Serial.println("WSPR beacon"); 36 | Serial.flush(); 37 | 38 | encode_call(); 39 | 40 | Serial.print("Call: "); 41 | Serial.println(call); 42 | 43 | encode_locator(); 44 | 45 | Serial.print("Locator: "); 46 | Serial.println(locator); 47 | 48 | Serial.print("Power: "); 49 | Serial.println(power); 50 | 51 | encode_conv(); 52 | 53 | Serial.println(""); 54 | 55 | for (bb=0;bb<162 ;bb++) 56 | { 57 | Serial.print(symt[bb],DEC); 58 | Serial.print(","); 59 | if ( (bb+1) %32 == 0) Serial.println(""); 60 | } 61 | Serial.println(""); 62 | Serial.println(""); 63 | 64 | interleave_sync(); 65 | 66 | for (bb=0;bb<162 ;bb++) 67 | { 68 | Serial.print(sym[bb],DEC); 69 | Serial.print(","); 70 | if ((bb+1) %32 == 0) Serial.println(""); 71 | } 72 | Serial.println(""); 73 | 74 | while(Serial.available() > 0) Serial.read(); 75 | } 76 | 77 | 78 | // encode sequence 79 | void encode() 80 | { 81 | encode_call(); 82 | encode_locator(); 83 | encode_conv(); 84 | interleave_sync(); 85 | }; 86 | 87 | // normalize characters 0..9 A..Z Space in order 0..36 88 | char chr_normf(char bc ) 89 | { 90 | char cc=36; 91 | 92 | if (bc >= '0' && bc <= '9') cc=bc-'0'; 93 | if (bc >= 'A' && bc <= 'Z') cc=bc-'A'+10; 94 | if (bc == ' ' ) cc=36; 95 | 96 | return(cc); 97 | } 98 | 99 | // encode call sign 100 | void encode_call() 101 | { 102 | unsigned long t1; 103 | 104 | n1=chr_normf(call[0]); 105 | n1=n1*36+chr_normf(call[1]); 106 | n1=n1*10+chr_normf(call[2]); 107 | n1=n1*27+chr_normf(call[3])-10; 108 | n1=n1*27+chr_normf(call[4])-10; 109 | n1=n1*27+chr_normf(call[5])-10; 110 | 111 | // merge coded callsign into message array c[] 112 | t1=n1; 113 | c[0]= t1 >> 20; 114 | t1=n1; 115 | c[1]= t1 >> 12; 116 | t1=n1; 117 | c[2]= t1 >> 4; 118 | t1=n1; 119 | c[3]= t1 << 4; 120 | } 121 | 122 | // encode locator 123 | void encode_locator() 124 | { 125 | unsigned long t1; 126 | 127 | // coding of locator 128 | m1=179-10*(chr_normf(locator[0])-10)-chr_normf(locator[2]); 129 | m1=m1*180+10*(chr_normf(locator[1])-10)+chr_normf(locator[3]); 130 | m1=m1*128+power+64; 131 | 132 | // merge coded locator and power into message array c[] 133 | t1=m1; 134 | c[3]= c[3] + ( 0x0f & t1 >> 18); 135 | t1=m1; 136 | c[4]= t1 >> 10; 137 | t1=m1; 138 | c[5]= t1 >> 2; 139 | t1=m1; 140 | c[6]= t1 << 6; 141 | } 142 | 143 | void encode_conv() 144 | { 145 | int bc=0; 146 | int cnt=0; 147 | int cc; 148 | unsigned long sh1=0; 149 | 150 | cc=c[0]; 151 | 152 | for (int i=0; i < 81;i++) 153 | { 154 | if (i % 8 == 0 ) 155 | { 156 | cc=c[bc]; 157 | bc++; 158 | } 159 | if (cc & 0x80) sh1=sh1 | 1; 160 | 161 | symt[cnt++]=parity(sh1 & 0xF2D05351); 162 | symt[cnt++]=parity(sh1 & 0xE4613C47); 163 | 164 | cc=cc << 1; 165 | sh1=sh1 << 1; 166 | } 167 | } 168 | 169 | // calculate parity 170 | byte parity(unsigned long li) 171 | { 172 | byte po = 0; 173 | while(li != 0) 174 | { 175 | po++; 176 | li&= (li-1); 177 | } 178 | return (po & 1); 179 | } 180 | 181 | // interleave reorder the 162 data bits and and merge table with the sync vector 182 | void interleave_sync() 183 | { 184 | int ii,ij,b2,bis,ip; 185 | ip=0; 186 | 187 | for (ii=0;ii<=255;ii++) 188 | { 189 | bis=1; 190 | ij=0; 191 | 192 | for (b2=0;b2 < 8 ;b2++) 193 | { 194 | if (ii & bis) ij= ij | (0x80 >> b2); 195 | bis=bis << 1; 196 | } 197 | 198 | if (ij < 162 ) 199 | { 200 | sym[ij]= SyncVec[ij] +2*symt[ip]; 201 | ip++; 202 | } 203 | } 204 | } 205 | 206 | -------------------------------------------------------------------------------- /libraries/DS3231/DS3231.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231.cpp: DS3231 Real-Time Clock library 3 | original code by 4 | Eric Ayars 5 | 4/1/11 6 | 7 | updated to Arduino 1.0 8 | John Hubert 9 | Feb 7, 2012 10 | 11 | Released into the public domain. 12 | */ 13 | 14 | #include 15 | 16 | #define CLOCK_ADDRESS 0x68 17 | 18 | // Constructor 19 | DS3231::DS3231() { 20 | // nothing to do for this constructor. 21 | } 22 | 23 | /***************************************** 24 | Public Functions 25 | *****************************************/ 26 | 27 | void DS3231::getTime(byte& year, byte& month, byte& date, byte& DoW, byte& hour, byte& minute, byte& second) { 28 | byte tempBuffer; 29 | bool PM; 30 | bool h12; 31 | 32 | Wire.beginTransmission(CLOCK_ADDRESS); 33 | Wire.write(uint8_t(0x00)); 34 | Wire.endTransmission(); 35 | 36 | Wire.requestFrom(CLOCK_ADDRESS, 7); 37 | 38 | second = bcdToDec(Wire.read()); 39 | minute = bcdToDec(Wire.read()); 40 | tempBuffer = bcdToDec(Wire.read()); 41 | h12 = tempBuffer & 0b01000000; 42 | if (h12) { 43 | PM = tempBuffer & 0b00100000; 44 | hour = bcdToDec(tempBuffer & 0b00011111); 45 | } else { 46 | hour = bcdToDec(tempBuffer & 0b00111111); 47 | } 48 | DoW = bcdToDec(Wire.read()); 49 | date = bcdToDec(Wire.read()); 50 | month = bcdToDec(Wire.read() & 0b01111111); 51 | year = bcdToDec(Wire.read()); 52 | } 53 | 54 | byte DS3231::getSecond() { 55 | Wire.beginTransmission(CLOCK_ADDRESS); 56 | Wire.write(uint8_t(0x00)); 57 | Wire.endTransmission(); 58 | 59 | Wire.requestFrom(CLOCK_ADDRESS, 1); 60 | return bcdToDec(Wire.read()); 61 | } 62 | 63 | byte DS3231::getMinute() { 64 | Wire.beginTransmission(CLOCK_ADDRESS); 65 | Wire.write(0x01); 66 | Wire.endTransmission(); 67 | 68 | Wire.requestFrom(CLOCK_ADDRESS, 1); 69 | return bcdToDec(Wire.read()); 70 | } 71 | 72 | byte DS3231::getHour(bool& h12, bool& PM) { 73 | byte temp_buffer; 74 | byte hour; 75 | Wire.beginTransmission(CLOCK_ADDRESS); 76 | Wire.write(0x02); 77 | Wire.endTransmission(); 78 | 79 | Wire.requestFrom(CLOCK_ADDRESS, 1); 80 | temp_buffer = Wire.read(); 81 | h12 = temp_buffer & 0b01000000; 82 | if (h12) { 83 | PM = temp_buffer & 0b00100000; 84 | hour = bcdToDec(temp_buffer & 0b00011111); 85 | } else { 86 | hour = bcdToDec(temp_buffer & 0b00111111); 87 | } 88 | return hour; 89 | } 90 | 91 | byte DS3231::getDoW() { 92 | Wire.beginTransmission(CLOCK_ADDRESS); 93 | Wire.write(uint8_t(0x03)); 94 | Wire.endTransmission(); 95 | 96 | Wire.requestFrom(CLOCK_ADDRESS, 1); 97 | return bcdToDec(Wire.read()); 98 | } 99 | 100 | byte DS3231::getDate() { 101 | Wire.beginTransmission(CLOCK_ADDRESS); 102 | Wire.write(uint8_t(0x04)); 103 | Wire.endTransmission(); 104 | 105 | Wire.requestFrom(CLOCK_ADDRESS, 1); 106 | return bcdToDec(Wire.read()); 107 | } 108 | 109 | byte DS3231::getMonth(bool& Century) { 110 | byte temp_buffer; 111 | byte hour; 112 | Wire.beginTransmission(CLOCK_ADDRESS); 113 | Wire.write(uint8_t(0x05)); 114 | Wire.endTransmission(); 115 | 116 | Wire.requestFrom(CLOCK_ADDRESS, 1); 117 | temp_buffer = Wire.read(); 118 | Century = temp_buffer & 0b10000000; 119 | return (bcdToDec(temp_buffer & 0b01111111)) ; 120 | } 121 | 122 | byte DS3231::getYear() { 123 | Wire.beginTransmission(CLOCK_ADDRESS); 124 | Wire.write(uint8_t(0x06)); 125 | Wire.endTransmission(); 126 | 127 | Wire.requestFrom(CLOCK_ADDRESS, 1); 128 | return bcdToDec(Wire.read()); 129 | } 130 | 131 | void DS3231::setSecond(byte Second) { 132 | // Sets the seconds 133 | // This function also resets the Oscillator Stop Flag, which is set 134 | // whenever power is interrupted. 135 | Wire.beginTransmission(CLOCK_ADDRESS); 136 | Wire.write(uint8_t(0x00)); 137 | Wire.write(decToBcd(Second)); 138 | Wire.endTransmission(); 139 | // Clear OSF flag 140 | byte temp_buffer = readControlByte(1); 141 | writeControlByte((temp_buffer & 0b01111111), 1); 142 | } 143 | 144 | void DS3231::setMinute(byte Minute) { 145 | // Sets the minutes 146 | Wire.beginTransmission(CLOCK_ADDRESS); 147 | Wire.write(uint8_t(0x01)); 148 | Wire.write(decToBcd(Minute)); 149 | Wire.endTransmission(); 150 | } 151 | 152 | void DS3231::setHour(byte Hour) { 153 | // Sets the hour, without changing 12/24h mode. 154 | // The hour must be in 24h format. 155 | 156 | bool h12; 157 | 158 | // Start by figuring out what the 12/24 mode is 159 | Wire.beginTransmission(CLOCK_ADDRESS); 160 | Wire.write(uint8_t(0x02)); 161 | Wire.endTransmission(); 162 | Wire.requestFrom(CLOCK_ADDRESS, 1); 163 | h12 = (Wire.read() & 0b01000000); 164 | // if h12 is true, it's 12h mode; false is 24h. 165 | 166 | if (h12) { 167 | // 12 hour 168 | if (Hour > 12) { 169 | Hour = decToBcd(Hour-12) | 0b01100000; 170 | } else { 171 | Hour = decToBcd(Hour) & 0b11011111; 172 | } 173 | } else { 174 | // 24 hour 175 | Hour = decToBcd(Hour) & 0b10111111; 176 | } 177 | 178 | Wire.beginTransmission(CLOCK_ADDRESS); 179 | Wire.write(uint8_t(0x02)); 180 | Wire.write(Hour); 181 | Wire.endTransmission(); 182 | } 183 | 184 | void DS3231::setDoW(byte DoW) { 185 | // Sets the Day of Week 186 | Wire.beginTransmission(CLOCK_ADDRESS); 187 | Wire.write(uint8_t(0x03)); 188 | Wire.write(decToBcd(DoW)); 189 | Wire.endTransmission(); 190 | } 191 | 192 | void DS3231::setDate(byte Date) { 193 | // Sets the Date 194 | Wire.beginTransmission(CLOCK_ADDRESS); 195 | Wire.write(uint8_t(0x04)); 196 | Wire.write(decToBcd(Date)); 197 | Wire.endTransmission(); 198 | } 199 | 200 | void DS3231::setMonth(byte Month) { 201 | // Sets the month 202 | Wire.beginTransmission(CLOCK_ADDRESS); 203 | Wire.write(uint8_t(0x05)); 204 | Wire.write(decToBcd(Month)); 205 | Wire.endTransmission(); 206 | } 207 | 208 | void DS3231::setYear(byte Year) { 209 | // Sets the year 210 | Wire.beginTransmission(CLOCK_ADDRESS); 211 | Wire.write(uint8_t(0x06)); 212 | Wire.write(decToBcd(Year)); 213 | Wire.endTransmission(); 214 | } 215 | 216 | void DS3231::setClockMode(bool h12) { 217 | // sets the mode to 12-hour (true) or 24-hour (false). 218 | // One thing that bothers me about how I've written this is that 219 | // if the read and right happen at the right hourly millisecnd, 220 | // the clock will be set back an hour. Not sure how to do it better, 221 | // though, and as long as one doesn't set the mode frequently it's 222 | // a very minimal risk. 223 | // It's zero risk if you call this BEFORE setting the hour, since 224 | // the setHour() function doesn't change this mode. 225 | 226 | byte temp_buffer; 227 | 228 | // Start by reading byte 0x02. 229 | Wire.beginTransmission(CLOCK_ADDRESS); 230 | Wire.write(uint8_t(0x02)); 231 | Wire.endTransmission(); 232 | Wire.requestFrom(CLOCK_ADDRESS, 1); 233 | temp_buffer = Wire.read(); 234 | 235 | // Set the flag to the requested value: 236 | if (h12) { 237 | temp_buffer = temp_buffer | 0b01000000; 238 | } else { 239 | temp_buffer = temp_buffer & 0b10111111; 240 | } 241 | 242 | // Write the byte 243 | Wire.beginTransmission(CLOCK_ADDRESS); 244 | Wire.write(uint8_t(0x02)); 245 | Wire.write(temp_buffer); 246 | Wire.endTransmission(); 247 | } 248 | 249 | float DS3231::getTemperature() { 250 | // Checks the internal thermometer on the DS3231 and returns the 251 | // temperature as a floating-point value. 252 | byte temp; 253 | Wire.beginTransmission(CLOCK_ADDRESS); 254 | Wire.write(uint8_t(0x11)); 255 | Wire.endTransmission(); 256 | 257 | Wire.requestFrom(CLOCK_ADDRESS, 2); 258 | temp = Wire.read(); // Here's the MSB 259 | return float(temp) + 0.25*(Wire.read()>>6); 260 | } 261 | 262 | void DS3231::getA1Time(byte& A1Day, byte& A1Hour, byte& A1Minute, byte& A1Second, byte& AlarmBits, bool& A1Dy, bool& A1h12, bool& A1PM) { 263 | byte temp_buffer; 264 | Wire.beginTransmission(CLOCK_ADDRESS); 265 | Wire.write(uint8_t(0x07)); 266 | Wire.endTransmission(); 267 | 268 | Wire.requestFrom(CLOCK_ADDRESS, 4); 269 | 270 | temp_buffer = Wire.read(); // Get A1M1 and A1 Seconds 271 | A1Second = bcdToDec(temp_buffer & 0b01111111); 272 | // put A1M1 bit in position 0 of DS3231_AlarmBits. 273 | AlarmBits = AlarmBits | (temp_buffer & 0b10000000)>>7; 274 | 275 | temp_buffer = Wire.read(); // Get A1M2 and A1 minutes 276 | A1Minute = bcdToDec(temp_buffer & 0b01111111); 277 | // put A1M2 bit in position 1 of DS3231_AlarmBits. 278 | AlarmBits = AlarmBits | (temp_buffer & 0b10000000)>>6; 279 | 280 | temp_buffer = Wire.read(); // Get A1M3 and A1 Hour 281 | // put A1M3 bit in position 2 of DS3231_AlarmBits. 282 | AlarmBits = AlarmBits | (temp_buffer & 0b10000000)>>5; 283 | // determine A1 12/24 mode 284 | A1h12 = temp_buffer & 0b01000000; 285 | if (A1h12) { 286 | A1PM = temp_buffer & 0b00100000; // determine am/pm 287 | A1Hour = bcdToDec(temp_buffer & 0b00011111); // 12-hour 288 | } else { 289 | A1Hour = bcdToDec(temp_buffer & 0b00111111); // 24-hour 290 | } 291 | 292 | temp_buffer = Wire.read(); // Get A1M4 and A1 Day/Date 293 | // put A1M3 bit in position 3 of DS3231_AlarmBits. 294 | AlarmBits = AlarmBits | (temp_buffer & 0b10000000)>>4; 295 | // determine A1 day or date flag 296 | A1Dy = (temp_buffer & 0b01000000)>>6; 297 | if (A1Dy) { 298 | // alarm is by day of week, not date. 299 | A1Day = bcdToDec(temp_buffer & 0b00001111); 300 | } else { 301 | // alarm is by date, not day of week. 302 | A1Day = bcdToDec(temp_buffer & 0b00111111); 303 | } 304 | } 305 | 306 | void DS3231::getA2Time(byte& A2Day, byte& A2Hour, byte& A2Minute, byte& AlarmBits, bool& A2Dy, bool& A2h12, bool& A2PM) { 307 | byte temp_buffer; 308 | Wire.beginTransmission(CLOCK_ADDRESS); 309 | Wire.write(uint8_t(0x0b)); 310 | Wire.endTransmission(); 311 | 312 | Wire.requestFrom(CLOCK_ADDRESS, 3); 313 | temp_buffer = Wire.read(); // Get A2M2 and A2 Minutes 314 | A2Minute = bcdToDec(temp_buffer & 0b01111111); 315 | // put A2M2 bit in position 4 of DS3231_AlarmBits. 316 | AlarmBits = AlarmBits | (temp_buffer & 0b10000000)>>3; 317 | 318 | temp_buffer = Wire.read(); // Get A2M3 and A2 Hour 319 | // put A2M3 bit in position 5 of DS3231_AlarmBits. 320 | AlarmBits = AlarmBits | (temp_buffer & 0b10000000)>>2; 321 | // determine A2 12/24 mode 322 | A2h12 = temp_buffer & 0b01000000; 323 | if (A2h12) { 324 | A2PM = temp_buffer & 0b00100000; // determine am/pm 325 | A2Hour = bcdToDec(temp_buffer & 0b00011111); // 12-hour 326 | } else { 327 | A2Hour = bcdToDec(temp_buffer & 0b00111111); // 24-hour 328 | } 329 | 330 | temp_buffer = Wire.read(); // Get A2M4 and A1 Day/Date 331 | // put A2M4 bit in position 6 of DS3231_AlarmBits. 332 | AlarmBits = AlarmBits | (temp_buffer & 0b10000000)>>1; 333 | // determine A2 day or date flag 334 | A2Dy = (temp_buffer & 0b01000000)>>6; 335 | if (A2Dy) { 336 | // alarm is by day of week, not date. 337 | A2Day = bcdToDec(temp_buffer & 0b00001111); 338 | } else { 339 | // alarm is by date, not day of week. 340 | A2Day = bcdToDec(temp_buffer & 0b00111111); 341 | } 342 | } 343 | 344 | void DS3231::setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM) { 345 | // Sets the alarm-1 date and time on the DS3231, using A1* information 346 | byte temp_buffer; 347 | Wire.beginTransmission(CLOCK_ADDRESS); 348 | Wire.write(uint8_t(0x07)); // A1 starts at 07h 349 | // Send A1 second and A1M1 350 | Wire.write(decToBcd(A1Second) | ((AlarmBits & 0b00000001) << 7)); 351 | // Send A1 Minute and A1M2 352 | Wire.write(decToBcd(A1Minute) | ((AlarmBits & 0b00000010) << 6)); 353 | // Figure out A1 hour 354 | if (A1h12) { 355 | // Start by converting existing time to h12 if it was given in 24h. 356 | if (A1Hour > 12) { 357 | // well, then, this obviously isn't a h12 time, is it? 358 | A1Hour = A1Hour - 12; 359 | A1PM = true; 360 | } 361 | if (A1PM) { 362 | // Afternoon 363 | // Convert the hour to BCD and add appropriate flags. 364 | temp_buffer = decToBcd(A1Hour) | 0b01100000; 365 | } else { 366 | // Morning 367 | // Convert the hour to BCD and add appropriate flags. 368 | temp_buffer = decToBcd(A1Hour) | 0b01000000; 369 | } 370 | } else { 371 | // Now for 24h 372 | temp_buffer = decToBcd(A1Hour); 373 | } 374 | temp_buffer = temp_buffer | ((AlarmBits & 0b00000100)<<5); 375 | // A1 hour is figured out, send it 376 | Wire.write(temp_buffer); 377 | // Figure out A1 day/date and A1M4 378 | temp_buffer = ((AlarmBits & 0b00001000)<<4) | decToBcd(A1Day); 379 | if (A1Dy) { 380 | // Set A1 Day/Date flag (Otherwise it's zero) 381 | temp_buffer = temp_buffer | 0b01000000; 382 | } 383 | Wire.write(temp_buffer); 384 | // All done! 385 | Wire.endTransmission(); 386 | } 387 | 388 | void DS3231::setA2Time(byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits, bool A2Dy, bool A2h12, bool A2PM) { 389 | // Sets the alarm-2 date and time on the DS3231, using A2* information 390 | byte temp_buffer; 391 | Wire.beginTransmission(CLOCK_ADDRESS); 392 | Wire.write(uint8_t(0x0b)); // A1 starts at 0bh 393 | // Send A2 Minute and A2M2 394 | Wire.write(decToBcd(A2Minute) | ((AlarmBits & 0b00010000) << 3)); 395 | // Figure out A2 hour 396 | if (A2h12) { 397 | // Start by converting existing time to h12 if it was given in 24h. 398 | if (A2Hour > 12) { 399 | // well, then, this obviously isn't a h12 time, is it? 400 | A2Hour = A2Hour - 12; 401 | A2PM = true; 402 | } 403 | if (A2PM) { 404 | // Afternoon 405 | // Convert the hour to BCD and add appropriate flags. 406 | temp_buffer = decToBcd(A2Hour) | 0b01100000; 407 | } else { 408 | // Morning 409 | // Convert the hour to BCD and add appropriate flags. 410 | temp_buffer = decToBcd(A2Hour) | 0b01000000; 411 | } 412 | } else { 413 | // Now for 24h 414 | temp_buffer = decToBcd(A2Hour); 415 | } 416 | // add in A2M3 bit 417 | temp_buffer = temp_buffer | ((AlarmBits & 0b00100000)<<2); 418 | // A2 hour is figured out, send it 419 | Wire.write(temp_buffer); 420 | // Figure out A2 day/date and A2M4 421 | temp_buffer = ((AlarmBits & 0b01000000)<<1) | decToBcd(A2Day); 422 | if (A2Dy) { 423 | // Set A2 Day/Date flag (Otherwise it's zero) 424 | temp_buffer = temp_buffer | 0b01000000; 425 | } 426 | Wire.write(temp_buffer); 427 | // All done! 428 | Wire.endTransmission(); 429 | } 430 | 431 | void DS3231::turnOnAlarm(byte Alarm) { 432 | // turns on alarm number "Alarm". Defaults to 2 if Alarm is not 1. 433 | byte temp_buffer = readControlByte(0); 434 | // modify control byte 435 | if (Alarm == 1) { 436 | temp_buffer = temp_buffer | 0b00000101; 437 | } else { 438 | temp_buffer = temp_buffer | 0b00000110; 439 | } 440 | writeControlByte(temp_buffer, 0); 441 | } 442 | 443 | void DS3231::turnOffAlarm(byte Alarm) { 444 | // turns off alarm number "Alarm". Defaults to 2 if Alarm is not 1. 445 | // Leaves interrupt pin alone. 446 | byte temp_buffer = readControlByte(0); 447 | // modify control byte 448 | if (Alarm == 1) { 449 | temp_buffer = temp_buffer & 0b11111110; 450 | } else { 451 | temp_buffer = temp_buffer & 0b11111101; 452 | } 453 | writeControlByte(temp_buffer, 0); 454 | } 455 | 456 | bool DS3231::checkAlarmEnabled(byte Alarm) { 457 | // Checks whether the given alarm is enabled. 458 | byte result = 0x0; 459 | byte temp_buffer = readControlByte(0); 460 | if (Alarm == 1) { 461 | result = temp_buffer & 0b00000001; 462 | } else { 463 | result = temp_buffer & 0b00000010; 464 | } 465 | return result; 466 | } 467 | 468 | bool DS3231::checkIfAlarm(byte Alarm) { 469 | // Checks whether alarm 1 or alarm 2 flag is on, returns T/F accordingly. 470 | // Turns flag off, also. 471 | // defaults to checking alarm 2, unless Alarm == 1. 472 | byte result; 473 | byte temp_buffer = readControlByte(1); 474 | if (Alarm == 1) { 475 | // Did alarm 1 go off? 476 | result = temp_buffer & 0b00000001; 477 | // clear flag 478 | temp_buffer = temp_buffer & 0b11111110; 479 | } else { 480 | // Did alarm 2 go off? 481 | result = temp_buffer & 0b00000010; 482 | // clear flag 483 | temp_buffer = temp_buffer & 0b11111101; 484 | } 485 | writeControlByte(temp_buffer, 1); 486 | return result; 487 | } 488 | 489 | void DS3231::enableOscillator(bool TF, bool battery, byte frequency) { 490 | // turns oscillator on or off. True is on, false is off. 491 | // if battery is true, turns on even for battery-only operation, 492 | // otherwise turns off if Vcc is off. 493 | // frequency must be 0, 1, 2, or 3. 494 | // 0 = 1 Hz 495 | // 1 = 1.024 kHz 496 | // 2 = 4.096 kHz 497 | // 3 = 8.192 kHz (Default if frequency byte is out of range) 498 | if (frequency > 3) frequency = 3; 499 | // read control byte in, but zero out current state of RS2 and RS1. 500 | byte temp_buffer = readControlByte(0) & 0b11100111; 501 | if (battery) { 502 | // turn on BBSQW flag 503 | temp_buffer = temp_buffer | 0b01000000; 504 | } else { 505 | // turn off BBSQW flag 506 | temp_buffer = temp_buffer & 0b10111111; 507 | } 508 | if (TF) { 509 | // set ~EOSC to 0 and INTCN to zero. 510 | temp_buffer = temp_buffer & 0b01111011; 511 | } else { 512 | // set ~EOSC to 1, leave INTCN as is. 513 | temp_buffer = temp_buffer | 0b10000000; 514 | } 515 | // shift frequency into bits 3 and 4 and set. 516 | frequency = frequency << 3; 517 | temp_buffer = temp_buffer | frequency; 518 | // And write the control bits 519 | writeControlByte(temp_buffer, 0); 520 | } 521 | 522 | void DS3231::enable32kHz(bool TF) { 523 | // turn 32kHz pin on or off 524 | byte temp_buffer = readControlByte(1); 525 | if (TF) { 526 | // turn on 32kHz pin 527 | temp_buffer = temp_buffer | 0b00001000; 528 | } else { 529 | // turn off 32kHz pin 530 | temp_buffer = temp_buffer & 0b11110111; 531 | } 532 | writeControlByte(temp_buffer, 1); 533 | } 534 | 535 | bool DS3231::oscillatorCheck() { 536 | // Returns false if the oscillator has been off for some reason. 537 | // If this is the case, the time is probably not correct. 538 | byte temp_buffer = readControlByte(1); 539 | bool result = true; 540 | if (temp_buffer & 0b10000000) { 541 | // Oscillator Stop Flag (OSF) is set, so return false. 542 | result = false; 543 | } 544 | return result; 545 | } 546 | 547 | /***************************************** 548 | Private Functions 549 | *****************************************/ 550 | 551 | byte DS3231::decToBcd(byte val) { 552 | // Convert normal decimal numbers to binary coded decimal 553 | return ( (val/10*16) + (val%10) ); 554 | } 555 | 556 | byte DS3231::bcdToDec(byte val) { 557 | // Convert binary coded decimal to normal decimal numbers 558 | return ( (val/16*10) + (val%16) ); 559 | } 560 | 561 | byte DS3231::readControlByte(bool which) { 562 | // Read selected control byte 563 | // first byte (0) is 0x0e, second (1) is 0x0f 564 | Wire.beginTransmission(CLOCK_ADDRESS); 565 | if (which) { 566 | // second control byte 567 | Wire.write(uint8_t(0x0f)); 568 | } else { 569 | // first control byte 570 | Wire.write(uint8_t(0x0e)); 571 | } 572 | Wire.endTransmission(); 573 | Wire.requestFrom(CLOCK_ADDRESS, 1); 574 | return Wire.read(); 575 | } 576 | 577 | void DS3231::writeControlByte(byte control, bool which) { 578 | // Write the selected control byte. 579 | // which=false -> 0x0e, true->0x0f. 580 | Wire.beginTransmission(CLOCK_ADDRESS); 581 | if (which) { 582 | Wire.write(uint8_t(0x0f)); 583 | } else { 584 | Wire.write(uint8_t(0x0e)); 585 | } 586 | Wire.write(control); 587 | Wire.endTransmission(); 588 | } 589 | 590 | -------------------------------------------------------------------------------- /libraries/DS3231/DS3231.h: -------------------------------------------------------------------------------- 1 | /* 2 | * DS3231.h 3 | * 4 | * Arduino Library for the DS3231 Real-Time Clock chip 5 | * 6 | * (c) Eric Ayars 7 | * 4/1/11 8 | * Updated to Arduino 1.0 By john Hubert 9 | * Feb 7 2012 10 | * released into the public domain. If you use this, please let me know 11 | * (just out of pure curiosity!) by sending me an email: 12 | * eric@ayars.org 13 | * 14 | */ 15 | 16 | #ifndef DS3231_h 17 | #define DS3231_h 18 | 19 | #include 20 | #include 21 | 22 | class DS3231 { 23 | public: 24 | 25 | //Constructor 26 | DS3231(); 27 | 28 | // Time-retrieval functions 29 | 30 | // the get*() functions retrieve current values of the registers. 31 | // If you only need one element, use that one for simplicity; but 32 | // if you need the whole passel then use getTime() to avoid 33 | // the chance of rollover between reads of the different components. 34 | void getTime(byte& year, byte& month, byte& date, byte& DoW, byte& hour, byte& minute, byte& second); 35 | byte getSecond(); 36 | byte getMinute(); 37 | byte getHour(bool& h12, bool& PM); 38 | // In addition to returning the hour register, this function 39 | // returns the values of the 12/24-hour flag and the AM/PM flag. 40 | byte getDoW(); 41 | byte getDate(); 42 | byte getMonth(bool& Century); 43 | // Also sets the flag indicating century roll-over. 44 | byte getYear(); 45 | // Last 2 digits only 46 | 47 | // Time-setting functions 48 | // Note that none of these check for sensibility: You can set the 49 | // date to July 42nd and strange things will probably result. 50 | 51 | void setSecond(byte Second); 52 | // In addition to setting the seconds, this clears the 53 | // "Oscillator Stop Flag". 54 | void setMinute(byte Minute); 55 | // Sets the minute 56 | void setHour(byte Hour); 57 | // Sets the hour 58 | void setDoW(byte DoW); 59 | // Sets the Day of the Week (1-7); 60 | void setDate(byte Date); 61 | // Sets the Date of the Month 62 | void setMonth(byte Month); 63 | // Sets the Month of the year 64 | void setYear(byte Year); 65 | // Last two digits of the year 66 | void setClockMode(bool h12); 67 | // Set 12/24h mode. True is 12-h, false is 24-hour. 68 | 69 | // Temperature function 70 | 71 | float getTemperature(); 72 | 73 | // Alarm functions 74 | 75 | void getA1Time(byte& A1Day, byte& A1Hour, byte& A1Minute, byte& A1Second, byte& AlarmBits, bool& A1Dy, bool& A1h12, bool& A1PM); 76 | /* Retrieves everything you could want to know about alarm 77 | * one. 78 | * A1Dy true makes the alarm go on A1Day = Day of Week, 79 | * A1Dy false makes the alarm go on A1Day = Date of month. 80 | * 81 | * byte AlarmBits sets the behavior of the alarms: 82 | * Dy A1M4 A1M3 A1M2 A1M1 Rate 83 | * X 1 1 1 1 Once per second 84 | * X 1 1 1 0 Alarm when seconds match 85 | * X 1 1 0 0 Alarm when min, sec match 86 | * X 1 0 0 0 Alarm when hour, min, sec match 87 | * 0 0 0 0 0 Alarm when date, h, m, s match 88 | * 1 0 0 0 0 Alarm when DoW, h, m, s match 89 | * 90 | * Dy A2M4 A2M3 A2M2 Rate 91 | * X 1 1 1 Once per minute (at seconds = 00) 92 | * X 1 1 0 Alarm when minutes match 93 | * X 1 0 0 Alarm when hours and minutes match 94 | * 0 0 0 0 Alarm when date, hour, min match 95 | * 1 0 0 0 Alarm when DoW, hour, min match 96 | */ 97 | void getA2Time(byte& A2Day, byte& A2Hour, byte& A2Minute, byte& AlarmBits, bool& A2Dy, bool& A2h12, bool& A2PM); 98 | // Same as getA1Time();, but A2 only goes on seconds == 00. 99 | void setA1Time(byte A1Day, byte A1Hour, byte A1Minute, byte A1Second, byte AlarmBits, bool A1Dy, bool A1h12, bool A1PM); 100 | // Set the details for Alarm 1 101 | void setA2Time(byte A2Day, byte A2Hour, byte A2Minute, byte AlarmBits, bool A2Dy, bool A2h12, bool A2PM); 102 | // Set the details for Alarm 2 103 | void turnOnAlarm(byte Alarm); 104 | // Enables alarm 1 or 2 and the external interrupt pin. 105 | // If Alarm != 1, it assumes Alarm == 2. 106 | void turnOffAlarm(byte Alarm); 107 | // Disables alarm 1 or 2 (default is 2 if Alarm != 1); 108 | // and leaves the interrupt pin alone. 109 | bool checkAlarmEnabled(byte Alarm); 110 | // Returns T/F to indicate whether the requested alarm is 111 | // enabled. Defaults to 2 if Alarm != 1. 112 | bool checkIfAlarm(byte Alarm); 113 | // Checks whether the indicated alarm (1 or 2, 2 default); 114 | // has been activated. 115 | 116 | // Oscillator functions 117 | 118 | void enableOscillator(bool TF, bool battery, byte frequency); 119 | // turns oscillator on or off. True is on, false is off. 120 | // if battery is true, turns on even for battery-only operation, 121 | // otherwise turns off if Vcc is off. 122 | // frequency must be 0, 1, 2, or 3. 123 | // 0 = 1 Hz 124 | // 1 = 1.024 kHz 125 | // 2 = 4.096 kHz 126 | // 3 = 8.192 kHz (Default if frequency byte is out of range); 127 | void enable32kHz(bool TF); 128 | // Turns the 32kHz output pin on (true); or off (false). 129 | bool oscillatorCheck();; 130 | // Checks the status of the OSF (Oscillator Stop Flag);. 131 | // If this returns false, then the clock is probably not 132 | // giving you the correct time. 133 | // The OSF is cleared by function setSecond();. 134 | 135 | private: 136 | 137 | byte decToBcd(byte val); 138 | // Convert normal decimal numbers to binary coded decimal 139 | byte bcdToDec(byte val); 140 | // Convert binary coded decimal to normal decimal numbers 141 | byte readControlByte(bool which); 142 | // Read selected control byte: (0); reads 0x0e, (1) reads 0x0f 143 | void writeControlByte(byte control, bool which); 144 | // Write the selected control byte. 145 | // which == false -> 0x0e, true->0x0f. 146 | 147 | }; 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /libraries/DS3231/Examples/DS3231_oscillator_test/DS3231_oscillator_test.ino: -------------------------------------------------------------------------------- 1 | /* 2 | oscillator_test.pde 3 | Eric Ayars 4 | 4/11 5 | 6 | Test/demo of oscillator routines for a DS3231 RTC. 7 | 8 | Use a scope after loading this to check if things are 9 | working as they should. 10 | 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | DS3231 Clock; 17 | byte j; 18 | bool on = false; 19 | 20 | void setup() { 21 | // Start the I2C interface 22 | Wire.begin(); 23 | // Start the serial interface 24 | Serial.begin(9600); 25 | } 26 | 27 | void loop() { 28 | for (j=0;j<4;j++) { 29 | // invert state of 32kHz oscillator. 30 | on = !on; 31 | Clock.enable32kHz(on); 32 | // Turn on oscillator pin, frequency j 33 | Clock.enableOscillator(true, false, j); 34 | delay(4000); 35 | } 36 | // So... The 32kHz oscillator (pin 1) will turn on or off once each 2s, 37 | // and the oscillator out pin (pin 3) will cycle through frequencies. 38 | } 39 | -------------------------------------------------------------------------------- /libraries/DS3231/Examples/DS3231_set/ds3231_set.ino: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231_set.pde 3 | Eric Ayars 4 | 4/11 5 | 6 | Test of set-time routines for a DS3231 RTC 7 | 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | DS3231 Clock; 14 | 15 | byte Year; 16 | byte Month; 17 | byte Date; 18 | byte DoW; 19 | byte Hour; 20 | byte Minute; 21 | byte Second; 22 | 23 | void GetDateStuff(byte& Year, byte& Month, byte& Day, byte& DoW, 24 | byte& Hour, byte& Minute, byte& Second) { 25 | // Call this if you notice something coming in on 26 | // the serial port. The stuff coming in should be in 27 | // the order YYMMDDwHHMMSS, with an 'x' at the end. 28 | boolean GotString = false; 29 | char InChar; 30 | byte Temp1, Temp2; 31 | char InString[20]; 32 | 33 | byte j=0; 34 | while (!GotString) { 35 | if (Serial.available()) { 36 | InChar = Serial.read(); 37 | InString[j] = InChar; 38 | j += 1; 39 | if (InChar == 'x') { 40 | GotString = true; 41 | } 42 | } 43 | } 44 | Serial.println(InString); 45 | // Read Year first 46 | Temp1 = (byte)InString[0] -48; 47 | Temp2 = (byte)InString[1] -48; 48 | Year = Temp1*10 + Temp2; 49 | // now month 50 | Temp1 = (byte)InString[2] -48; 51 | Temp2 = (byte)InString[3] -48; 52 | Month = Temp1*10 + Temp2; 53 | // now date 54 | Temp1 = (byte)InString[4] -48; 55 | Temp2 = (byte)InString[5] -48; 56 | Day = Temp1*10 + Temp2; 57 | // now Day of Week 58 | DoW = (byte)InString[6] - 48; 59 | // now Hour 60 | Temp1 = (byte)InString[7] -48; 61 | Temp2 = (byte)InString[8] -48; 62 | Hour = Temp1*10 + Temp2; 63 | // now Minute 64 | Temp1 = (byte)InString[9] -48; 65 | Temp2 = (byte)InString[10] -48; 66 | Minute = Temp1*10 + Temp2; 67 | // now Second 68 | Temp1 = (byte)InString[11] -48; 69 | Temp2 = (byte)InString[12] -48; 70 | Second = Temp1*10 + Temp2; 71 | } 72 | 73 | void setup() { 74 | // Start the serial port 75 | Serial.begin(9600); 76 | 77 | // Start the I2C interface 78 | Wire.begin(); 79 | } 80 | 81 | void loop() { 82 | 83 | // If something is coming in on the serial line, it's 84 | // a time correction so set the clock accordingly. 85 | if (Serial.available()) { 86 | GetDateStuff(Year, Month, Date, DoW, Hour, Minute, Second); 87 | 88 | Clock.setClockMode(false); // set to 24h 89 | //setClockMode(true); // set to 12h 90 | 91 | Clock.setYear(Year); 92 | Clock.setMonth(Month); 93 | Clock.setDate(Date); 94 | Clock.setDoW(DoW); 95 | Clock.setHour(Hour); 96 | Clock.setMinute(Minute); 97 | Clock.setSecond(Second); 98 | 99 | // Test of alarm functions 100 | // set A1 to one minute past the time we just set the clock 101 | // on current day of week. 102 | Clock.setA1Time(DoW, Hour, Minute+1, Second, 0x0, true, 103 | false, false); 104 | // set A2 to two minutes past, on current day of month. 105 | Clock.setA2Time(Date, Hour, Minute+2, 0x0, false, false, 106 | false); 107 | // Turn on both alarms, with external interrupt 108 | Clock.turnOnAlarm(1); 109 | Clock.turnOnAlarm(2); 110 | 111 | } 112 | delay(1000); 113 | } 114 | 115 | -------------------------------------------------------------------------------- /libraries/DS3231/Examples/DS3231_test/ds3231_test.ino: -------------------------------------------------------------------------------- 1 | /* 2 | DS3231_test.pde 3 | Eric Ayars 4 | 4/11 5 | 6 | Test/demo of read routines for a DS3231 RTC. 7 | 8 | Turn on the serial monitor after loading this to check if things are 9 | working as they should. 10 | 11 | */ 12 | 13 | #include 14 | #include 15 | 16 | DS3231 Clock; 17 | bool Century=false; 18 | bool h12; 19 | bool PM; 20 | byte ADay, AHour, AMinute, ASecond, ABits; 21 | bool ADy, A12h, Apm; 22 | 23 | byte year, month, date, DoW, hour, minute, second; 24 | 25 | void setup() { 26 | // Start the I2C interface 27 | Wire.begin(); 28 | // Start the serial interface 29 | Serial.begin(57600); 30 | } 31 | 32 | void loop() { 33 | // send what's going on to the serial monitor. 34 | // Start with the year 35 | Serial.print("2"); 36 | if (Century) { // Won't need this for 89 years. 37 | Serial.print("1"); 38 | } else { 39 | Serial.print("0"); 40 | } 41 | Serial.print(Clock.getYear(), DEC); 42 | Serial.print(' '); 43 | // then the month 44 | Serial.print(Clock.getMonth(Century), DEC); 45 | Serial.print(' '); 46 | // then the date 47 | Serial.print(Clock.getDate(), DEC); 48 | Serial.print(' '); 49 | // and the day of the week 50 | Serial.print(Clock.getDoW(), DEC); 51 | Serial.print(' '); 52 | // Finally the hour, minute, and second 53 | Serial.print(Clock.getHour(h12, PM), DEC); 54 | Serial.print(' '); 55 | Serial.print(Clock.getMinute(), DEC); 56 | Serial.print(' '); 57 | Serial.print(Clock.getSecond(), DEC); 58 | // Add AM/PM indicator 59 | if (h12) { 60 | if (PM) { 61 | Serial.print(" PM "); 62 | } else { 63 | Serial.print(" AM "); 64 | } 65 | } else { 66 | Serial.print(" 24h "); 67 | } 68 | // Display the temperature 69 | Serial.print("T="); 70 | Serial.print(Clock.getTemperature(), 2); 71 | // Tell whether the time is (likely to be) valid 72 | if (Clock.oscillatorCheck()) { 73 | Serial.print(" O+"); 74 | } else { 75 | Serial.print(" O-"); 76 | } 77 | // Indicate whether an alarm went off 78 | if (Clock.checkIfAlarm(1)) { 79 | Serial.print(" A1!"); 80 | } 81 | if (Clock.checkIfAlarm(2)) { 82 | Serial.print(" A2!"); 83 | } 84 | // New line on display 85 | Serial.print('\n'); 86 | // Display Alarm 1 information 87 | Serial.print("Alarm 1: "); 88 | Clock.getA1Time(ADay, AHour, AMinute, ASecond, ABits, ADy, A12h, Apm); 89 | Serial.print(ADay, DEC); 90 | if (ADy) { 91 | Serial.print(" DoW"); 92 | } else { 93 | Serial.print(" Date"); 94 | } 95 | Serial.print(' '); 96 | Serial.print(AHour, DEC); 97 | Serial.print(' '); 98 | Serial.print(AMinute, DEC); 99 | Serial.print(' '); 100 | Serial.print(ASecond, DEC); 101 | Serial.print(' '); 102 | if (A12h) { 103 | if (Apm) { 104 | Serial.print('pm '); 105 | } else { 106 | Serial.print('am '); 107 | } 108 | } 109 | if (Clock.checkAlarmEnabled(1)) { 110 | Serial.print("enabled"); 111 | } 112 | Serial.print('\n'); 113 | // Display Alarm 2 information 114 | Serial.print("Alarm 2: "); 115 | Clock.getA2Time(ADay, AHour, AMinute, ABits, ADy, A12h, Apm); 116 | Serial.print(ADay, DEC); 117 | if (ADy) { 118 | Serial.print(" DoW"); 119 | } else { 120 | Serial.print(" Date"); 121 | } 122 | Serial.print(' '); 123 | Serial.print(AHour, DEC); 124 | Serial.print(' '); 125 | Serial.print(AMinute, DEC); 126 | Serial.print(' '); 127 | if (A12h) { 128 | if (Apm) { 129 | Serial.print('pm'); 130 | } else { 131 | Serial.print('am'); 132 | } 133 | } 134 | if (Clock.checkAlarmEnabled(2)) { 135 | Serial.print("enabled"); 136 | } 137 | /* display alarm bits 138 | Serial.print('\n'); 139 | Serial.print('Alarm bits: '); 140 | Serial.print(ABits, DEC); 141 | */ 142 | 143 | Serial.print('\n'); 144 | Serial.print('\n'); 145 | delay(1000); 146 | 147 | // Display the time once more as a test of the getTime() function 148 | Clock.getTime(year, month, date, DoW, hour, minute, second); 149 | 150 | Serial.print(year, DEC); 151 | Serial.print("/"); 152 | Serial.print(month, DEC); 153 | Serial.print("/"); 154 | Serial.print(date, DEC); 155 | Serial.print("day of the week :"); 156 | Serial.println(DoW, DEC); 157 | Serial.print(hour, DEC); 158 | Serial.print(":"); 159 | Serial.print(minute, DEC); 160 | Serial.print(":"); 161 | Serial.println(second, DEC); 162 | } 163 | 164 | -------------------------------------------------------------------------------- /libraries/DS3231/Readme.txt: -------------------------------------------------------------------------------- 1 | This library was original code by Eric Ayars 4/1/11 2 | 3 | Code was updated to run with Arduino IDE 1.0 By John Hubert Feb 7,2012 4 | Examples are all still original but in an INO file. 5 | 6 | Thank you Eric Ayars For your great work on the original code -------------------------------------------------------------------------------- /libraries/DS3231/keywords.txt: -------------------------------------------------------------------------------- 1 | DS3231 KEYWORD1 2 | getSecond KEYWORD2 3 | getMinute KEYWORD2 4 | getHour KEYWORD2 5 | getDoW KEYWORD2 6 | getDate KEYWORD2 7 | getMonth KEYWORD2 8 | getYear KEYWORD2 9 | setSecond KEYWORD2 10 | setMinute KEYWORD2 11 | setHour KEYWORD2 12 | setDoW KEYWORD2 13 | setDate KEYWORD2 14 | setMonth KEYWORD2 15 | setYear KEYWORD2 16 | setClockMode KEYWORD2 17 | getTemperature KEYWORD2 18 | getA1Time KEYWORD2 19 | getA2Time KEYWORD2 20 | setA1Time KEYWORD2 21 | setA2Time KEYWORD2 22 | turnOnAlarm KEYWORD2 23 | turnOffAlarm KEYWORD2 24 | checkAlarmEnabled KEYWORD2 25 | checkIfAlarm KEYWORD2 26 | enableOscillator KEYWORD2 27 | enable32kHz KEYWORD2 28 | oscillatorCheck KEYWORD2 29 | -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/LiquidCrystal_I2C.cpp: -------------------------------------------------------------------------------- 1 | //YWROBOT 2 | //last updated on 21/12/2011 3 | //Tim Starling Fix the reset bug (Thanks Tim) 4 | //wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063) 5 | //Support Forum: http://www.dfrobot.com/forum/ 6 | //Compatible with the Arduino IDE 1.0 7 | //Library version:1.1 8 | 9 | 10 | #include "LiquidCrystal_I2C.h" 11 | #include 12 | #if defined(ARDUINO) && ARDUINO >= 100 13 | 14 | #include "Arduino.h" 15 | 16 | #define printIIC(args) Wire.write(args) 17 | inline size_t LiquidCrystal_I2C::write(uint8_t value) { 18 | send(value, Rs); 19 | return 0; 20 | } 21 | 22 | #else 23 | #include "WProgram.h" 24 | 25 | #define printIIC(args) Wire.send(args) 26 | inline void LiquidCrystal_I2C::write(uint8_t value) { 27 | send(value, Rs); 28 | } 29 | 30 | #endif 31 | #include "Wire.h" 32 | 33 | 34 | 35 | // When the display powers up, it is configured as follows: 36 | // 37 | // 1. Display clear 38 | // 2. Function set: 39 | // DL = 1; 8-bit interface data 40 | // N = 0; 1-line display 41 | // F = 0; 5x8 dot character font 42 | // 3. Display on/off control: 43 | // D = 0; Display off 44 | // C = 0; Cursor off 45 | // B = 0; Blinking off 46 | // 4. Entry mode set: 47 | // I/D = 1; Increment by 1 48 | // S = 0; No shift 49 | // 50 | // Note, however, that resetting the Arduino doesn't reset the LCD, so we 51 | // can't assume that its in that state when a sketch starts (and the 52 | // LiquidCrystal constructor is called). 53 | 54 | LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows) 55 | { 56 | _Addr = lcd_Addr; 57 | _cols = lcd_cols; 58 | _rows = lcd_rows; 59 | _backlightval = LCD_NOBACKLIGHT; 60 | } 61 | 62 | void LiquidCrystal_I2C::init(){ 63 | init_priv(); 64 | } 65 | 66 | void LiquidCrystal_I2C::init_priv() 67 | { 68 | Wire.begin(); 69 | _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; 70 | begin(_cols, _rows); 71 | } 72 | 73 | void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { 74 | if (lines > 1) { 75 | _displayfunction |= LCD_2LINE; 76 | } 77 | _numlines = lines; 78 | 79 | // for some 1 line displays you can select a 10 pixel high font 80 | if ((dotsize != 0) && (lines == 1)) { 81 | _displayfunction |= LCD_5x10DOTS; 82 | } 83 | 84 | // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! 85 | // according to datasheet, we need at least 40ms after power rises above 2.7V 86 | // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 87 | delay(50); 88 | 89 | // Now we pull both RS and R/W low to begin commands 90 | expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1) 91 | delay(1000); 92 | 93 | //put the LCD into 4 bit mode 94 | // this is according to the hitachi HD44780 datasheet 95 | // figure 24, pg 46 96 | 97 | // we start in 8bit mode, try to set 4 bit mode 98 | write4bits(0x03 << 4); 99 | delayMicroseconds(4500); // wait min 4.1ms 100 | 101 | // second try 102 | write4bits(0x03 << 4); 103 | delayMicroseconds(4500); // wait min 4.1ms 104 | 105 | // third go! 106 | write4bits(0x03 << 4); 107 | delayMicroseconds(150); 108 | 109 | // finally, set to 4-bit interface 110 | write4bits(0x02 << 4); 111 | 112 | 113 | // set # lines, font size, etc. 114 | command(LCD_FUNCTIONSET | _displayfunction); 115 | 116 | // turn the display on with no cursor or blinking default 117 | _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; 118 | display(); 119 | 120 | // clear it off 121 | clear(); 122 | 123 | // Initialize to default text direction (for roman languages) 124 | _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; 125 | 126 | // set the entry mode 127 | command(LCD_ENTRYMODESET | _displaymode); 128 | 129 | home(); 130 | 131 | } 132 | 133 | /********** high level commands, for the user! */ 134 | void LiquidCrystal_I2C::clear(){ 135 | command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero 136 | delayMicroseconds(2000); // this command takes a long time! 137 | } 138 | 139 | void LiquidCrystal_I2C::home(){ 140 | command(LCD_RETURNHOME); // set cursor position to zero 141 | delayMicroseconds(2000); // this command takes a long time! 142 | } 143 | 144 | void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row){ 145 | int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; 146 | if ( row > _numlines ) { 147 | row = _numlines-1; // we count rows starting w/0 148 | } 149 | command(LCD_SETDDRAMADDR | (col + row_offsets[row])); 150 | } 151 | 152 | // Turn the display on/off (quickly) 153 | void LiquidCrystal_I2C::noDisplay() { 154 | _displaycontrol &= ~LCD_DISPLAYON; 155 | command(LCD_DISPLAYCONTROL | _displaycontrol); 156 | } 157 | void LiquidCrystal_I2C::display() { 158 | _displaycontrol |= LCD_DISPLAYON; 159 | command(LCD_DISPLAYCONTROL | _displaycontrol); 160 | } 161 | 162 | // Turns the underline cursor on/off 163 | void LiquidCrystal_I2C::noCursor() { 164 | _displaycontrol &= ~LCD_CURSORON; 165 | command(LCD_DISPLAYCONTROL | _displaycontrol); 166 | } 167 | void LiquidCrystal_I2C::cursor() { 168 | _displaycontrol |= LCD_CURSORON; 169 | command(LCD_DISPLAYCONTROL | _displaycontrol); 170 | } 171 | 172 | // Turn on and off the blinking cursor 173 | void LiquidCrystal_I2C::noBlink() { 174 | _displaycontrol &= ~LCD_BLINKON; 175 | command(LCD_DISPLAYCONTROL | _displaycontrol); 176 | } 177 | void LiquidCrystal_I2C::blink() { 178 | _displaycontrol |= LCD_BLINKON; 179 | command(LCD_DISPLAYCONTROL | _displaycontrol); 180 | } 181 | 182 | // These commands scroll the display without changing the RAM 183 | void LiquidCrystal_I2C::scrollDisplayLeft(void) { 184 | command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); 185 | } 186 | void LiquidCrystal_I2C::scrollDisplayRight(void) { 187 | command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); 188 | } 189 | 190 | // This is for text that flows Left to Right 191 | void LiquidCrystal_I2C::leftToRight(void) { 192 | _displaymode |= LCD_ENTRYLEFT; 193 | command(LCD_ENTRYMODESET | _displaymode); 194 | } 195 | 196 | // This is for text that flows Right to Left 197 | void LiquidCrystal_I2C::rightToLeft(void) { 198 | _displaymode &= ~LCD_ENTRYLEFT; 199 | command(LCD_ENTRYMODESET | _displaymode); 200 | } 201 | 202 | // This will 'right justify' text from the cursor 203 | void LiquidCrystal_I2C::autoscroll(void) { 204 | _displaymode |= LCD_ENTRYSHIFTINCREMENT; 205 | command(LCD_ENTRYMODESET | _displaymode); 206 | } 207 | 208 | // This will 'left justify' text from the cursor 209 | void LiquidCrystal_I2C::noAutoscroll(void) { 210 | _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; 211 | command(LCD_ENTRYMODESET | _displaymode); 212 | } 213 | 214 | // Allows us to fill the first 8 CGRAM locations 215 | // with custom characters 216 | void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) { 217 | location &= 0x7; // we only have 8 locations 0-7 218 | command(LCD_SETCGRAMADDR | (location << 3)); 219 | for (int i=0; i<8; i++) { 220 | write(charmap[i]); 221 | } 222 | } 223 | 224 | // Turn the (optional) backlight off/on 225 | void LiquidCrystal_I2C::noBacklight(void) { 226 | _backlightval=LCD_NOBACKLIGHT; 227 | expanderWrite(0); 228 | } 229 | 230 | void LiquidCrystal_I2C::backlight(void) { 231 | _backlightval=LCD_BACKLIGHT; 232 | expanderWrite(0); 233 | } 234 | 235 | 236 | 237 | /*********** mid level commands, for sending data/cmds */ 238 | 239 | inline void LiquidCrystal_I2C::command(uint8_t value) { 240 | send(value, 0); 241 | } 242 | 243 | 244 | /************ low level data pushing commands **********/ 245 | 246 | // write either command or data 247 | void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) { 248 | uint8_t highnib=value&0xf0; 249 | uint8_t lownib=(value<<4)&0xf0; 250 | write4bits((highnib)|mode); 251 | write4bits((lownib)|mode); 252 | } 253 | 254 | void LiquidCrystal_I2C::write4bits(uint8_t value) { 255 | expanderWrite(value); 256 | pulseEnable(value); 257 | } 258 | 259 | void LiquidCrystal_I2C::expanderWrite(uint8_t _data){ 260 | Wire.beginTransmission(_Addr); 261 | printIIC((int)(_data) | _backlightval); 262 | Wire.endTransmission(); 263 | } 264 | 265 | void LiquidCrystal_I2C::pulseEnable(uint8_t _data){ 266 | expanderWrite(_data | En); // En high 267 | delayMicroseconds(1); // enable pulse must be >450ns 268 | 269 | expanderWrite(_data & ~En); // En low 270 | delayMicroseconds(50); // commands need > 37us to settle 271 | } 272 | 273 | 274 | // Alias functions 275 | 276 | void LiquidCrystal_I2C::cursor_on(){ 277 | cursor(); 278 | } 279 | 280 | void LiquidCrystal_I2C::cursor_off(){ 281 | noCursor(); 282 | } 283 | 284 | void LiquidCrystal_I2C::blink_on(){ 285 | blink(); 286 | } 287 | 288 | void LiquidCrystal_I2C::blink_off(){ 289 | noBlink(); 290 | } 291 | 292 | void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows){ 293 | createChar(char_num, rows); 294 | } 295 | 296 | void LiquidCrystal_I2C::setBacklight(uint8_t new_val){ 297 | if(new_val){ 298 | backlight(); // turn backlight on 299 | }else{ 300 | noBacklight(); // turn backlight off 301 | } 302 | } 303 | 304 | void LiquidCrystal_I2C::printstr(const char c[]){ 305 | //This function is not identical to the function used for "real" I2C displays 306 | //it's here so the user sketch doesn't have to be changed 307 | print(c); 308 | } 309 | 310 | 311 | // unsupported API functions 312 | void LiquidCrystal_I2C::off(){} 313 | void LiquidCrystal_I2C::on(){} 314 | void LiquidCrystal_I2C::setDelay (int cmdDelay,int charDelay) {} 315 | uint8_t LiquidCrystal_I2C::status(){return 0;} 316 | uint8_t LiquidCrystal_I2C::keypad (){return 0;} 317 | uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype){return 0;} 318 | void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end){} 319 | void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_row_end){} 320 | void LiquidCrystal_I2C::setContrast(uint8_t new_val){} 321 | 322 | -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/LiquidCrystal_I2C.h: -------------------------------------------------------------------------------- 1 | //YWROBOT 2 | #ifndef LiquidCrystal_I2C_h 3 | #define LiquidCrystal_I2C_h 4 | 5 | #include 6 | #include "Print.h" 7 | #include 8 | 9 | // commands 10 | #define LCD_CLEARDISPLAY 0x01 11 | #define LCD_RETURNHOME 0x02 12 | #define LCD_ENTRYMODESET 0x04 13 | #define LCD_DISPLAYCONTROL 0x08 14 | #define LCD_CURSORSHIFT 0x10 15 | #define LCD_FUNCTIONSET 0x20 16 | #define LCD_SETCGRAMADDR 0x40 17 | #define LCD_SETDDRAMADDR 0x80 18 | 19 | // flags for display entry mode 20 | #define LCD_ENTRYRIGHT 0x00 21 | #define LCD_ENTRYLEFT 0x02 22 | #define LCD_ENTRYSHIFTINCREMENT 0x01 23 | #define LCD_ENTRYSHIFTDECREMENT 0x00 24 | 25 | // flags for display on/off control 26 | #define LCD_DISPLAYON 0x04 27 | #define LCD_DISPLAYOFF 0x00 28 | #define LCD_CURSORON 0x02 29 | #define LCD_CURSOROFF 0x00 30 | #define LCD_BLINKON 0x01 31 | #define LCD_BLINKOFF 0x00 32 | 33 | // flags for display/cursor shift 34 | #define LCD_DISPLAYMOVE 0x08 35 | #define LCD_CURSORMOVE 0x00 36 | #define LCD_MOVERIGHT 0x04 37 | #define LCD_MOVELEFT 0x00 38 | 39 | // flags for function set 40 | #define LCD_8BITMODE 0x10 41 | #define LCD_4BITMODE 0x00 42 | #define LCD_2LINE 0x08 43 | #define LCD_1LINE 0x00 44 | #define LCD_5x10DOTS 0x04 45 | #define LCD_5x8DOTS 0x00 46 | 47 | // flags for backlight control 48 | #define LCD_BACKLIGHT 0x08 49 | #define LCD_NOBACKLIGHT 0x00 50 | 51 | #define En B00000100 // Enable bit 52 | #define Rw B00000010 // Read/Write bit 53 | #define Rs B00000001 // Register select bit 54 | 55 | class LiquidCrystal_I2C : public Print { 56 | public: 57 | LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows); 58 | void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS ); 59 | void clear(); 60 | void home(); 61 | void noDisplay(); 62 | void display(); 63 | void noBlink(); 64 | void blink(); 65 | void noCursor(); 66 | void cursor(); 67 | void scrollDisplayLeft(); 68 | void scrollDisplayRight(); 69 | void printLeft(); 70 | void printRight(); 71 | void leftToRight(); 72 | void rightToLeft(); 73 | void shiftIncrement(); 74 | void shiftDecrement(); 75 | void noBacklight(); 76 | void backlight(); 77 | void autoscroll(); 78 | void noAutoscroll(); 79 | void createChar(uint8_t, uint8_t[]); 80 | void setCursor(uint8_t, uint8_t); 81 | #if defined(ARDUINO) && ARDUINO >= 100 82 | virtual size_t write(uint8_t); 83 | #else 84 | virtual void write(uint8_t); 85 | #endif 86 | void command(uint8_t); 87 | void init(); 88 | 89 | ////compatibility API function aliases 90 | void blink_on(); // alias for blink() 91 | void blink_off(); // alias for noBlink() 92 | void cursor_on(); // alias for cursor() 93 | void cursor_off(); // alias for noCursor() 94 | void setBacklight(uint8_t new_val); // alias for backlight() and nobacklight() 95 | void load_custom_character(uint8_t char_num, uint8_t *rows); // alias for createChar() 96 | void printstr(const char[]); 97 | 98 | ////Unsupported API functions (not implemented in this library) 99 | uint8_t status(); 100 | void setContrast(uint8_t new_val); 101 | uint8_t keypad(); 102 | void setDelay(int,int); 103 | void on(); 104 | void off(); 105 | uint8_t init_bargraph(uint8_t graphtype); 106 | void draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end); 107 | void draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len, uint8_t pixel_col_end); 108 | 109 | 110 | private: 111 | void init_priv(); 112 | void send(uint8_t, uint8_t); 113 | void write4bits(uint8_t); 114 | void expanderWrite(uint8_t); 115 | void pulseEnable(uint8_t); 116 | uint8_t _Addr; 117 | uint8_t _displayfunction; 118 | uint8_t _displaycontrol; 119 | uint8_t _displaymode; 120 | uint8_t _numlines; 121 | uint8_t _cols; 122 | uint8_t _rows; 123 | uint8_t _backlightval; 124 | }; 125 | 126 | #endif 127 | -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/LiquidCrystal_I2C.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/M0IFA/Concept/f28b3da07fd09a6e1b3e8fd6d476d854d45b7774/libraries/LiquidCrystal_I2C/LiquidCrystal_I2C.o -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/diff.txt: -------------------------------------------------------------------------------- 1 | 1,6c1 2 | < //YWROBOT 3 | < //last updated on 26/11/2010 4 | < //Tim Starling Fix the reset bug (Thanks Tim) 5 | < //wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063) 6 | < //Support Forum: http://www.dfrobot.com/forum/ 7 | < 8 | --- 9 | > // LiquidCrystal_I2C V2.0 10 | 10d4 11 | < #include "WProgram.h" 12 | 12c6 13 | < 14 | --- 15 | > #include "Arduino.h" 16 | 67c61 17 | < delay(50); 18 | --- 19 | > delayMicroseconds(50000); 20 | 77,90c71,84 21 | < // we start in 8bit mode, try to set 4 bit mode 22 | < write4bits(0x03 << 4); 23 | < delayMicroseconds(4500); // wait min 4.1ms 24 | < 25 | < // second try 26 | < write4bits(0x03 << 4); 27 | < delayMicroseconds(4500); // wait min 4.1ms 28 | < 29 | < // third go! 30 | < write4bits(0x03 << 4); 31 | < delayMicroseconds(150); 32 | < 33 | < // finally, set to 4-bit interface 34 | < write4bits(0x02 << 4); 35 | --- 36 | > // we start in 8bit mode, try to set 4 bit mode 37 | > write4bits(0x03); 38 | > delayMicroseconds(4500); // wait min 4.1ms 39 | > 40 | > // second try 41 | > write4bits(0x03); 42 | > delayMicroseconds(4500); // wait min 4.1ms 43 | > 44 | > // third go! 45 | > write4bits(0x03); 46 | > delayMicroseconds(150); 47 | > 48 | > // finally, set to 4-bit interface 49 | > write4bits(0x02); 50 | 225c219 51 | < inline void LiquidCrystal_I2C::write(uint8_t value) { 52 | --- 53 | > inline size_t LiquidCrystal_I2C::write(uint8_t value) { 54 | 226a221 55 | > return 0; 56 | 235,238c230,233 57 | < uint8_t highnib=value&0xf0; 58 | < uint8_t lownib=(value<<4)&0xf0; 59 | < write4bits((highnib)|mode); 60 | < write4bits((lownib)|mode); 61 | --- 62 | > uint8_t highnib=value>>4; 63 | > uint8_t lownib=value & 0x0F; 64 | > write4bits((highnib)|mode); 65 | > write4bits((lownib)|mode); 66 | 248c243 67 | < Wire.send((int)(_data) | _backlightval); 68 | --- 69 | > Wire.write((int)(_data) | _backlightval); 70 | -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/examples/CustomChars/CustomChars.pde: -------------------------------------------------------------------------------- 1 | //YWROBOT 2 | //Compatible with the Arduino IDE 1.0 3 | //Library version:1.1 4 | #include 5 | #include 6 | 7 | #if defined(ARDUINO) && ARDUINO >= 100 8 | #define printByte(args) write(args); 9 | #else 10 | #define printByte(args) print(args,BYTE); 11 | #endif 12 | 13 | uint8_t bell[8] = {0x4,0xe,0xe,0xe,0x1f,0x0,0x4}; 14 | uint8_t note[8] = {0x2,0x3,0x2,0xe,0x1e,0xc,0x0}; 15 | uint8_t clock[8] = {0x0,0xe,0x15,0x17,0x11,0xe,0x0}; 16 | uint8_t heart[8] = {0x0,0xa,0x1f,0x1f,0xe,0x4,0x0}; 17 | uint8_t duck[8] = {0x0,0xc,0x1d,0xf,0xf,0x6,0x0}; 18 | uint8_t check[8] = {0x0,0x1,0x3,0x16,0x1c,0x8,0x0}; 19 | uint8_t cross[8] = {0x0,0x1b,0xe,0x4,0xe,0x1b,0x0}; 20 | uint8_t retarrow[8] = { 0x1,0x1,0x5,0x9,0x1f,0x8,0x4}; 21 | 22 | LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display 23 | 24 | void setup() 25 | { 26 | lcd.init(); // initialize the lcd 27 | lcd.backlight(); 28 | 29 | lcd.createChar(0, bell); 30 | lcd.createChar(1, note); 31 | lcd.createChar(2, clock); 32 | lcd.createChar(3, heart); 33 | lcd.createChar(4, duck); 34 | lcd.createChar(5, check); 35 | lcd.createChar(6, cross); 36 | lcd.createChar(7, retarrow); 37 | lcd.home(); 38 | 39 | lcd.print("Hello world..."); 40 | lcd.setCursor(0, 1); 41 | lcd.print(" i "); 42 | lcd.printByte(3); 43 | lcd.print(" arduinos!"); 44 | delay(5000); 45 | displayKeyCodes(); 46 | 47 | } 48 | 49 | // display all keycodes 50 | void displayKeyCodes(void) { 51 | uint8_t i = 0; 52 | while (1) { 53 | lcd.clear(); 54 | lcd.print("Codes 0x"); lcd.print(i, HEX); 55 | lcd.print("-0x"); lcd.print(i+16, HEX); 56 | lcd.setCursor(0, 1); 57 | for (int j=0; j<16; j++) { 58 | lcd.printByte(i+j); 59 | } 60 | i+=16; 61 | 62 | delay(4000); 63 | } 64 | } 65 | 66 | void loop() 67 | { 68 | 69 | } 70 | 71 | -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/examples/HelloWorld/ARD_LCD_HCARDU0023_I2C_Hello_World_Example.ino: -------------------------------------------------------------------------------- 1 | /* FILE: ARD_LCD_HCARDU0023_I2C_Hello_World_Example.pde 2 | DATE: 11/07/12 3 | VERSION: 0.1 4 | 5 | This is a simple example of how to use the Hobby Components I2C LCD module 6 | (HCARDU0023). To use this module you will require the appropriate library 7 | which can be downloaded from the following location: 8 | 9 | http://forum.hobbycomponents.com/arduino_shields_modules 10 | 11 | This code also demonstrates the correct pin assignment for the LCD. When you 12 | run this program you should see a greeting message appear on the display. 13 | 14 | 15 | DEVICE PINOUT (SPI Interface): 16 | 17 | PIN 1: GND 18 | PIN 2: +5V 19 | PIN 3: SDA - Connect to Arduino analogue PIN 4 20 | PIN 4: SCL - Connect to Arduino analogue PIN 5 21 | 22 | 23 | You may copy, alter and reuse this code in any way you like but please leave 24 | reference to hobbycomponents.com in your comments if you redistribute this code. */ 25 | 26 | 27 | /* Include the SPI/IIC Library */ 28 | #include 29 | #include 30 | 31 | 32 | /* Initialise the LiquidCrystal library. The default address is 0x27 and this is a 16x2 line display */ 33 | LiquidCrystal_I2C lcd(0x27,16,2); 34 | 35 | 36 | void setup() 37 | { 38 | /* Initialise the LCD */ 39 | lcd.init(); 40 | lcd.init(); 41 | } 42 | 43 | /* Main program loop */ 44 | void loop() 45 | { 46 | /* Make sure the backlight is turned on */ 47 | lcd.backlight(); 48 | 49 | /* Output the test message to the LCD */ 50 | lcd.setCursor(0,0); 51 | lcd.print("HOBBY COMPONENTS"); 52 | lcd.setCursor(0,1); 53 | lcd.print("**HELLO WORLD**"); 54 | 55 | 56 | /* Do nothing */ 57 | while(1); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/examples/HelloWorld/ARD_LCD_HCARDU0023_I2C_Hello_World_Example.pde: -------------------------------------------------------------------------------- 1 | /* FILE: ARD_LCD_HCARDU0023_I2C_Hello_World_Example.pde 2 | DATE: 11/07/12 3 | VERSION: 0.1 4 | 5 | This is a simple example of how to use the Hobby Components I2C LCD module 6 | (HCARDU0023). To use this module you will require the appropriate library 7 | which can be downloaded from the following location: 8 | 9 | http://forum.hobbycomponents.com/arduino_shields_modules 10 | 11 | This code also demonstrates the correct pin assignment for the LCD. When you 12 | run this program you should see a greeting message appear on the display. 13 | 14 | 15 | DEVICE PINOUT (SPI Interface): 16 | 17 | PIN 1: GND 18 | PIN 2: +5V 19 | PIN 3: SDA - Connect to Arduino analogue PIN 4 20 | PIN 4: SCL - Connect to Arduino analogue PIN 5 21 | 22 | 23 | You may copy, alter and reuse this code in any way you like but please leave 24 | reference to hobbycomponents.com in your comments if you redistribute this code. */ 25 | 26 | 27 | /* Include the SPI/IIC Library */ 28 | #include 29 | #include 30 | 31 | 32 | /* Initialise the LiquidCrystal library. The default address is 0x27 and this is a 16x2 line display */ 33 | LiquidCrystal_I2C lcd(0x27,16,2); 34 | 35 | 36 | void setup() 37 | { 38 | /* Initialise the LCD */ 39 | lcd.init(); 40 | lcd.init(); 41 | } 42 | 43 | /* Main program loop */ 44 | void loop() 45 | { 46 | /* Make sure the backlight is turned on */ 47 | lcd.backlight(); 48 | 49 | /* Output the test message to the LCD */ 50 | lcd.setCursor(0,0); 51 | lcd.print("HOBBY COMPONENTS"); 52 | lcd.setCursor(0,1); 53 | lcd.print("**HELLO WORLD**"); 54 | 55 | 56 | /* Do nothing */ 57 | while(1); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/examples/SerialDisplay/SerialDisplay.pde: -------------------------------------------------------------------------------- 1 | /* 2 | * Displays text sent over the serial port (e.g. from the Serial Monitor) on 3 | * an attached LCD. 4 | * YWROBOT 5 | *Compatible with the Arduino IDE 1.0 6 | *Library version:1.1 7 | */ 8 | #include 9 | #include 10 | 11 | LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display 12 | 13 | void setup() 14 | { 15 | lcd.init(); // initialize the lcd 16 | lcd.backlight(); 17 | Serial.begin(9600); 18 | } 19 | 20 | void loop() 21 | { 22 | // when characters arrive over the serial port... 23 | if (Serial.available()) { 24 | // wait a bit for the entire message to arrive 25 | delay(100); 26 | // clear the screen 27 | lcd.clear(); 28 | // read all the available characters 29 | while (Serial.available() > 0) { 30 | // display each character to the LCD 31 | lcd.write(Serial.read()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /libraries/LiquidCrystal_I2C/keywords.txt: -------------------------------------------------------------------------------- 1 | ########################################### 2 | # Syntax Coloring Map For LiquidCrystal_I2C 3 | ########################################### 4 | 5 | ########################################### 6 | # Datatypes (KEYWORD1) 7 | ########################################### 8 | 9 | LiquidCrystal_I2C KEYWORD1 10 | 11 | ########################################### 12 | # Methods and Functions (KEYWORD2) 13 | ########################################### 14 | init KEYWORD2 15 | begin KEYWORD2 16 | clear KEYWORD2 17 | home KEYWORD2 18 | noDisplay KEYWORD2 19 | display KEYWORD2 20 | noBlink KEYWORD2 21 | blink KEYWORD2 22 | noCursor KEYWORD2 23 | cursor KEYWORD2 24 | scrollDisplayLeft KEYWORD2 25 | scrollDisplayRight KEYWORD2 26 | leftToRight KEYWORD2 27 | rightToLeft KEYWORD2 28 | shiftIncrement KEYWORD2 29 | shiftDecrement KEYWORD2 30 | noBacklight KEYWORD2 31 | backlight KEYWORD2 32 | autoscroll KEYWORD2 33 | noAutoscroll KEYWORD2 34 | createChar KEYWORD2 35 | setCursor KEYWORD2 36 | print KEYWORD2 37 | blink_on KEYWORD2 38 | blink_off KEYWORD2 39 | cursor_on KEYWORD2 40 | cursor_off KEYWORD2 41 | setBacklight KEYWORD2 42 | load_custom_character KEYWORD2 43 | printstr KEYWORD2 44 | ########################################### 45 | # Constants (LITERAL1) 46 | ########################################### 47 | -------------------------------------------------------------------------------- /libraries/Morse_EnDecoder/Morse EnDecoder usage.rtfd/TXT.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1265 2 | {\fonttbl\f0\fswiss\fcharset0 ArialMT;\f1\fnil\fcharset0 Monaco;} 3 | {\colortbl;\red255\green255\blue255;\red115\green0\blue2;\red234\green234\blue234;\red16\green121\blue2; 4 | \red0\green0\blue117;\red83\green85\blue2;\red11\green84\blue83;\red82\green0\blue83;} 5 | {\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid2\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid1} 6 | {\list\listtemplateid2\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid101\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid2} 7 | {\list\listtemplateid3\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid201\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid202\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid3} 8 | {\list\listtemplateid4\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid301\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid302\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid4} 9 | {\list\listtemplateid5\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid401\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid402\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid5} 10 | {\list\listtemplateid6\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid501\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid502\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid6} 11 | {\list\listtemplateid7\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid601\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid602\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid7} 12 | {\list\listtemplateid8\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid701\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid702\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid8} 13 | {\list\listtemplateid9\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid801\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid802\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid9} 14 | {\list\listtemplateid10\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid901\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid902\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid10} 15 | {\list\listtemplateid11\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1001\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid1002\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid11} 16 | {\list\listtemplateid12\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1101\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid1102\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid12} 17 | {\list\listtemplateid13\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1201\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid1202\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid13} 18 | {\list\listtemplateid14\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1301\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{circle\}}{\leveltext\leveltemplateid1302\'01\uc0\u9702 ;}{\levelnumbers;}\fi-360\li1440\lin1440 }{\listname ;}\listid14}} 19 | {\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}{\listoverride\listid3\listoverridecount0\ls3}{\listoverride\listid4\listoverridecount0\ls4}{\listoverride\listid5\listoverridecount0\ls5}{\listoverride\listid6\listoverridecount0\ls6}{\listoverride\listid7\listoverridecount0\ls7}{\listoverride\listid8\listoverridecount0\ls8}{\listoverride\listid9\listoverridecount0\ls9}{\listoverride\listid10\listoverridecount0\ls10}{\listoverride\listid11\listoverridecount0\ls11}{\listoverride\listid12\listoverridecount0\ls12}{\listoverride\listid13\listoverridecount0\ls13}{\listoverride\listid14\listoverridecount0\ls14}} 20 | \paperw11905\paperh16837\margl1011\margr1011\margb1445\margt1011\vieww14000\viewh16000\viewkind1\viewscale108 21 | \deftab720 22 | \pard\pardeftab720\sa321 23 | 24 | \f0\b\fs48 \cf0 Morse EnDecoder usage\ 25 | \pard\pardeftab720\sa298 26 | 27 | \fs36 \cf0 Installation\ 28 | \pard\pardeftab720\sa262 29 | 30 | \b0\fs26 \cf0 Just extract the folder from the archive and put it in your Arduino libraries folder, the one located in your sketch folder.\ 31 | \pard\pardeftab720\sa298 32 | 33 | \b\fs36 \cf0 Instantiating a Morse decoder or encoder object\ 34 | \pard\pardeftab720 35 | 36 | \fs32 \cf0 For the Morse decoder\ 37 | \pard\pardeftab720\sa262 38 | 39 | \fs26 \cf0 morseDecoder objectname(input pin nr, input type, input logic); 40 | \b0 \ 41 | Where\ 42 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 43 | \ls1\ilvl0\cf0 {\listtext \'95 }objectname is a name for the morse decoder object\ 44 | {\listtext \'95 }input pin nr. is which Arduino pin used for Morse signal input\ 45 | {\listtext \'95 }input type is:\ 46 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 47 | \ls1\ilvl1\cf0 {\listtext \uc0\u9702 }MORSE_KEYER - for a digital input (like a push button).\ 48 | {\listtext \uc0\u9702 }MORSE_AUDIO - for an analog input (Morse audio signal).\ 49 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 50 | \ls1\ilvl0\cf0 {\listtext \'95 }input logic is:\ 51 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 52 | \ls1\ilvl1\cf0 {\listtext \uc0\u9702 }MORSE_ACTIVE_LOW - will also use the internal pull-up resistor.\ 53 | {\listtext \uc0\u9702 }MORSE_ACTIVE_HIGH - for "normal logic" signals.\ 54 | \pard\pardeftab720\sa262 55 | \cf0 \ 56 | \pard\pardeftab720\sa262 57 | 58 | \b \cf0 Note 59 | \b0 The input pin nr differs between each type of input, IE digital 3 is not the same as analog 3.\ 60 | \pard\pardeftab720 61 | 62 | \b\fs32 \cf0 For the Morse encoder\ 63 | \pard\pardeftab720\sa262 64 | 65 | \fs26 \cf0 morseEncoder objectname(output pin nr); 66 | \b0 \ 67 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 68 | \ls2\ilvl0\cf0 {\listtext \'95 }It only needs one argument, which Arduno pin to use as an output.\ 69 | \pard\pardeftab720\sa298 70 | 71 | \b\fs36 \cf0 Functions or methods\ 72 | \pard\pardeftab720 73 | 74 | \fs32 \cf0 Morse Decoder\ 75 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 76 | \ls3\ilvl0 77 | \b0\fs26 \cf0 {\listtext \'95 }objectname.decode();\ 78 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 79 | \ls3\ilvl1\cf0 {\listtext \uc0\u9702 }Returns nothing. This needs to be called at least once every main loop in the decoding process.\ 80 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 81 | \ls4\ilvl0\cf0 {\listtext \'95 }objectname.available();\ 82 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 83 | \ls4\ilvl1\cf0 {\listtext \uc0\u9702 }Returns boolean true or false, depending on whether or not a Morse code character is decoded (received).\ 84 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 85 | \ls5\ilvl0\cf0 {\listtext \'95 }objectname.read();\ 86 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 87 | \ls5\ilvl1\cf0 {\listtext \uc0\u9702 }Returns a char, the last morse code character received and decoded. This only contains the last character decoded, until it is read.\ 88 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 89 | \ls6\ilvl0\cf0 {\listtext \'95 }objectname.setspeed();\ 90 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 91 | \ls6\ilvl1\cf0 {\listtext \uc0\u9702 }Returns nothing. Sets the Morse speed in wpm (words per minute). If this method is not called, a default wpm of 13 is used.\ 92 | \pard\pardeftab720\sa345 93 | 94 | \b \cf0 Members\ 95 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 96 | \ls7\ilvl0 97 | \b0 \cf0 {\listtext \'95 }objectname.debounceDelay\ 98 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 99 | \ls7\ilvl1\cf0 {\listtext \uc0\u9702 }Sets or returns the debounce timer for the digital input signal. Keep well below the time for a Morse dot (dot time in ms = 1200/wpm).\ 100 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 101 | \ls8\ilvl0\cf0 {\listtext \'95 }objectname.AudioThreshold\ 102 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 103 | \ls8\ilvl1\cf0 {\listtext \uc0\u9702 }Sets or returns the threshold used for analog input. It is a simple clipping filter setting.\ 104 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 105 | \ls9\ilvl0\cf0 {\listtext \'95 }obectname.morseSignalState\ 106 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 107 | \ls9\ilvl1\cf0 {\listtext \uc0\u9702 }Returns (or sets, but of no use) the current state of the input Morse signal.\ 108 | \pard\pardeftab720 109 | 110 | \b\fs32 \cf0 Morse Encoder\ 111 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 112 | \ls10\ilvl0 113 | \b0\fs26 \cf0 {\listtext \'95 }objectname.encode();\ 114 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 115 | \ls10\ilvl1\cf0 {\listtext \uc0\u9702 }Returns nothing. This needs to be called at least once every main loop during the encoding process.\ 116 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 117 | \ls11\ilvl0\cf0 {\listtext \'95 }objectname.available();\ 118 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 119 | \ls11\ilvl1\cf0 {\listtext \uc0\u9702 }Returns boolean true or false, depending on whether or not it is ready to receive the next Morse code character to encode and send.\ 120 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 121 | \ls12\ilvl0\cf0 {\listtext \'95 }objectname.write();\ 122 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 123 | \ls12\ilvl1\cf0 {\listtext \uc0\u9702 }Returns nothing. Sets the next character to encode and send. The output pin is then toggled in Morse code (if subsequent calls to the .encode method is used).\ 124 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 125 | \ls13\ilvl0\cf0 {\listtext \'95 }objectname.setspeed();\ 126 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 127 | \ls13\ilvl1\cf0 {\listtext \uc0\u9702 }Returns nothing. Sets the Morse speed in wpm (words per minute). If this method is not called, a default wpm of 13 is used.\ 128 | \pard\pardeftab720\sa345 129 | 130 | \b \cf0 Members\ 131 | \pard\tx220\tx720\pardeftab720\li720\fi-720\sa78 132 | \ls14\ilvl0 133 | \b0 \cf0 {\listtext \'95 }objectname.morseSignalString\ 134 | \pard\tx940\tx1440\pardeftab720\li1440\fi-1440\sa78 135 | \ls14\ilvl1\cf0 {\listtext \uc0\u9702 }Returns a C-type string with the encoded Morse signals as ASCII dots or dashes, for sending Morse.\ 136 | {\listtext \uc0\u9702 }Note that this string will be destroyed while sending the Morse, so if you want to use it, you must read it at once after sending a character with the write() method.\ 137 | \pard\pardeftab720\sa321 138 | 139 | \b\fs48 \cf0 Example\ 140 | \pard\pardeftab720\sa262 141 | 142 | \b0\fs26 \cf0 This example takes a Morse signal on digital input pin 7, decodes it and write the text to the serial output. The input is active-low, hence it will also use the internal pull-up resistor.\ 143 | It also takes text received on the serial interface, and encodes it to the digital output pin nr. 13. It also shows the letters and morse code back on the serial output.\ 144 | If no morse code is being sent, it also use the output pin to show the debounced input.\ 145 | This example also comes with the library.\ 146 | \pard\pardeftab720 147 | 148 | \f1\fs24 \cf2 \cb3 #include\cf0 \cf4 "MorseEnDecoder.h"\cf0 \ 149 | \ 150 | \ 151 | \pard\pardeftab720 152 | \cf5 int\cf0 morseInPin \cf6 =\cf0 \cf7 7\cf6 ;\cf0 \'a0 \'a0 \'a0\ 153 | \cf5 int\cf0 morseOutPin \cf6 =\cf0 \cf7 13\cf6 ;\cf0 \ 154 | \ 155 | morseDecoder morseInput\cf6 (\cf0 morseInPin\cf6 ,\cf0 MORSE_KEYER\cf6 ,\cf0 MORSE_ACTIVE_LOW\cf6 );\cf0 \ 156 | morseEncoder morseOutput\cf6 (\cf0 morseOutPin\cf6 );\cf0 \ 157 | \ 158 | \ 159 | \cf5 void\cf0 setup\cf6 ()\cf0 \ 160 | \cf6 \{\cf0 \ 161 | \'a0 \cf8 Serial\cf6 .\cf5 begin\cf6 (\cf7 9600\cf6 );\cf0 \ 162 | \'a0 \cf8 Serial\cf6 .\cf0 println\cf6 (\cf4 "Morse EnDecoder demo"\cf6 );\cf0 \ 163 | \'a0 \ 164 | \'a0 \cf2 // Setting Morse speed in wpm - words per minute\cf0 \ 165 | \'a0 \cf2 // If not set, 13 wpm is default\cf0 \ 166 | \'a0 morseInput\cf6 .\cf0 setspeed\cf6 (\cf7 13\cf6 );\cf0 \ 167 | \'a0 morseOutput\cf6 .\cf0 setspeed\cf6 (\cf7 13\cf6 );\cf0 \ 168 | \cf6 \}\cf0 \ 169 | \ 170 | \ 171 | \ 172 | \cf5 void\cf0 loop\cf6 ()\cf0 \ 173 | \cf6 \{\cf0 \ 174 | \'a0 \cf2 // Needs to call these once per loop\cf0 \ 175 | \'a0 morseInput\cf6 .\cf0 decode\cf6 ();\cf0 \ 176 | \'a0 morseOutput\cf6 .\cf0 encode\cf6 ();\cf0 \ 177 | \ 178 | \ 179 | \'a0 \cf2 // Morse output:\cf0 \ 180 | \'a0 \cf2 // Encoding text received from the serial input\cf0 \ 181 | \'a0 \cf5 if\cf0 \cf6 (\cf8 Serial\cf6 .\cf0 available\cf6 ()\cf0 \cf6 &&\cf0 morseOutput\cf6 .\cf0 available\cf6 ())\cf0 \ 182 | \'a0 \cf6 \{\cf0 \ 183 | \'a0 \'a0 \cf5 char\cf0 sendMorse \cf6 =\cf0 \cf8 Serial\cf6 .\cf0 read\cf6 ();\cf0 \ 184 | \'a0 \'a0 morseOutput\cf6 .\cf0 write\cf6 (\cf0 sendMorse\cf6 );\cf0 \ 185 | \'a0 \'a0 \ 186 | \'a0 \'a0 \cf2 // Also write it back to serial\cf0 \ 187 | \'a0 \'a0 morseOutput\cf6 .\cf0 encode\cf6 ();\cf0 \'a0 \'a0\cf2 // This is just to get morseSignalString before it is destroyed\cf0 \ 188 | \'a0 \'a0 \cf8 Serial\cf6 .\cf0 write\cf6 (\cf4 ' '\cf6 );\cf0 \ 189 | \'a0 \'a0 \cf8 Serial\cf6 .\cf0 write\cf6 (\cf0 sendMorse\cf6 );\cf0 \ 190 | \'a0 \'a0 \cf8 Serial\cf6 .\cf0 write\cf6 (\cf0 morseOutput\cf6 .\cf0 morseSignalString\cf6 );\cf0 \ 191 | \'a0 \cf6 \}\cf0 \ 192 | \ 193 | \'a0 \cf2 // Morse input:\cf0 \ 194 | \'a0 \cf2 // If a character is decoded from the input, write it to serial output\cf0 \ 195 | \'a0 \cf5 if\cf0 \cf6 (\cf0 morseInput\cf6 .\cf0 available\cf6 ())\cf0 \ 196 | \'a0 \cf6 \{\cf0 \ 197 | \'a0 \'a0 \cf5 char\cf0 receivedMorse \cf6 =\cf0 morseInput\cf6 .\cf0 read\cf6 ();\cf0 \ 198 | \'a0 \'a0 \cf8 Serial\cf6 .\cf5 print\cf6 (\cf0 receivedMorse\cf6 );\cf0 \ 199 | \'a0 \'a0 \ 200 | \'a0 \'a0 \cf2 // A little error checking \'a0 \'a0\cf0 \ 201 | \'a0 \'a0 \cf5 if\cf0 \cf6 (\cf0 receivedMorse \cf6 ==\cf0 \cf4 '#'\cf6 )\cf0 \cf8 Serial\cf6 .\cf0 println\cf6 (\cf4 "< ERROR:too many morse signals! >"\cf6 );\cf0 \ 202 | \'a0 \cf6 \}\cf0 \ 203 | \ 204 | \ 205 | \'a0 \cf2 // Morse feedback from input if not sending Morse.\cf0 \ 206 | \'a0 \cf5 if\cf0 \cf6 (\cf0 morseOutput\cf6 .\cf0 available\cf6 ())\cf0 digitalWrite\cf6 (\cf0 morseOutPin\cf6 ,\cf0 morseInput\cf6 .\cf0 morseSignalState\cf6 );\cf0 \ 207 | \cf6 \}{\*\beandata789c9d935d6f82301486aff157748db752d876b12d8851c1c4cc2099b86497153a65e32ba5cef1ef57444aeb66b68c1bda73fabe4f7b4e6b8d3ed3047c105ac6793684a66e4040b2308fe26c3b84eb6036b88323bb675d39cb69f0e2bba048e292017f3d59cca7000e101a17454210720207f88bf92a00dc0321d78300ee182b1e103a1c0e3aae57e9619ed60b4be4d3bc2094550b6e36e0023d6211e498c65dd90e8f4671c8ec9e66bd93caee631aee62bec242f594474b46f9666d6ff5482a128d45fa146f75f9e68d84ac14324c29ae07c2a09fed934492692d573b3984092e855e4e37f9e9acbf9e3b5d5eb3e28c912da1f6ad85dae1518854636fa5f39fec2cf6a6502e603aceb5ca5140a8f36ca16715f93ff7e64fdc2eda567ce28ebd27f6ead6f78d778ef1e866cf48f9dcf4dfdba71ba591d2490dd334ee0df5c03ff68b5c3a9fb8360e57711aa6958c92572c8f8552b2dfead9d0329c1289f70b4354a4736bbc585e887b2a8a56cf2704670e665830cece7cde24513053ad540756ded6e9e109b6501bf52759b43a0b1d5facddfb02aa1d4161}} -------------------------------------------------------------------------------- /libraries/Morse_EnDecoder/MorseEnDecoder.cpp: -------------------------------------------------------------------------------- 1 | /* MORSE ENDECODER 2 | 3 | - Morse encoder / decoder classes for the Arduino. 4 | 5 | Copyright (C) 2010-2012 raron 6 | 7 | GNU GPLv3 license: 8 | 9 | This program is free software: you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation, either version 3 of the License, or 12 | (at your option) any later version. 13 | 14 | This program is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | GNU General Public License for more details. 18 | 19 | You should have received a copy of the GNU General Public License 20 | along with this program. If not, see . 21 | 22 | 23 | Contact: raronzen@gmail.com 24 | Details: http://raronoff.wordpress.com/2010/12/16/morse-endecoder/ 25 | 26 | TODO: 27 | - have this table in PROGMEM! DONE! 28 | - Get rid of debounce for keying input - *NOT DONE* was needed! 29 | - Use micros() for faster timings 30 | - use different defines for different morse code tables, up to including 9-signal SOS etc 31 | - Speed auto sense? (unlikely, but would be nice). 32 | - Serial command parser example sketch (to change speed and settings etc) 33 | - LOOK AT UNDERSCORE SEND-BUG (is sent as questionmark)! *DONE* Fixed! 34 | 35 | 36 | History: 37 | 2012.11.22 - Debugged the _underscore_ problem, it got "uppercased" to a 38 | question mark. Also, included ampersand (&) 39 | 2012.11.20 - Finally moved table to PROGMEM! Cleaned up header comments a bit. 40 | 2012.11.10 - Fixed minor bug: pinMode for the Morse output pin (thanks Rezoss!) 41 | 2012.01.31 - Tiny update for Arduino 1.0. Fixed header comments. 42 | 2010.12.06 - Cleaned up code a bit. 43 | Added the "MN digraph" ---. for alternate exclamation mark(!). 44 | Still encoded as the "KW digraph" -.-.-- though. 45 | 2010.12.04 - Program changed to use (Decode and Encode) classes instead. 46 | 2010.12.02 - Changed back to signed timers to avoid overflow. 47 | 2010.11.30 - Morse punctuation added (except $ - the dollar sign). 48 | 2010.11.29 - Added echo on/off command. 49 | 2010.11.28 - Added simple Morse audio clipping filter + Command parser. 50 | 2010.11.27 - Added Morse encoding via reverse-dichotomic path tracing. 51 | Thus using the same Morse tree for encoding and decoding. 52 | 2010.11.11 - Complete Rewrite for the Arduino. 53 | 1992.01.06 - My old rather unknown "Morse decoder 3.5" for Amiga 600. 54 | A 68000 Assembler version using a binary tree for Morse 55 | decoding only, of which this is based on. 56 | */ 57 | 58 | #include "MorseEnDecoder.h" 59 | 60 | // Morse code binary tree table (or, dichotomic search table) 61 | 62 | // ITU - International Morse code table only 63 | //const int morseTreetop = 31; 64 | //char morseTable[] = "5H4S?V3I?F?U??2E?L?R???A?P?W?J1 6B?D?X?N?C?K?Y?T7Z?G?Q?M8??O9?0"; 65 | 66 | 67 | // ITU with punctuation (but without non-english characters - for now) 68 | const int morseTreetop = 63; 69 | const char morseTable[] PROGMEM = "*5*H*4*S***V*3*I***F***U?*_**2*E*&*L\"**R*+.****A***P@**W***J'1* *6-B*=*D*/" 70 | "*X***N***C;*!K*()Y***T*7*Z**,G***Q***M:8*!***O*9***0*"; 71 | 72 | 73 | const int morseTableLength = (morseTreetop*2)+1; 74 | const int morseTreeLevels = log(morseTreetop+1)/log(2); 75 | 76 | 77 | 78 | morseDecoder::morseDecoder(int decodePin, boolean listenAudio, boolean morsePullup) 79 | { 80 | morseInPin = decodePin; 81 | morseAudio = listenAudio; 82 | activeLow = morsePullup; 83 | 84 | if (morseAudio == false) 85 | { 86 | pinMode(morseInPin, INPUT); 87 | if (activeLow) digitalWrite (morseInPin, HIGH); 88 | } 89 | 90 | // Some initial values 91 | wpm = 13; 92 | AudioThreshold = 700; 93 | debounceDelay = 20; 94 | dotTime = 1200 / wpm; // morse dot time length in ms 95 | dashTime = 3 * 1200 / wpm; 96 | wordSpace = 7 * 1200 / wpm; 97 | 98 | morseTableJumper = (morseTreetop+1)/2; 99 | morseTablePointer = morseTreetop; 100 | 101 | morseKeyer = LOW; 102 | morseSignalState = LOW; 103 | lastKeyerState = LOW; 104 | 105 | gotLastSig = true; 106 | morseSpace = true; 107 | decodedMorseChar = '\0'; 108 | 109 | lastDebounceTime = 0; 110 | markTime = 0; 111 | spaceTime = 0; 112 | } 113 | 114 | 115 | 116 | void morseDecoder::setspeed(int value) 117 | { 118 | wpm = value; 119 | if (wpm <= 0) wpm = 1; 120 | dotTime = 1200 / wpm; 121 | dashTime = 3 * 1200 / wpm; 122 | wordSpace = 7 * 1200 / wpm; 123 | } 124 | 125 | 126 | 127 | boolean morseDecoder::available() 128 | { 129 | if (decodedMorseChar) return true; else return false; 130 | } 131 | 132 | 133 | 134 | char morseDecoder::read() 135 | { 136 | char temp = decodedMorseChar; 137 | decodedMorseChar = '\0'; 138 | return temp; 139 | } 140 | 141 | 142 | 143 | 144 | 145 | morseEncoder::morseEncoder(int encodePin) 146 | { 147 | morseOutPin = encodePin; 148 | pinMode(morseOutPin, OUTPUT); 149 | 150 | // some initial values 151 | digitalWrite (morseOutPin, LOW); 152 | sendingMorse = false; 153 | encodeMorseChar = '\0'; 154 | 155 | wpm = 13; 156 | dotTime = 1200 / wpm; // morse dot time length in ms 157 | dashTime = 3 * 1200 / wpm; 158 | wordSpace = 7 * 1200 / wpm; 159 | 160 | } 161 | 162 | 163 | 164 | void morseEncoder::setspeed(int value) 165 | { 166 | wpm = value; 167 | if (wpm <= 0) wpm = 1; 168 | dotTime = 1200 / wpm; 169 | dashTime = 3 * 1200 / wpm; 170 | wordSpace = 7 * 1200 / wpm; 171 | } 172 | 173 | 174 | 175 | boolean morseEncoder::available() 176 | { 177 | if (sendingMorse) return false; else return true; 178 | } 179 | 180 | 181 | 182 | void morseEncoder::write(char temp) 183 | { 184 | if (!sendingMorse && temp != '*') encodeMorseChar = temp; 185 | } 186 | 187 | 188 | 189 | 190 | 191 | void morseDecoder::decode() 192 | { 193 | currentTime = millis(); 194 | 195 | // Read Morse signals 196 | if (morseAudio == false) 197 | { 198 | // Read the Morse keyer (digital) 199 | morseKeyer = digitalRead(morseInPin); 200 | if (activeLow) morseKeyer = !morseKeyer; 201 | 202 | // If the switch changed, due to noise or pressing: 203 | if (morseKeyer != lastKeyerState) lastDebounceTime = currentTime; // reset timer 204 | 205 | // debounce the morse keyer 206 | if ((currentTime - lastDebounceTime) > debounceDelay) 207 | { 208 | // whatever the reading is at, it's been there for longer 209 | // than the debounce delay, so take it as the actual current state: 210 | morseSignalState = morseKeyer; 211 | 212 | // differentiante mark and space times 213 | if (morseSignalState) markTime = lastDebounceTime; 214 | else spaceTime = lastDebounceTime; 215 | } 216 | } else { 217 | // Read Morse audio signal 218 | audioSignal = analogRead(morseInPin); 219 | if (audioSignal > AudioThreshold) 220 | { 221 | // If this is a new morse signal, reset morse signal timer 222 | if (currentTime - lastDebounceTime > dotTime/2) 223 | { 224 | markTime = currentTime; 225 | morseSignalState = true; // there is currently a Morse signal 226 | } 227 | lastDebounceTime = currentTime; 228 | } else { 229 | // if this is a new pause, reset space time 230 | if (currentTime - lastDebounceTime > dotTime/2 && morseSignalState == true) 231 | { 232 | spaceTime = lastDebounceTime; // not too far off from last received audio 233 | morseSignalState = false; // No more signal 234 | } 235 | } 236 | } 237 | 238 | 239 | 240 | // Decode morse code 241 | if (!morseSignalState) 242 | { 243 | if (!gotLastSig) 244 | { 245 | if (morseTableJumper > 0) 246 | { 247 | // if pause for more than half a dot, get what kind of signal pulse (dot/dash) received last 248 | if (currentTime - spaceTime > dotTime/2) 249 | { 250 | // if signal for more than 1/4 dotTime, take it as a morse pulse 251 | if (spaceTime-markTime > dotTime/4) 252 | { 253 | // if signal for less than half a dash, take it as a dot 254 | if (spaceTime-markTime < dashTime/2) 255 | { 256 | morseTablePointer -= morseTableJumper; 257 | morseTableJumper /= 2; 258 | gotLastSig = true; 259 | } 260 | // else if signal for between half a dash and a dash + one dot (1.33 dashes), take as a dash 261 | else if (spaceTime-markTime < dashTime + dotTime) 262 | { 263 | morseTablePointer += morseTableJumper; 264 | morseTableJumper /= 2; 265 | gotLastSig = true; 266 | } 267 | } 268 | } 269 | } else { // error if too many pulses in one morse character 270 | //Serial.println(""); 271 | decodedMorseChar = '#'; // error mark 272 | gotLastSig = true; 273 | morseTableJumper = (morseTreetop+1)/2; 274 | morseTablePointer = morseTreetop; 275 | } 276 | } 277 | // Write out the character if pause is longer than 2/3 dash time (2 dots) and a character received 278 | if ((currentTime-spaceTime >= (dotTime*2)) && (morseTableJumper < ((morseTreetop+1)/2))) 279 | { 280 | decodedMorseChar = pgm_read_byte_near(morseTable + morseTablePointer); 281 | morseTableJumper = (morseTreetop+1)/2; 282 | morseTablePointer = morseTreetop; 283 | } 284 | // Write a space if pause is longer than 2/3rd wordspace 285 | if (currentTime-spaceTime > (wordSpace*2/3) && morseSpace == false) 286 | { 287 | //Serial.print(" "); 288 | decodedMorseChar = ' '; 289 | morseSpace = true ; // space written-flag 290 | } 291 | 292 | } else { 293 | // while there is a signal, reset some flags 294 | gotLastSig = false; 295 | morseSpace = false; 296 | } 297 | 298 | // Save the morse keyer state for next round 299 | lastKeyerState = morseKeyer; 300 | } 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | void morseEncoder::encode() 309 | { 310 | currentTime = millis(); 311 | 312 | if (!sendingMorse && encodeMorseChar) 313 | { 314 | // change to capital letter if not 315 | if (encodeMorseChar > 96) encodeMorseChar -= 32; 316 | 317 | // Scan for the character to send in the Morse table 318 | int i; 319 | for (i=0; i 0) 339 | { 340 | // build the morse signal (backwards from last signal to first) 341 | for (i = startLevel; i= dotTime) 387 | { 388 | digitalWrite(morseOutPin, LOW); 389 | sendMorseTimer = currentTime; 390 | morseSignalString[sendingMorseSignalNr] = 'x'; // Mark the signal as sent 391 | } 392 | break; 393 | case '-': // Send a dash (same here, stop sending after a dash worth of time) 394 | if (currentTime - sendMorseTimer >= dashTime) 395 | { 396 | digitalWrite(morseOutPin, LOW); 397 | sendMorseTimer = currentTime; 398 | morseSignalString[sendingMorseSignalNr] = 'x'; // Mark the signal as sent 399 | } 400 | break; 401 | case 'x': // To make sure there is a pause between signals and letters 402 | if (sendingMorseSignalNr < morseSignals-1) 403 | { 404 | // Pause between signals in the same letter 405 | if (currentTime - sendMorseTimer >= dotTime) 406 | { 407 | sendingMorseSignalNr++; 408 | digitalWrite(morseOutPin, HIGH); // Start sending the next signal 409 | sendMorseTimer = currentTime; // reset the timer 410 | } 411 | } else { 412 | // Pause between letters 413 | if (currentTime - sendMorseTimer >= dashTime) 414 | { 415 | sendingMorseSignalNr++; 416 | sendMorseTimer = currentTime; // reset the timer 417 | } 418 | } 419 | break; 420 | case ' ': // Pause between words (minus pause between letters - already sent) 421 | default: // Just in case its something else 422 | if (currentTime - sendMorseTimer > wordSpace - dashTime) sendingMorseSignalNr++; 423 | } 424 | if (sendingMorseSignalNr >= morseSignals) 425 | { 426 | // Ready to encode more letters 427 | sendingMorse = false; 428 | encodeMorseChar = '\0'; 429 | } 430 | } 431 | } 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | -------------------------------------------------------------------------------- /libraries/Morse_EnDecoder/MorseEnDecoder.h: -------------------------------------------------------------------------------- 1 | #ifndef MorseEnDecoder_H 2 | #define MorseEnDecoder_H 3 | 4 | #if (ARDUINO < 100) 5 | #include 6 | #else 7 | #include 8 | #endif 9 | 10 | #define MORSE_AUDIO true 11 | #define MORSE_KEYER false 12 | #define MORSE_ACTIVE_LOW true 13 | #define MORSE_ACTIVE_HIGH false 14 | 15 | 16 | class morseDecoder 17 | { 18 | public: 19 | morseDecoder(int decodePin, boolean listenAudio, boolean morsePullup); 20 | void decode(); 21 | void setspeed(int value); 22 | char read(); 23 | boolean available(); 24 | int AudioThreshold; 25 | long debounceDelay; // the debounce time. Keep well below dotTime!! 26 | boolean morseSignalState; 27 | private: 28 | int morseInPin; // The Morse input pin 29 | int audioSignal; 30 | int morseTableJumper; 31 | int morseTablePointer; 32 | int wpm; // Word-per-minute speed 33 | long dotTime; // morse dot time length in ms 34 | long dashTime; 35 | long wordSpace; 36 | boolean morseSpace; // Flag to prevent multiple received spaces 37 | boolean gotLastSig; // Flag that the last received morse signal is decoded as dot or dash 38 | boolean morseKeyer; 39 | boolean lastKeyerState; 40 | boolean morseAudio; 41 | boolean activeLow; 42 | long markTime; // timers for mark and space in morse signal 43 | long spaceTime; // E=MC^2 ;p 44 | long lastDebounceTime; // the last time the input pin was toggled 45 | long currentTime; // The current (signed) time 46 | char decodedMorseChar; // The last decoded Morse character 47 | }; 48 | 49 | 50 | 51 | 52 | class morseEncoder 53 | { 54 | public: 55 | morseEncoder(int encodePin); 56 | void encode(); 57 | void setspeed(int value); 58 | void write(char temp); 59 | boolean available(); 60 | char morseSignalString[7];// Morse signal for one character as temporary ASCII string of dots and dashes 61 | private: 62 | char encodeMorseChar; // ASCII character to encode 63 | int morseOutPin; 64 | boolean sendingMorse; 65 | int wpm; // Word-per-minute speed 66 | long dotTime; // morse dot time length in ms 67 | long dashTime; 68 | long wordSpace; 69 | int morseSignals; // nr of morse signals to send in one morse character 70 | int morseSignalPos; 71 | int sendingMorseSignalNr; 72 | long sendMorseTimer; 73 | long lastDebounceTime; 74 | long currentTime; 75 | }; 76 | 77 | 78 | #endif 79 | 80 | 81 | -------------------------------------------------------------------------------- /libraries/Morse_EnDecoder/examples/Morse_EnDecoder_barebones/Morse_EnDecoder_barebones.ino: -------------------------------------------------------------------------------- 1 | /* 2 | MORSE ENDECODER BAREBONES 3 | 4 | Minimum sketch to send/receive Morse code via the serial monitor. 5 | 6 | This example decodes Morse signals present on digital input 7 7 | (active low, and then also using the internal pullup resistor). 8 | It also encodes Morse sent via the serial interface to the Arduino, 9 | on digital output pin 13. 10 | 11 | Copyright (C) 2010, 2012 raron 12 | GNU GPLv3 license (http://www.gnu.org/licenses) 13 | Contact: raronzen@gmail.com (not checked too often..) 14 | Details: http://raronoff.wordpress.com/2010/12/16/morse-endecoder/ 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | // Pin mapping 21 | const byte morseInPin = 7; 22 | const byte morseOutPin = 13; 23 | 24 | // Instantiate Morse objects 25 | morseDecoder morseInput(morseInPin, MORSE_KEYER, MORSE_ACTIVE_LOW); 26 | morseEncoder morseOutput(morseOutPin); 27 | 28 | void setup() 29 | { 30 | Serial.begin(9600); 31 | Serial.println("Morse EnDecoder barebones demo"); 32 | 33 | // Setting Morse speed in wpm - words per minute 34 | // If not set, 13 wpm is default anyway 35 | morseInput.setspeed(13); 36 | morseOutput.setspeed(13); 37 | } 38 | 39 | 40 | void loop() 41 | { 42 | // Need to call these once per loop 43 | morseInput.decode(); 44 | morseOutput.encode(); 45 | 46 | // SEND MORSE (OUTPUT) 47 | // Encode and send text received from the serial port (serial monitor) 48 | if (Serial.available() && morseOutput.available()) 49 | { 50 | // Get character from serial and send as Morse code 51 | char sendMorse = Serial.read(); 52 | morseOutput.write(sendMorse); 53 | } 54 | 55 | // RECEIVE MORSE (INPUT) 56 | // If a character is decoded from the input, write it to serial port 57 | if (morseInput.available()) 58 | { 59 | char receivedMorse = morseInput.read(); 60 | Serial.print(receivedMorse); 61 | 62 | // A little error checking 63 | if (receivedMorse == '#') Serial.println("< ERROR:too many morse signals! >"); 64 | } 65 | 66 | } 67 | 68 | -------------------------------------------------------------------------------- /libraries/Morse_EnDecoder/examples/Morse_EnDecoder_demo/Morse_EnDecoder_demo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | MORSE ENDECODER DEMO 3 | 4 | Demonstrates using Morse encoder and decoder classes for the Arduino. 5 | 6 | Local Morse code feedback to both serial and Morse output (unless sending 7 | at the same time as receiving or keying in morse), for morse training demo. 8 | Formatted serial port output - Serial monitor looks a bit nicer. 9 | 10 | 11 | This example decodes Morse code signals with a speed of 13 WPM present on 12 | digital input 7 (active low, and also using the internal pullup resistor). 13 | 14 | It also encodes Morse code sent via the serial interface to the Arduino, 15 | on digital output pin 13. Speed is 13 WPM also (easily changed in code). 16 | 17 | It can also decode audible signals, if using the constant MORSE_AUDIO 18 | instead of MORSE_KEYER, but then it is important to note that the 19 | input pin nr. will be for ANALOG inputs (0-5 on Atmega 168 - 328), 20 | and not the digital inputs. 21 | 22 | 23 | 24 | Copyright (C) 2010, 2012 raron 25 | 26 | GNU GPLv3 license: 27 | 28 | This program is free software: you can redistribute it and/or modify 29 | it under the terms of the GNU General Public License as published by 30 | the Free Software Foundation, either version 3 of the License, or 31 | (at your option) any later version. 32 | 33 | This program is distributed in the hope that it will be useful, 34 | but WITHOUT ANY WARRANTY; without even the implied warranty of 35 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 36 | GNU General Public License for more details. 37 | 38 | You should have received a copy of the GNU General Public License 39 | along with this program. If not, see . 40 | 41 | 42 | Contact: raronzen@gmail.com (not checked too often..) 43 | Details: http://raronoff.wordpress.com/2010/12/16/morse-endecoder/ 44 | */ 45 | 46 | #include 47 | #include 48 | 49 | // Pin mappings 50 | const byte morseInPin = 7; 51 | const byte morseOutPin = 13; 52 | 53 | // Instantiate Morse objects 54 | morseDecoder morseInput(morseInPin, MORSE_KEYER, MORSE_ACTIVE_LOW); 55 | morseEncoder morseOutput(morseOutPin); 56 | 57 | // Variables dealing with formatting the output somewhat 58 | // by inserting CR's (carriage returns) 59 | long lastTransmissionTime; 60 | long currentTime; 61 | boolean transmissionEnded = true; // Flag to mark old transmission is finished 62 | 63 | // Minimum transmission pause time to insert carriage returns (CR) 64 | // Adjust depending on Morse speed. IE 13 wpm = 646 ms between words (no CR). 65 | const long transmissionPaused = 1000; // Suitable for 13 wpm? 66 | 67 | 68 | void setup() 69 | { 70 | Serial.begin(9600); 71 | Serial.println("Morse EnDecoder demo"); 72 | 73 | // Setting Morse speed in wpm - words per minute 74 | // If not set, 13 wpm is default anyway 75 | morseInput.setspeed(13); 76 | morseOutput.setspeed(13); 77 | 78 | lastTransmissionTime = (long)millis(); 79 | } 80 | 81 | 82 | 83 | void loop() 84 | { 85 | currentTime = (long)millis(); 86 | 87 | // Needs to call these once per loop 88 | morseInput.decode(); 89 | morseOutput.encode(); 90 | 91 | // SEND MORSE (OUTPUT) 92 | // Encode and send text received from the serial port (serial monitor) 93 | if (Serial.available() && morseOutput.available()) 94 | { 95 | // Get character from serial and send as Morse code 96 | char sendMorse = Serial.read(); 97 | morseOutput.write(sendMorse); 98 | 99 | // Not strictly needed, but used to get morseSignalString before it is destroyed 100 | // (E.g. for morse training purposes) 101 | morseOutput.encode(); 102 | 103 | // Also write sent character + Morse code to serial port/monitor 104 | Serial.write(' '); 105 | Serial.write(sendMorse); 106 | Serial.write(morseOutput.morseSignalString); 107 | } 108 | 109 | 110 | // RECEIVE MORSE (INPUT) 111 | // If a character is decoded from the input, write it to serial port 112 | if (morseInput.available()) 113 | { 114 | // Get decoded Morse code character and write it to serial port/monitor 115 | char receivedMorse = morseInput.read(); 116 | Serial.print(receivedMorse); 117 | 118 | // A little error checking 119 | if (receivedMorse == '#') Serial.println("< ERROR:too many morse signals! >"); 120 | } 121 | 122 | 123 | // Local Morse code feedback from input if not sending Morse simultaneously 124 | if (morseOutput.available()) digitalWrite(morseOutPin, morseInput.morseSignalState); 125 | 126 | 127 | // Check if ongoing transmission (not yet transmission pause) 128 | if (!morseOutput.available() || morseInput.morseSignalState == true) 129 | { 130 | // reset last transmission timer and flag 131 | lastTransmissionTime = currentTime; 132 | transmissionEnded = false; 133 | } 134 | 135 | // Format output with carriage returns after a transmission pause 136 | if ((currentTime - lastTransmissionTime) > transmissionPaused) 137 | { 138 | if (transmissionEnded == false) 139 | { 140 | // Separate the transmissions somewhat in the serial monitor with CR's 141 | for (int cr=0; cr<2; cr++) Serial.println(""); // some carriage returns.. 142 | 143 | // Finally set the flag to prevent continous carriage returns 144 | transmissionEnded = true; 145 | } 146 | } 147 | } 148 | 149 | -------------------------------------------------------------------------------- /libraries/Morse_EnDecoder/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For MorseEnDecoder 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | morseDecoder KEYWORD1 10 | morseEncoder KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | decode KEYWORD2 16 | encode KEYWORD2 17 | setspeed KEYWORD2 18 | read KEYWORD2 19 | write KEYWORD2 20 | available KEYWORD2 21 | 22 | 23 | ####################################### 24 | # Constants (LITERAL1) 25 | ####################################### 26 | 27 | MORSE_AUDIO LITERAL1 28 | MORSE_KEYER LITERAL1 29 | MORSE_ACTIVE_LOW LITERAL1 30 | MORSE_ACTIVE_HIGH LITERAL1 31 | 32 | -------------------------------------------------------------------------------- /libraries/Rotary/README.md: -------------------------------------------------------------------------------- 1 | Rotary Encoder Arduino Library 2 | ============================== 3 | 4 | Arduino library for reading rotary encoders that output a 2-bit [gray code](http://en.wikipedia.org/wiki/Gray_code). 5 | 6 | Rotary r = Rotary(2, 3); 7 | 8 | void loop() { 9 | result = r.process(); 10 | if (result) { 11 | Serial.println(result == DIR_CW ? "Right" : "Left"); 12 | } 13 | } 14 | 15 | This is a repackaged version of Ben Buxton's excellent [rotary library](http://www.buxtronix.net/2011/10/rotary-encoders-done-properly.html) organized for the Arduino 1.x IDE, keyword highlighting, polling example, Arduino library capitalization conventions. 16 | 17 | Features 18 | -------- 19 | * Debounce handling with support for high rotation speeds 20 | * Correctly handles direction changes mid-step 21 | * Checks for valid state changes for more robust counting / noise immunity 22 | * Interrupt based or polling in loop() 23 | * Counts full-steps (default) or half-steps 24 | 25 | Installation 26 | ------------ 27 | 1. Download and unzip to Arduino\\libraries\\Rotary. So for example rotary.h will be in Arduino\\libraries\\Rotary\\rotary.h. 28 | 2. Restart Arduino IDE 29 | 3. File -> Examples -> Rotary 30 | 31 | Background 32 | ---------- 33 | A typical mechanical rotary encoder emits a two bit gray code on 3 output pins. Every step in the output (often accompanied by a physical 'click') generates a specific sequence of output codes on the pins. 34 | 35 | There are 3 pins used for the rotary encoding - one common and two 'bit' pins. 36 | 37 | The following is the typical sequence of code on the output when moving from one step to the next: 38 | 39 | Position Bit1 Bit2 40 | - - - - - - - - - - - 41 | Step1 0 0 42 | 1/4 1 0 43 | 1/2 1 1 44 | 3/4 0 1 45 | Step2 0 0 46 | 47 | From this table, we can see that when moving from one 'click' to the next, there are 4 changes in the output code. 48 | 49 | - From an initial 0 - 0, Bit1 goes high, Bit0 stays low. 50 | - Then both bits are high, halfway through the step. 51 | - Then Bit1 goes low, but Bit2 stays high. 52 | - Finally at the end of the step, both bits return to 0. 53 | 54 | Detecting the direction is easy - the table simply goes in the other direction (read up instead of down). 55 | 56 | To decode this, we use a simple state machine. Every time the output code changes, it follows state, until finally a full steps worth of code is received (in the correct order). At the final 0-0, it returns a value indicating a step in one direction or the other. 57 | 58 | It's also possible to use 'half-step' mode. This just emits an event at both the 0-0 and 1-1 positions. This might be useful for some encoders where you want to detect all positions. In rotary.h, uncomment `#define HALF_STEP` to enable half-step mode. 59 | 60 | If an invalid state happens (for example we go from '0-1' straight to '1-0'), the state machine resets to the start until 0-0 and the next valid codes occur. 61 | 62 | The biggest advantage of using a state machine over other algorithms is that this has inherent debounce built in. Other algorithms emit spurious output with switch bounce, but this one will simply flip between sub-states until the bounce settles, then continue along the state machine. A side effect of debounce is that fast rotations can cause steps to be skipped. By not requiring debounce, fast rotations can be accurately measured. Another advantage is the ability to properly handle bad state, such as due to EMI, etc. It is also a lot simpler than others - a static state table and less than 10 lines of logic. 63 | 64 | License 65 | ------- 66 | GNU GPL Version 3 67 | -------------------------------------------------------------------------------- /libraries/Rotary/Rotary.cpp: -------------------------------------------------------------------------------- 1 | /* Rotary encoder handler for arduino. 2 | * 3 | * Copyright 2011 Ben Buxton. Licenced under the GNU GPL Version 3. 4 | * Contact: bb@cactii.net 5 | * 6 | */ 7 | 8 | #include "Arduino.h" 9 | #include "Rotary.h" 10 | 11 | /* 12 | * The below state table has, for each state (row), the new state 13 | * to set based on the next encoder output. From left to right in, 14 | * the table, the encoder outputs are 00, 01, 10, 11, and the value 15 | * in that position is the new state to set. 16 | */ 17 | 18 | #define R_START 0x0 19 | 20 | #ifdef HALF_STEP 21 | // Use the half-step state table (emits a code at 00 and 11) 22 | #define R_CCW_BEGIN 0x1 23 | #define R_CW_BEGIN 0x2 24 | #define R_START_M 0x3 25 | #define R_CW_BEGIN_M 0x4 26 | #define R_CCW_BEGIN_M 0x5 27 | const unsigned char ttable[6][4] = { 28 | // R_START (00) 29 | {R_START_M, R_CW_BEGIN, R_CCW_BEGIN, R_START}, 30 | // R_CCW_BEGIN 31 | {R_START_M | DIR_CCW, R_START, R_CCW_BEGIN, R_START}, 32 | // R_CW_BEGIN 33 | {R_START_M | DIR_CW, R_CW_BEGIN, R_START, R_START}, 34 | // R_START_M (11) 35 | {R_START_M, R_CCW_BEGIN_M, R_CW_BEGIN_M, R_START}, 36 | // R_CW_BEGIN_M 37 | {R_START_M, R_START_M, R_CW_BEGIN_M, R_START | DIR_CW}, 38 | // R_CCW_BEGIN_M 39 | {R_START_M, R_CCW_BEGIN_M, R_START_M, R_START | DIR_CCW}, 40 | }; 41 | #else 42 | // Use the full-step state table (emits a code at 00 only) 43 | #define R_CW_FINAL 0x1 44 | #define R_CW_BEGIN 0x2 45 | #define R_CW_NEXT 0x3 46 | #define R_CCW_BEGIN 0x4 47 | #define R_CCW_FINAL 0x5 48 | #define R_CCW_NEXT 0x6 49 | 50 | const unsigned char ttable[7][4] = { 51 | // R_START 52 | {R_START, R_CW_BEGIN, R_CCW_BEGIN, R_START}, 53 | // R_CW_FINAL 54 | {R_CW_NEXT, R_START, R_CW_FINAL, R_START | DIR_CW}, 55 | // R_CW_BEGIN 56 | {R_CW_NEXT, R_CW_BEGIN, R_START, R_START}, 57 | // R_CW_NEXT 58 | {R_CW_NEXT, R_CW_BEGIN, R_CW_FINAL, R_START}, 59 | // R_CCW_BEGIN 60 | {R_CCW_NEXT, R_START, R_CCW_BEGIN, R_START}, 61 | // R_CCW_FINAL 62 | {R_CCW_NEXT, R_CCW_FINAL, R_START, R_START | DIR_CCW}, 63 | // R_CCW_NEXT 64 | {R_CCW_NEXT, R_CCW_FINAL, R_CCW_BEGIN, R_START}, 65 | }; 66 | #endif 67 | 68 | /* 69 | * Constructor. Each arg is the pin number for each encoder contact. 70 | */ 71 | Rotary::Rotary(char _pin1, char _pin2) { 72 | // Assign variables. 73 | pin1 = _pin1; 74 | pin2 = _pin2; 75 | // Set pins to input. 76 | pinMode(pin1, INPUT); 77 | pinMode(pin2, INPUT); 78 | #ifdef ENABLE_PULLUPS 79 | digitalWrite(pin1, HIGH); 80 | digitalWrite(pin2, HIGH); 81 | #endif 82 | // Initialise state. 83 | state = R_START; 84 | } 85 | 86 | unsigned char Rotary::process() { 87 | // Grab state of input pins. 88 | unsigned char pinstate = (digitalRead(pin2) << 1) | digitalRead(pin1); 89 | // Determine new state from the pins and state table. 90 | state = ttable[state & 0xf][pinstate]; 91 | // Return emit bits, ie the generated event. 92 | return state & 0x30; 93 | } 94 | -------------------------------------------------------------------------------- /libraries/Rotary/Rotary.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Rotary encoder library for Arduino. 3 | */ 4 | 5 | #ifndef Rotary_h 6 | #define Rotary_h 7 | 8 | #include "Arduino.h" 9 | 10 | // Enable this to emit codes twice per step. 11 | // #define HALF_STEP 12 | 13 | // Enable weak pullups 14 | #define ENABLE_PULLUPS 15 | 16 | // Values returned by 'process' 17 | // No complete step yet. 18 | #define DIR_NONE 0x0 19 | // Clockwise step. 20 | #define DIR_CW 0x10 21 | // Counter-clockwise step. 22 | #define DIR_CCW 0x20 23 | 24 | class Rotary 25 | { 26 | public: 27 | Rotary(char, char); 28 | unsigned char process(); 29 | private: 30 | unsigned char state; 31 | unsigned char pin1; 32 | unsigned char pin2; 33 | }; 34 | 35 | #endif 36 | 37 | -------------------------------------------------------------------------------- /libraries/Rotary/examples/Interrupt/Interrupt.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Rotary Encoder - Interrupt Example 3 | 4 | The circuit: 5 | * encoder pin A to Arduino pin 2 6 | * encoder pin B to Arduino pin 3 7 | * encoder ground pin to ground (GND) 8 | */ 9 | 10 | #include 11 | 12 | Rotary r = Rotary(2, 3); 13 | 14 | void setup() { 15 | Serial.begin(9600); 16 | PCICR |= (1 << PCIE2); 17 | PCMSK2 |= (1 << PCINT18) | (1 << PCINT19); 18 | sei(); 19 | } 20 | 21 | void loop() { 22 | 23 | } 24 | 25 | ISR(PCINT2_vect) { 26 | unsigned char result = r.process(); 27 | if (result == DIR_NONE) { 28 | // do nothing 29 | } 30 | else if (result == DIR_CW) { 31 | Serial.println("ClockWise"); 32 | } 33 | else if (result == DIR_CCW) { 34 | Serial.println("CounterClockWise"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /libraries/Rotary/examples/Polling/Polling.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Rotary Encoder - Polling Example 3 | 4 | The circuit: 5 | * encoder pin A to Arduino pin 2 6 | * encoder pin B to Arduino pin 3 7 | * encoder ground pin to ground (GND) 8 | 9 | */ 10 | 11 | #include 12 | 13 | Rotary r = Rotary(2, 3); 14 | 15 | void setup() { 16 | Serial.begin(9600); 17 | } 18 | 19 | void loop() { 20 | unsigned char result = r.process(); 21 | if (result) { 22 | Serial.println(result == DIR_CW ? "Right" : "Left"); 23 | } 24 | } -------------------------------------------------------------------------------- /libraries/Rotary/keywords.txt: -------------------------------------------------------------------------------- 1 | Rotary KEYWORD1 2 | process KEYWORD2 3 | DIR_NONE LITERAL1 4 | DIR_CW LITERAL1 5 | DIR_CCW LITERAL1 -------------------------------------------------------------------------------- /libraries/Si5351/examples/si5351calibration/si5351calibration.ino: -------------------------------------------------------------------------------- 1 | /* Simple calibration routine for the Si5351 breakout board. 2 | * 3 | * Copyright 2015 Paul Warren 4 | * 5 | * Uses code from https://github.com/darksidelemm/open_radio_miniconf_2015 6 | * and the old version of the calibration sketch 7 | * 8 | * This sketch is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * Foobar is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * You should have received a copy of the GNU General Public License. 17 | * If not, see . 18 | */ 19 | 20 | #include "si5351.h" 21 | #include "Wire.h" 22 | 23 | Si5351 si5351; 24 | 25 | int32_t cal_factor; 26 | int32_t old_cal; 27 | 28 | uint64_t rx_freq; 29 | uint64_t target_freq = 1000000000ULL; // 10 MHz, in hundredths of hertz 30 | 31 | void setup() 32 | { 33 | // Start serial and initialize the Si5351 34 | Serial.begin(57600); 35 | si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); 36 | 37 | // get old cal factor 38 | //old_cal = si5351.get_correction(); 39 | si5351.set_correction(0); 40 | // start on target frequency 41 | si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); 42 | si5351.set_freq(target_freq, SI5351_PLL_FIXED, SI5351_CLK0); 43 | } 44 | 45 | void loop() 46 | { 47 | si5351.update_status(); 48 | if (si5351.dev_status.SYS_INIT == 1) { 49 | Serial.println("Initialising Si5351, you shouldn't see many of these!"); 50 | delay(500); 51 | } else { 52 | cal_factor = 0; 53 | // Serial.print("Old cal factor was: "); 54 | // Serial.println(old_cal); 55 | // Serial.println("Cal factor now set to 0"); 56 | // si5351.set_correction(0); 57 | Serial.println(); 58 | Serial.println(F("Adjust until your frequency counter reads as close to 10 MHz as possible")); 59 | vfo_interface(); 60 | Serial.print(F("Calibration factor is ")); 61 | Serial.println(cal_factor); 62 | Serial.println("Setting calibration factor"); 63 | si5351.set_correction(cal_factor); 64 | Serial.println("Resetting target frequency"); 65 | si5351.set_freq(target_freq, SI5351_PLL_FIXED, SI5351_CLK0); 66 | } 67 | 68 | 69 | } 70 | 71 | static void flush_input(void) 72 | { 73 | while (Serial.available() > 0) 74 | Serial.read(); 75 | } 76 | 77 | static void vfo_interface(void) 78 | { 79 | rx_freq = target_freq; 80 | Serial.println(F(" Up: r t y u i o p")); 81 | Serial.println(F(" Down: f g h j k l ;")); 82 | Serial.println(F(" Hz: 0.01 0.1 1 10 100 1K 10k")); 83 | while (1) { 84 | if (Serial.available() > 0) { 85 | char c = Serial.read(); 86 | switch (c) { 87 | case 'q': 88 | flush_input(); 89 | return; 90 | case 'r': rx_freq += 1; break; 91 | case 'f': rx_freq -= 1; break; 92 | case 't': rx_freq += 10; break; 93 | case 'g': rx_freq -= 10; break; 94 | case 'y': rx_freq += 100; break; 95 | case 'h': rx_freq -= 100; break; 96 | case 'u': rx_freq += 1000; break; 97 | case 'j': rx_freq -= 1000; break; 98 | case 'i': rx_freq += 10000; break; 99 | case 'k': rx_freq -= 10000; break; 100 | case 'o': rx_freq += 100000; break; 101 | case 'l': rx_freq -= 100000; break; 102 | case 'p': rx_freq += 1000000; break; 103 | case ';': rx_freq -= 1000000; break; 104 | default: 105 | // Do nothing 106 | continue; 107 | } 108 | si5351.set_freq(rx_freq,SI5351_PLL_FIXED,SI5351_CLK0); 109 | cal_factor = (int32_t)(target_freq - rx_freq); 110 | Serial.print("Current difference:"); 111 | Serial.println(cal_factor); 112 | } 113 | } 114 | } 115 | 116 | -------------------------------------------------------------------------------- /libraries/Si5351/examples/si5351example/si5351example.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * si5351example.ino - Simple example of using Si5351Arduino library 3 | * 4 | * Copyright (C) 2015 Jason Milldrum 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | 21 | #include "si5351.h" 22 | #include "Wire.h" 23 | 24 | Si5351 si5351; 25 | 26 | void setup() 27 | { 28 | // Start serial and initialize the Si5351 29 | Serial.begin(57600); 30 | si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); 31 | 32 | // Set CLK0 to output 14 MHz with a fixed PLL frequency 33 | si5351.set_pll(SI5351_PLL_FIXED, SI5351_PLLA); 34 | si5351.set_freq(1400000000ULL, SI5351_PLL_FIXED, SI5351_CLK0); 35 | 36 | // Set CLK1 to output 20 MHz 37 | si5351.set_freq(2000000000ULL, 0ULL, SI5351_CLK1); 38 | } 39 | 40 | void loop() 41 | { 42 | // Read the Status Register and print it every 10 seconds 43 | si5351.update_status(); 44 | Serial.print("SYS_INIT: "); 45 | Serial.print(si5351.dev_status.SYS_INIT); 46 | Serial.print(" LOL_A: "); 47 | Serial.print(si5351.dev_status.LOL_A); 48 | Serial.print(" LOL_B: "); 49 | Serial.print(si5351.dev_status.LOL_B); 50 | Serial.print(" LOS: "); 51 | Serial.print(si5351.dev_status.LOS); 52 | Serial.print(" REVID: "); 53 | Serial.println(si5351.dev_status.REVID); 54 | 55 | delay(10000); 56 | } 57 | -------------------------------------------------------------------------------- /libraries/Si5351/examples/si5351phase/si5351phase.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * si5351phase.ino - Example for setting phase with Si5351Arduino library 3 | * 4 | * Copyright (C) 2015 Jason Milldrum 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | /* 21 | * Setting the phase of a clock requires that you manually set the PLL and 22 | * take the PLL frequency into account when calculation the value to place 23 | * in the phase register. As shown on page 10 of Silicon Labs Application 24 | * Note 619 (AN619), the phase register is a 7-bit register, where a bit 25 | * represents a phase difference of 1/4 the PLL period. Therefore, the best 26 | * way to get an accurate phase setting is to make the PLL an even multiple 27 | * of the clock frequency, depending on what phase you need. 28 | * 29 | * If you need a 90 degree phase shift (as in many RF applications), then 30 | * it is quite easy to determine your parameters. Pick a PLL frequency that 31 | * is an even multiple of your clock frequency (remember that the PLL needs 32 | * to be in the range of 600 to 900 MHz). Then to set a 90 degree phase shift, 33 | * you simply enter that multiple into the phase register. Remember when 34 | * setting multiple outputs to be phase-related to each other, they each need 35 | * to be referenced to the same PLL. 36 | */ 37 | 38 | #include "si5351.h" 39 | #include "Wire.h" 40 | 41 | Si5351 si5351; 42 | 43 | void setup() 44 | { 45 | // Start serial and initialize the Si5351 46 | Serial.begin(57600); 47 | si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0); 48 | 49 | // We will output 14.1 MHz on CLK0 and CLK1. 50 | // A PLLA frequency of 705 MHz was chosen to give an even 51 | // divisor by 14.1 MHz. 52 | unsigned long long freq = 1410000000ULL; 53 | unsigned long long pll_freq = 70500000000ULL; 54 | 55 | // Set PLLA to the chosen frequency 56 | si5351.set_pll(pll_freq, SI5351_PLLA); 57 | 58 | // Set CLK0 and CLK1 to use PLLA as the MS source 59 | si5351.set_ms_source(SI5351_CLK0, SI5351_PLLA); 60 | si5351.set_ms_source(SI5351_CLK1, SI5351_PLLA); 61 | 62 | // Set CLK0 and CLK1 to output 14.1 MHz with a fixed PLL frequency 63 | si5351.set_freq(freq, pll_freq, SI5351_CLK0); 64 | si5351.set_freq(freq, pll_freq, SI5351_CLK1); 65 | 66 | // Now we can set CLK1 to have a 90 deg phase shift by entering 67 | // 50 in the CLK1 phase register, since the ratio of the PLL to 68 | // the clock frequency is 50. 69 | si5351.set_phase(SI5351_CLK0, 0); 70 | si5351.set_phase(SI5351_CLK1, 50); 71 | 72 | // We need to reset the PLL before they will be in phase alignment 73 | si5351.pll_reset(SI5351_PLLA); 74 | } 75 | 76 | void loop() 77 | { 78 | // Read the Status Register and print it every 10 seconds 79 | si5351.update_status(); 80 | Serial.print("SYS_INIT: "); 81 | Serial.print(si5351.dev_status.SYS_INIT); 82 | Serial.print(" LOL_A: "); 83 | Serial.print(si5351.dev_status.LOL_A); 84 | Serial.print(" LOL_B: "); 85 | Serial.print(si5351.dev_status.LOL_B); 86 | Serial.print(" LOS: "); 87 | Serial.print(si5351.dev_status.LOS); 88 | Serial.print(" REVID: "); 89 | Serial.println(si5351.dev_status.REVID); 90 | 91 | delay(10000); 92 | } 93 | -------------------------------------------------------------------------------- /libraries/Si5351/keywords.txt: -------------------------------------------------------------------------------- 1 | Si5351 KEYWORD1 2 | 3 | set_freq KEYWORD2 4 | set_pll KEYWORD2 5 | clock_enable KEYWORD2 6 | drive_strength KEYWORD2 7 | update_status KEYWORD2 8 | set_correction KEYWORD2 9 | get_correction KEYWORD2 10 | 11 | SI5351_PLL_FIXED LITERAL1 12 | SI5351_CRYSTAL_LOAD_6PF LITERAL1 13 | SI5351_CRYSTAL_LOAD_8PF LITERAL1 14 | SI5351_CRYSTAL_LOAD_10PF LITERAL1 15 | SI5351_CLK0 LITERAL1 16 | SI5351_CLK1 LITERAL1 17 | SI5351_CLK2 LITERAL1 18 | SI5351_CLK3 LITERAL1 19 | SI5351_CLK4 LITERAL1 20 | SI5351_CLK5 LITERAL1 21 | SI5351_CLK6 LITERAL1 22 | SI5351_CLK7 LITERAL1 23 | SI5351_PLLA LITERAL1 24 | SI5351_PLLB LITERAL1 25 | SI5351_DRIVE_2MA LITERAL1 26 | SI5351_DRIVE_4MA LITERAL1 27 | SI5351_DRIVE_6MA LITERAL1 28 | SI5351_DRIVE_8MA LITERAL1 29 | -------------------------------------------------------------------------------- /libraries/Si5351/si5351.h: -------------------------------------------------------------------------------- 1 | /* 2 | * si5351.h - Si5351 library for Arduino 3 | * 4 | * Copyright (C) 2015 Jason Milldrum 5 | * Dana H. Myers 6 | * 7 | * Many defines derived from clk-si5351.h in the Linux kernel. 8 | * Sebastian Hesselbarth 9 | * Rabeeh Khoury 10 | * 11 | * do_div() macro derived from /include/asm-generic/div64.h in 12 | * the Linux kernel. 13 | * Copyright (C) 2003 Bernardo Innocenti 14 | * 15 | * This program is free software: you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation, either version 3 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * This program is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with this program. If not, see . 27 | */ 28 | 29 | #ifndef SI5351_H_ 30 | #define SI5351_H_ 31 | 32 | #include "Arduino.h" 33 | #include "Wire.h" 34 | #include 35 | 36 | /* Define definitions */ 37 | 38 | #define SI5351_BUS_BASE_ADDR 0x60 39 | #define SI5351_XTAL_FREQ 25000000 40 | #define SI5351_PLL_FIXED 90000000000ULL 41 | #define SI5351_FREQ_MULT 100ULL 42 | #define SI5351_DEFAULT_CLK 1000000000ULL 43 | 44 | #define SI5351_PLL_VCO_MIN 600000000 45 | #define SI5351_PLL_VCO_MAX 900000000 46 | #define SI5351_MULTISYNTH_MIN_FREQ 1000000 47 | #define SI5351_MULTISYNTH_DIVBY4_FREQ 150000000 48 | #define SI5351_MULTISYNTH_MAX_FREQ 160000000 49 | #define SI5351_MULTISYNTH_SHARE_MAX 112500000 50 | #define SI5351_MULTISYNTH67_MAX_FREQ SI5351_MULTISYNTH_DIVBY4_FREQ 51 | #define SI5351_CLKOUT_MIN_FREQ 8000 52 | #define SI5351_CLKOUT_MAX_FREQ SI5351_MULTISYNTH_MAX_FREQ 53 | #define SI5351_CLKOUT67_MAX_FREQ SI5351_MULTISYNTH67_MAX_FREQ 54 | 55 | #define SI5351_PLL_A_MIN 15 56 | #define SI5351_PLL_A_MAX 90 57 | #define SI5351_PLL_B_MAX (SI5351_PLL_C_MAX-1) 58 | #define SI5351_PLL_C_MAX 1048575 59 | #define SI5351_MULTISYNTH_A_MIN 6 60 | #define SI5351_MULTISYNTH_A_MAX 1800 61 | #define SI5351_MULTISYNTH67_A_MAX 254 62 | #define SI5351_MULTISYNTH_B_MAX (SI5351_MULTISYNTH_C_MAX-1) 63 | #define SI5351_MULTISYNTH_C_MAX 1048575 64 | #define SI5351_MULTISYNTH_P1_MAX ((1<<18)-1) 65 | #define SI5351_MULTISYNTH_P2_MAX ((1<<20)-1) 66 | #define SI5351_MULTISYNTH_P3_MAX ((1<<20)-1) 67 | 68 | #define SI5351_DEVICE_STATUS 0 69 | #define SI5351_INTERRUPT_STATUS 1 70 | #define SI5351_INTERRUPT_MASK 2 71 | #define SI5351_STATUS_SYS_INIT (1<<7) 72 | #define SI5351_STATUS_LOL_B (1<<6) 73 | #define SI5351_STATUS_LOL_A (1<<5) 74 | #define SI5351_STATUS_LOS (1<<4) 75 | #define SI5351_OUTPUT_ENABLE_CTRL 3 76 | #define SI5351_OEB_PIN_ENABLE_CTRL 9 77 | #define SI5351_PLL_INPUT_SOURCE 15 78 | #define SI5351_CLKIN_DIV_MASK (3<<6) 79 | #define SI5351_CLKIN_DIV_1 (0<<6) 80 | #define SI5351_CLKIN_DIV_2 (1<<6) 81 | #define SI5351_CLKIN_DIV_4 (2<<6) 82 | #define SI5351_CLKIN_DIV_8 (3<<6) 83 | #define SI5351_PLLB_SOURCE (1<<3) 84 | #define SI5351_PLLA_SOURCE (1<<2) 85 | 86 | #define SI5351_CLK0_CTRL 16 87 | #define SI5351_CLK1_CTRL 17 88 | #define SI5351_CLK2_CTRL 18 89 | #define SI5351_CLK3_CTRL 19 90 | #define SI5351_CLK4_CTRL 20 91 | #define SI5351_CLK5_CTRL 21 92 | #define SI5351_CLK6_CTRL 22 93 | #define SI5351_CLK7_CTRL 23 94 | #define SI5351_CLK_POWERDOWN (1<<7) 95 | #define SI5351_CLK_INTEGER_MODE (1<<6) 96 | #define SI5351_CLK_PLL_SELECT (1<<5) 97 | #define SI5351_CLK_INVERT (1<<4) 98 | #define SI5351_CLK_INPUT_MASK (3<<2) 99 | #define SI5351_CLK_INPUT_XTAL (0<<2) 100 | #define SI5351_CLK_INPUT_CLKIN (1<<2) 101 | #define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2) 102 | #define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2) 103 | #define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0) 104 | #define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0) 105 | #define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0) 106 | #define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0) 107 | #define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0) 108 | 109 | #define SI5351_CLK3_0_DISABLE_STATE 24 110 | #define SI5351_CLK7_4_DISABLE_STATE 25 111 | #define SI5351_CLK_DISABLE_STATE_MASK 3 112 | #define SI5351_CLK_DISABLE_STATE_LOW 0 113 | #define SI5351_CLK_DISABLE_STATE_HIGH 1 114 | #define SI5351_CLK_DISABLE_STATE_FLOAT 2 115 | #define SI5351_CLK_DISABLE_STATE_NEVER 3 116 | 117 | #define SI5351_PARAMETERS_LENGTH 8 118 | #define SI5351_PLLA_PARAMETERS 26 119 | #define SI5351_PLLB_PARAMETERS 34 120 | #define SI5351_CLK0_PARAMETERS 42 121 | #define SI5351_CLK1_PARAMETERS 50 122 | #define SI5351_CLK2_PARAMETERS 58 123 | #define SI5351_CLK3_PARAMETERS 66 124 | #define SI5351_CLK4_PARAMETERS 74 125 | #define SI5351_CLK5_PARAMETERS 82 126 | #define SI5351_CLK6_PARAMETERS 90 127 | #define SI5351_CLK7_PARAMETERS 91 128 | #define SI5351_CLK6_7_OUTPUT_DIVIDER 92 129 | #define SI5351_OUTPUT_CLK_DIV_MASK (7 << 4) 130 | #define SI5351_OUTPUT_CLK6_DIV_MASK (7 << 0) 131 | #define SI5351_OUTPUT_CLK_DIV_SHIFT 4 132 | #define SI5351_OUTPUT_CLK_DIV6_SHIFT 0 133 | #define SI5351_OUTPUT_CLK_DIV_1 0 134 | #define SI5351_OUTPUT_CLK_DIV_2 1 135 | #define SI5351_OUTPUT_CLK_DIV_4 2 136 | #define SI5351_OUTPUT_CLK_DIV_8 3 137 | #define SI5351_OUTPUT_CLK_DIV_16 4 138 | #define SI5351_OUTPUT_CLK_DIV_32 5 139 | #define SI5351_OUTPUT_CLK_DIV_64 6 140 | #define SI5351_OUTPUT_CLK_DIV_128 7 141 | #define SI5351_OUTPUT_CLK_DIVBY4 (3<<2) 142 | 143 | #define SI5351_SSC_PARAM0 149 144 | #define SI5351_SSC_PARAM1 150 145 | #define SI5351_SSC_PARAM2 151 146 | #define SI5351_SSC_PARAM3 152 147 | #define SI5351_SSC_PARAM4 153 148 | #define SI5351_SSC_PARAM5 154 149 | #define SI5351_SSC_PARAM6 155 150 | #define SI5351_SSC_PARAM7 156 151 | #define SI5351_SSC_PARAM8 157 152 | #define SI5351_SSC_PARAM9 158 153 | #define SI5351_SSC_PARAM10 159 154 | #define SI5351_SSC_PARAM11 160 155 | #define SI5351_SSC_PARAM12 161 156 | 157 | #define SI5351_VXCO_PARAMETERS_LOW 162 158 | #define SI5351_VXCO_PARAMETERS_MID 163 159 | #define SI5351_VXCO_PARAMETERS_HIGH 164 160 | 161 | #define SI5351_CLK0_PHASE_OFFSET 165 162 | #define SI5351_CLK1_PHASE_OFFSET 166 163 | #define SI5351_CLK2_PHASE_OFFSET 167 164 | #define SI5351_CLK3_PHASE_OFFSET 168 165 | #define SI5351_CLK4_PHASE_OFFSET 169 166 | #define SI5351_CLK5_PHASE_OFFSET 170 167 | 168 | #define SI5351_PLL_RESET 177 169 | #define SI5351_PLL_RESET_B (1<<7) 170 | #define SI5351_PLL_RESET_A (1<<5) 171 | 172 | #define SI5351_CRYSTAL_LOAD 183 173 | #define SI5351_CRYSTAL_LOAD_MASK (3<<6) 174 | #define SI5351_CRYSTAL_LOAD_6PF (1<<6) 175 | #define SI5351_CRYSTAL_LOAD_8PF (2<<6) 176 | #define SI5351_CRYSTAL_LOAD_10PF (3<<6) 177 | 178 | #define SI5351_FANOUT_ENABLE 187 179 | #define SI5351_CLKIN_ENABLE (1<<7) 180 | #define SI5351_XTAL_ENABLE (1<<6) 181 | #define SI5351_MULTISYNTH_ENABLE (1<<4) 182 | 183 | 184 | /* Macro definitions */ 185 | 186 | #define RFRAC_DENOM ((1L << 20) - 1) 187 | 188 | /* 189 | * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h 190 | * 191 | * The semantics of do_div() are: 192 | * 193 | * uint32_t do_div(uint64_t *n, uint32_t base) 194 | * { 195 | * uint32_t remainder = *n % base; 196 | * *n = *n / base; 197 | * return remainder; 198 | * } 199 | * 200 | * NOTE: macro parameter n is evaluated multiple times, 201 | * beware of side effects! 202 | */ 203 | 204 | # define do_div(n,base) ({ \ 205 | uint64_t __base = (base); \ 206 | uint64_t __rem; \ 207 | __rem = ((uint64_t)(n)) % __base; \ 208 | (n) = ((uint64_t)(n)) / __base; \ 209 | __rem; \ 210 | }) 211 | 212 | /* Enum definitions */ 213 | 214 | /* 215 | * enum si5351_variant - SiLabs Si5351 chip variant 216 | * @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input) 217 | * @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input) 218 | * @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input) 219 | * @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input) 220 | */ 221 | enum si5351_variant { 222 | SI5351_VARIANT_A = 1, 223 | SI5351_VARIANT_A3 = 2, 224 | SI5351_VARIANT_B = 3, 225 | SI5351_VARIANT_C = 4, 226 | }; 227 | 228 | enum si5351_clock {SI5351_CLK0, SI5351_CLK1, SI5351_CLK2, SI5351_CLK3, 229 | SI5351_CLK4, SI5351_CLK5, SI5351_CLK6, SI5351_CLK7, SI5351_CLKNONE}; 230 | 231 | enum si5351_pll {SI5351_PLLA, SI5351_PLLB}; 232 | 233 | enum si5351_drive {SI5351_DRIVE_2MA, SI5351_DRIVE_4MA, SI5351_DRIVE_6MA, SI5351_DRIVE_8MA}; 234 | 235 | enum si5351_clock_source {SI5351_CLK_SRC_XTAL, SI5351_CLK_SRC_CLKIN, SI5351_CLK_SRC_MS0, SI5351_CLK_SRC_MS}; 236 | 237 | enum si5351_clock_disable {SI5351_CLK_DISABLE_LOW, SI5351_CLK_DISABLE_HIGH, SI5351_CLK_DISABLE_HI_Z, SI5351_CLK_DISABLE_NEVER}; 238 | 239 | enum si5351_clock_fanout {SI5351_FANOUT_CLKIN, SI5351_FANOUT_XO, SI5351_FANOUT_MS}; 240 | 241 | /* Struct definitions */ 242 | 243 | struct Si5351RegSet 244 | { 245 | uint32_t p1; 246 | uint32_t p2; 247 | uint32_t p3; 248 | }; 249 | 250 | struct Si5351Status 251 | { 252 | uint8_t SYS_INIT; 253 | uint8_t LOL_B; 254 | uint8_t LOL_A; 255 | uint8_t LOS; 256 | uint8_t REVID; 257 | }; 258 | 259 | struct Si5351IntStatus 260 | { 261 | uint8_t SYS_INIT_STKY; 262 | uint8_t LOL_B_STKY; 263 | uint8_t LOL_A_STKY; 264 | uint8_t LOS_STKY; 265 | }; 266 | 267 | class Si5351 268 | { 269 | public: 270 | Si5351(void); 271 | void init(uint8_t, uint32_t); 272 | uint8_t set_freq(uint64_t, uint64_t, enum si5351_clock); 273 | void set_pll(uint64_t, enum si5351_pll); 274 | void set_ms(enum si5351_clock, struct Si5351RegSet, uint8_t, uint8_t, uint8_t); 275 | void output_enable(enum si5351_clock, uint8_t); 276 | void drive_strength(enum si5351_clock, enum si5351_drive); 277 | void update_status(void); 278 | void set_correction(int32_t); 279 | void set_phase(enum si5351_clock, uint8_t); 280 | int32_t get_correction(void); 281 | void pll_reset(enum si5351_pll); 282 | void set_ms_source(enum si5351_clock, enum si5351_pll); 283 | void set_int(enum si5351_clock, uint8_t); 284 | void set_clock_pwr(enum si5351_clock, uint8_t); 285 | void set_clock_invert(enum si5351_clock, uint8_t); 286 | void set_clock_source(enum si5351_clock, enum si5351_clock_source); 287 | void set_clock_disable(enum si5351_clock, enum si5351_clock_disable); 288 | void set_clock_fanout(enum si5351_clock_fanout, uint8_t); 289 | uint8_t si5351_write_bulk(uint8_t, uint8_t, uint8_t *); 290 | uint8_t si5351_write(uint8_t, uint8_t); 291 | uint8_t si5351_read(uint8_t); 292 | struct Si5351Status dev_status; 293 | struct Si5351IntStatus dev_int_status; 294 | uint64_t plla_freq; 295 | uint64_t pllb_freq; 296 | uint64_t clk0_freq; 297 | uint64_t clk1_freq; 298 | uint64_t clk2_freq; 299 | uint8_t clk0_int_mode, clk1_int_mode, clk2_int_mode; 300 | private: 301 | uint64_t pll_calc(uint64_t, struct Si5351RegSet *, int32_t); 302 | uint64_t multisynth_calc(uint64_t, uint64_t, struct Si5351RegSet *); 303 | void update_sys_status(struct Si5351Status *); 304 | void update_int_status(struct Si5351IntStatus *); 305 | void ms_div(enum si5351_clock, uint8_t, uint8_t); 306 | uint8_t select_r_div(uint64_t *); 307 | int32_t ref_correction; 308 | uint8_t lock_plla, lock_pllb; 309 | uint32_t xtal_freq; 310 | }; 311 | 312 | #endif /* SI5351_H_ */ 313 | -------------------------------------------------------------------------------- /libraries/TimerOne/TimerOne.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328 3 | * Original code by Jesse Tane for http://labs.ideo.com August 2008 4 | * Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support 5 | * Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop 6 | * Modified June 2011 by Lex Talionis to add a function to read the timer 7 | * Modified Oct 2011 by Andrew Richards to avoid certain problems: 8 | * - Add (long) assignments and casts to TimerOne::read() to ensure calculations involving tmp, ICR1 and TCNT1 aren't truncated 9 | * - Ensure 16 bit registers accesses are atomic - run with interrupts disabled when accessing 10 | * - Remove global enable of interrupts (sei())- could be running within an interrupt routine) 11 | * - Disable interrupts whilst TCTN1 == 0. Datasheet vague on this, but experiment shows that overflow interrupt 12 | * flag gets set whilst TCNT1 == 0, resulting in a phantom interrupt. Could just set to 1, but gets inaccurate 13 | * at very short durations 14 | * - startBottom() added to start counter at 0 and handle all interrupt enabling. 15 | * - start() amended to enable interrupts 16 | * - restart() amended to point at startBottom() 17 | * Modiied 7:26 PM Sunday, October 09, 2011 by Lex Talionis 18 | * - renamed start() to resume() to reflect it's actual role 19 | * - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off 20 | * 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, or 24 | * (at your option) any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | * 34 | * See Google Code project http://code.google.com/p/arduino-timerone/ for latest 35 | */ 36 | #ifndef TIMERONE_cpp 37 | #define TIMERONE_cpp 38 | 39 | #include "TimerOne.h" 40 | 41 | TimerOne Timer1; // preinstatiate 42 | 43 | ISR(TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt 44 | { 45 | Timer1.isrCallback(); 46 | } 47 | 48 | 49 | void TimerOne::initialize(long microseconds) 50 | { 51 | TCCR1A = 0; // clear control register A 52 | TCCR1B = _BV(WGM13); // set mode 8: phase and frequency correct pwm, stop the timer 53 | setPeriod(microseconds); 54 | } 55 | 56 | 57 | void TimerOne::setPeriod(long microseconds) // AR modified for atomic access 58 | { 59 | 60 | long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2 61 | if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal 62 | else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8 63 | else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64 64 | else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256 65 | else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024 66 | else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum 67 | 68 | oldSREG = SREG; 69 | cli(); // Disable interrupts for 16 bit register access 70 | ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode 71 | SREG = oldSREG; 72 | 73 | TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); 74 | TCCR1B |= clockSelectBits; // reset clock select register, and starts the clock 75 | } 76 | 77 | void TimerOne::setPwmDuty(char pin, int duty) 78 | { 79 | unsigned long dutyCycle = pwmPeriod; 80 | 81 | dutyCycle *= duty; 82 | dutyCycle >>= 10; 83 | 84 | oldSREG = SREG; 85 | cli(); 86 | if(pin == 1 || pin == 9) OCR1A = dutyCycle; 87 | else if(pin == 2 || pin == 10) OCR1B = dutyCycle; 88 | SREG = oldSREG; 89 | } 90 | 91 | void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024) 92 | { 93 | if(microseconds > 0) setPeriod(microseconds); 94 | if(pin == 1 || pin == 9) { 95 | DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin 96 | TCCR1A |= _BV(COM1A1); // activates the output pin 97 | } 98 | else if(pin == 2 || pin == 10) { 99 | DDRB |= _BV(PORTB2); 100 | TCCR1A |= _BV(COM1B1); 101 | } 102 | setPwmDuty(pin, duty); 103 | resume(); // Lex - make sure the clock is running. We don't want to restart the count, in case we are starting the second WGM 104 | // and the first one is in the middle of a cycle 105 | } 106 | 107 | void TimerOne::disablePwm(char pin) 108 | { 109 | if(pin == 1 || pin == 9) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1 110 | else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2 111 | } 112 | 113 | void TimerOne::attachInterrupt(void (*isr)(), long microseconds) 114 | { 115 | if(microseconds > 0) setPeriod(microseconds); 116 | isrCallback = isr; // register the user's callback with the real ISR 117 | TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit 118 | // might be running with interrupts disabled (eg inside an ISR), so don't touch the global state 119 | // sei(); 120 | resume(); 121 | } 122 | 123 | void TimerOne::detachInterrupt() 124 | { 125 | TIMSK1 &= ~_BV(TOIE1); // clears the timer overflow interrupt enable bit 126 | // timer continues to count without calling the isr 127 | } 128 | 129 | void TimerOne::resume() // AR suggested 130 | { 131 | TCCR1B |= clockSelectBits; 132 | } 133 | 134 | void TimerOne::restart() // Depricated - Public interface to start at zero - Lex 10/9/2011 135 | { 136 | start(); 137 | } 138 | 139 | void TimerOne::start() // AR addition, renamed by Lex to reflect it's actual role 140 | { 141 | unsigned int tcnt1; 142 | 143 | TIMSK1 &= ~_BV(TOIE1); // AR added 144 | GTCCR |= _BV(PSRSYNC); // AR added - reset prescaler (NB: shared with all 16 bit timers); 145 | 146 | oldSREG = SREG; // AR - save status register 147 | cli(); // AR - Disable interrupts 148 | TCNT1 = 0; 149 | SREG = oldSREG; // AR - Restore status register 150 | resume(); 151 | do { // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt 152 | oldSREG = SREG; 153 | cli(); 154 | tcnt1 = TCNT1; 155 | SREG = oldSREG; 156 | } while (tcnt1==0); 157 | 158 | // TIFR1 = 0xff; // AR - Clear interrupt flags 159 | // TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit 160 | } 161 | 162 | void TimerOne::stop() 163 | { 164 | TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits 165 | } 166 | 167 | unsigned long TimerOne::read() //returns the value of the timer in microseconds 168 | { //rember! phase and freq correct mode counts up to then down again 169 | unsigned long tmp; // AR amended to hold more than 65536 (could be nearly double this) 170 | unsigned int tcnt1; // AR added 171 | 172 | oldSREG= SREG; 173 | cli(); 174 | tmp=TCNT1; 175 | SREG = oldSREG; 176 | 177 | char scale=0; 178 | switch (clockSelectBits) 179 | { 180 | case 1:// no prescalse 181 | scale=0; 182 | break; 183 | case 2:// x8 prescale 184 | scale=3; 185 | break; 186 | case 3:// x64 187 | scale=6; 188 | break; 189 | case 4:// x256 190 | scale=8; 191 | break; 192 | case 5:// x1024 193 | scale=10; 194 | break; 195 | } 196 | 197 | do { // Nothing -- max delay here is ~1023 cycles. AR modified 198 | oldSREG = SREG; 199 | cli(); 200 | tcnt1 = TCNT1; 201 | SREG = oldSREG; 202 | } while (tcnt1==tmp); //if the timer has not ticked yet 203 | 204 | //if we are counting down add the top value to how far we have counted down 205 | tmp = ( (tcnt1>tmp) ? (tmp) : (long)(ICR1-tcnt1)+(long)ICR1 ); // AR amended to add casts and reuse previous TCNT1 206 | return ((tmp*1000L)/(F_CPU /1000L))<. 33 | * 34 | * See Google Code project http://code.google.com/p/arduino-timerone/ for latest 35 | */ 36 | #ifndef TIMERONE_h 37 | #define TIMERONE_h 38 | 39 | #include 40 | #include 41 | 42 | #define RESOLUTION 65536 // Timer1 is 16 bit 43 | 44 | class TimerOne 45 | { 46 | public: 47 | 48 | // properties 49 | unsigned int pwmPeriod; 50 | unsigned char clockSelectBits; 51 | char oldSREG; // To hold Status Register while ints disabled 52 | 53 | // methods 54 | void initialize(long microseconds=1000000); 55 | void start(); 56 | void stop(); 57 | void restart(); 58 | void resume(); 59 | unsigned long read(); 60 | void pwm(char pin, int duty, long microseconds=-1); 61 | void disablePwm(char pin); 62 | void attachInterrupt(void (*isr)(), long microseconds=-1); 63 | void detachInterrupt(); 64 | void setPeriod(long microseconds); 65 | void setPwmDuty(char pin, int duty); 66 | void (*isrCallback)(); 67 | }; 68 | 69 | extern TimerOne Timer1; 70 | #endif -------------------------------------------------------------------------------- /libraries/TimerOne/examples/ISRBlink/ISRBlink.pde: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void setup() 4 | { 5 | // Initialize the digital pin as an output. 6 | // Pin 13 has an LED connected on most Arduino boards 7 | pinMode(13, OUTPUT); 8 | 9 | Timer1.initialize(100000); // set a timer of length 100000 microseconds (or 0.1 sec - or 10Hz => the led will blink 5 times, 5 cycles of on-and-off, per second) 10 | Timer1.attachInterrupt( timerIsr ); // attach the service routine here 11 | } 12 | 13 | void loop() 14 | { 15 | // Main code loop 16 | // TODO: Put your regular (non-ISR) logic here 17 | } 18 | 19 | /// -------------------------- 20 | /// Custom ISR Timer Routine 21 | /// -------------------------- 22 | void timerIsr() 23 | { 24 | // Toggle LED 25 | digitalWrite( 13, digitalRead( 13 ) ^ 1 ); 26 | } -------------------------------------------------------------------------------- /libraries/TimerOne/examples/ReadReciver/.svn/all-wcprops: -------------------------------------------------------------------------------- 1 | K 25 2 | svn:wc:ra_dav:version-url 3 | V 51 4 | /svn/!svn/ver/3/trunk/Release%20Quality/ReadReciver 5 | END 6 | ReadReciver.pde 7 | K 25 8 | svn:wc:ra_dav:version-url 9 | V 67 10 | /svn/!svn/ver/7/trunk/Release%20Quality/ReadReciver/ReadReciver.pde 11 | END 12 | -------------------------------------------------------------------------------- /libraries/TimerOne/examples/ReadReciver/.svn/dir-prop-base: -------------------------------------------------------------------------------- 1 | K 14 2 | bugtraq:number 3 | V 4 4 | true 5 | END 6 | -------------------------------------------------------------------------------- /libraries/TimerOne/examples/ReadReciver/.svn/entries: -------------------------------------------------------------------------------- 1 | 10 2 | 3 | dir 4 | 6 5 | https://lex-arduino-sketchbook.googlecode.com/svn/trunk/Release%20Quality/ReadReciver 6 | https://lex-arduino-sketchbook.googlecode.com/svn 7 | 8 | 9 | 10 | 2011-06-24T22:05:24.141546Z 11 | 3 12 | lex.v.talionis@gmail.com 13 | has-props 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | c9f85be5-ce43-0359-81d1-43f08a9217a6 28 | 29 | ReadReciver.pde 30 | file 31 | 7 32 | 33 | 34 | 35 | 2011-06-25T03:21:57.149370Z 36 | 7554a9104cd32bca8710cff214402bb2 37 | 2011-06-25T03:22:33.720706Z 38 | 7 39 | lex.v.talionis@gmail.com 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 3527 62 | 63 | -------------------------------------------------------------------------------- /libraries/TimerOne/examples/ReadReciver/.svn/text-base/ReadReciver.pde.svn-base: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011 Lex Talionis (Lex.V.Talionis at gmail) 3 | This program is free software: you can redistribute it 4 | and/or modify it under the terms of the GNU General Public 5 | License as published by the Free Software Foundation, 6 | either version 3 of the License, or (at your option) any 7 | later version. 8 | 9 | This uses pin change interrupts and timer 1 to mesure the 10 | time between the rise and fall of 3 channels of PPM 11 | (Though often called PWM, see http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1253149521/all) 12 | on a typical RC car reciver. It could be extended to as 13 | many channels as you like. 14 | 15 | */ 16 | #include // http://www.arduino.cc/playground/Main/PinChangeInt 17 | #include 18 | #include // http://www.arduino.cc/playground/Code/Timer1 19 | 20 | #define NO_PORTB_PINCHANGES //PinChangeInt setup 21 | #define NO_PORTC_PINCHANGES //only port D pinchanges (see: http://www.arduino.cc/playground/Learning/Pins) 22 | #define PIN_COUNT 3 //number of channels attached to the reciver 23 | #define MAX_PIN_CHANGE_PINS PIN_COUNT 24 | 25 | #define RC_TURN 3 //arduino pins attached to the reciver 26 | #define RC_FWD 2 27 | #define RC_FIRE 4 28 | byte pin[] = {RC_FWD, RC_TURN, RC_FIRE}; //for maximum efficency thise pins should be attached 29 | unsigned int time[] = {0,0,0}; // to the reciver's channels in the order listed here 30 | 31 | byte state=0; 32 | byte burp=0; // a counter to see how many times the int has executed 33 | byte cmd=0; // a place to put our serial data 34 | byte i=0; // global counter for tracking what pin we are on 35 | 36 | void setup() { 37 | Serial.begin(115200); 38 | Serial.print("PinChangeInt ReciverReading test"); 39 | Serial.println(); //warm up the serial port 40 | 41 | Timer1.initialize(2200); //longest pulse in PPM is usally 2.1 milliseconds, 42 | //pick a period that gives you a little headroom. 43 | Timer1.stop(); //stop the counter 44 | Timer1.restart(); //set the clock to zero 45 | 46 | for (byte i=0; i<3; i++) 47 | { 48 | pinMode(pin[i], INPUT); //set the pin to input 49 | digitalWrite(pin[i], HIGH); //use the internal pullup resistor 50 | } 51 | PCintPort::attachInterrupt(pin[i], rise,RISING); // attach a PinChange Interrupt to our first pin 52 | } 53 | 54 | void loop() { 55 | 56 | cmd=Serial.read(); //while you got some time gimme a systems report 57 | if (cmd=='p') 58 | { 59 | Serial.print("time:\t"); 60 | for (byte i=0; i // http://www.arduino.cc/playground/Main/PinChangeInt 17 | #include 18 | #include // http://www.arduino.cc/playground/Code/Timer1 19 | 20 | #define NO_PORTB_PINCHANGES //PinChangeInt setup 21 | #define NO_PORTC_PINCHANGES //only port D pinchanges (see: http://www.arduino.cc/playground/Learning/Pins) 22 | #define PIN_COUNT 3 //number of channels attached to the reciver 23 | #define MAX_PIN_CHANGE_PINS PIN_COUNT 24 | 25 | #define RC_TURN 3 //arduino pins attached to the reciver 26 | #define RC_FWD 2 27 | #define RC_FIRE 4 28 | byte pin[] = {RC_FWD, RC_TURN, RC_FIRE}; //for maximum efficency thise pins should be attached 29 | unsigned int time[] = {0,0,0}; // to the reciver's channels in the order listed here 30 | 31 | byte state=0; 32 | byte burp=0; // a counter to see how many times the int has executed 33 | byte cmd=0; // a place to put our serial data 34 | byte i=0; // global counter for tracking what pin we are on 35 | 36 | void setup() { 37 | Serial.begin(115200); 38 | Serial.print("PinChangeInt ReciverReading test"); 39 | Serial.println(); //warm up the serial port 40 | 41 | Timer1.initialize(2200); //longest pulse in PPM is usally 2.1 milliseconds, 42 | //pick a period that gives you a little headroom. 43 | Timer1.stop(); //stop the counter 44 | Timer1.restart(); //set the clock to zero 45 | 46 | for (byte i=0; i<3; i++) 47 | { 48 | pinMode(pin[i], INPUT); //set the pin to input 49 | digitalWrite(pin[i], HIGH); //use the internal pullup resistor 50 | } 51 | PCintPort::attachInterrupt(pin[i], rise,RISING); // attach a PinChange Interrupt to our first pin 52 | } 53 | 54 | void loop() { 55 | 56 | cmd=Serial.read(); //while you got some time gimme a systems report 57 | if (cmd=='p') 58 | { 59 | Serial.print("time:\t"); 60 | for (byte i=0; i