Compare commits

..

5 Commits

10 changed files with 2581 additions and 298 deletions

View File

@@ -31,6 +31,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/ **************************************************************************/
/*
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
//27 + 10 + 18 + 1(SPACE) = //56 //27 + 10 + 18 + 1(SPACE) = //56
@@ -312,7 +313,7 @@ void controlAutoCW(){
autoCWSendReservCount = 0; //Init Reserve Count autoCWSendReservCount = 0; //Init Reserve Count
isAutoCWHold = 0; isAutoCWHold = 0;
if (!inTx){ //if not TX Status, change RX -> TX if (!inTx){ //if not TX Status, change RX -> TX
keyDown = false; keyDown = 0;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
updateDisplay(); updateDisplay();
@@ -344,7 +345,7 @@ void controlAutoCW(){
if (isAutoCWHold == 0 && (millis() - autoCWbeforeTime > cwSpeed * 3)) if (isAutoCWHold == 0 && (millis() - autoCWbeforeTime > cwSpeed * 3))
{ {
if (!inTx){ //if not TX Status, change RX -> TX if (!inTx){ //if not TX Status, change RX -> TX
keyDown = false; keyDown = 0;
startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time startTx(TX_CW, 0); //disable updateDisplay Command for reduce latency time
} }
@@ -398,3 +399,4 @@ void controlAutoCW(){
} }
} }
*/

View File

@@ -20,9 +20,9 @@
#include <Arduino.h> //for Linux, On Linux it is case sensitive. #include <Arduino.h> //for Linux, On Linux it is case sensitive.
//============================================================================== //==============================================================================
// Compile-Time Options // Compile Option
//============================================================================== //==============================================================================
// uBITX Board Version - KC4UPR: updated to v5 //Ubitx Board Version
#define UBITX_BOARD_VERSION 5 //v1 ~ v4 : 4, v5: 5 #define UBITX_BOARD_VERSION 5 //v1 ~ v4 : 4, v5: 5
//Depending on the type of LCD mounted on the uBITX, uncomment one of the options below. //Depending on the type of LCD mounted on the uBITX, uncomment one of the options below.
@@ -39,9 +39,12 @@
#define I2C_LCD_SECOND_ADDRESS_DEFAULT 0x3F //0x27 //only using Dual LCD Mode #define I2C_LCD_SECOND_ADDRESS_DEFAULT 0x3F //0x27 //only using Dual LCD Mode
//Select betwen Analog S-Meter and DSP (I2C) Meter //Select betwen Analog S-Meter and DSP (I2C) Meter
#define USE_I2CSMETER //#define USE_I2CSMETER
#define EXTEND_KEY_GROUP1 //MODE, BAND(-), BAND(+), STEP // Use alternate keyer?
#define USE_ALTKEYER
//#define EXTEND_KEY_GROUP1 //MODE, BAND(-), BAND(+), STEP
//#define EXTEND_KEY_GROUP2 //Numeric (0~9), Point(.), Enter //Not supported in Version 1.0x //#define EXTEND_KEY_GROUP2 //Numeric (0~9), Point(.), Enter //Not supported in Version 1.0x
//Custom LPF Filter Mod //Custom LPF Filter Mod
@@ -214,14 +217,17 @@ extern byte I2C_LCD_SECOND_ADDRESS; //only using Dual LCD Mode
#define ENC_A (A0) #define ENC_A (A0)
#define ENC_B (A1) #define ENC_B (A1)
#define FBUTTON (A2) #define FBUTTON (A2)
#define PTT (A3) // 8? #define PTT (A3)
#define DIGITAL_KEY (A3) // 8?
#define DIGITAL_DOT (12)
#define DIGITAL_DASH (11)
#define ANALOG_KEYER (A6) #define ANALOG_KEYER (A6)
#define ANALOG_SPARE (A7) #define ANALOG_SPARE (A7)
#define ANALOG_SMETER (A7) //by KD8CEC #define ANALOG_SMETER (A7) //by KD8CEC
#ifdef USE_ALTKEYER
#define DIGITAL_DOT (11) // can't remember if I need to swap still???
#define DIGITAL_DASH (12)
#define DIGITAL_KEY (A3)
#endif
/** /**
* The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig. * The second set of 16 pins on the Raduino's bottom connector are have the three clock outputs and the digital lines to control the rig.
* This assignment is as follows : * This assignment is as follows :
@@ -335,4 +341,22 @@ extern void DisplayVersionInfo(const char* fwVersionInfo);
//I2C Signal Meter, Version 1.097 //I2C Signal Meter, Version 1.097
extern int GetI2CSmeterValue(int valueType); //ubitx_ui.ino extern int GetI2CSmeterValue(int valueType); //ubitx_ui.ino
#define DIT_L 0x01 // DIT latch
#define DAH_L 0x02 // DAH latch
#define DIT_PROC 0x04 // DIT is being processed
#define PDLSWAP 0x08
enum KSTYPE {IDLE, CHK_DIT, CHK_DAH, KEYED_PREP, KEYED, INTER_ELEMENT };
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B
// For compatibility w/ W0EB code
#define MODE_USB 0
#define MODE_LSB 1
#define MODE_CW 2
#define MODE_CWR 3
#define MODE_SWU 4
#define MODE_SWL 5
#define PTT_HNDKEY_DEBOUNCE_CT 2
#endif //end of if header define #endif //end of if header define

View File

@@ -1,4 +1,4 @@
//Firmware Version //Firmware Version
//+ : This symbol identifies the firmware. //+ : This symbol identifies the firmware.
// It was originally called 'CEC V1.072' but it is too long to waste the LCD window. // It was originally called 'CEC V1.072' but it is too long to waste the LCD window.
// I do not want to make this Firmware users's uBITX messy with my callsign. // I do not want to make this Firmware users's uBITX messy with my callsign.
@@ -9,6 +9,8 @@
#define FIRMWARE_VERSION_INFO F("+v1.200") #define FIRMWARE_VERSION_INFO F("+v1.200")
#define FIRMWARE_VERSION_NUM 0x04 //1st Complete Project : 1 (Version 1.061), 2st Project : 2, 1.08: 3, 1.09 : 4 #define FIRMWARE_VERSION_NUM 0x04 //1st Complete Project : 1 (Version 1.061), 2st Project : 2, 1.08: 3, 1.09 : 4
extern void Connect_Interrupts(void);
/** /**
Cat Suppoort uBITX CEC Version Cat Suppoort uBITX CEC Version
This firmware has been gradually changed based on the original firmware created by Farhan, Jack, Jerry and others. This firmware has been gradually changed based on the original firmware created by Farhan, Jack, Jerry and others.
@@ -53,8 +55,6 @@
#include "ubitx.h" #include "ubitx.h"
#include "ubitx_eemap.h" #include "ubitx_eemap.h"
extern void Connect_Interrupts(void);
/** /**
* The uBITX is an upconnversion transceiver. The first IF is at 45 MHz. * The uBITX is an upconnversion transceiver. The first IF is at 45 MHz.
* The first IF frequency is not exactly at 45 Mhz but about 5 khz lower, * The first IF frequency is not exactly at 45 Mhz but about 5 khz lower,
@@ -126,7 +126,7 @@ unsigned long vfoA=7150000L, vfoB=14200000L, sideTone=800, usbCarrier, cwmCarrie
unsigned long vfoA_eeprom, vfoB_eeprom; //for protect eeprom life unsigned long vfoA_eeprom, vfoB_eeprom; //for protect eeprom life
unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial unsigned long frequency, ritRxFrequency, ritTxFrequency; //frequency is the current frequency on the dial
int cwSpeed = 100; //this is actuall the dot period in milliseconds unsigned int cwSpeed = 100; //this is actuall the dot period in milliseconds
extern int32_t calibration; extern int32_t calibration;
//for store the mode in eeprom //for store the mode in eeprom
@@ -167,12 +167,7 @@ int cwAdcBothFrom = 0;
int cwAdcBothTo = 0; int cwAdcBothTo = 0;
byte cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb byte cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
bool Iambic_Key = true; bool Iambic_Key = true;
#define IAMBICB 0x10 // 0 for Iambic A, 1 for Iambic B unsigned char keyerControl = IAMBICB;
volatile unsigned char keyerControl = 0; // IAMBICB;
volatile unsigned char keyerState = 0;
volatile unsigned char IAMBIC = 0x10; // 0 for Iambic A, 1 for Iambic B
volatile unsigned char PDLSWAP = 0x00; // 0x00 for normal, 0x08 for swap
byte isShiftDisplayCWFreq = 1; //Display Frequency byte isShiftDisplayCWFreq = 1; //Display Frequency
int shiftDisplayAdjustVal = 0; // int shiftDisplayAdjustVal = 0; //
@@ -193,8 +188,8 @@ byte userCallsignLength = 0; //7 : display callsign at system startup, 6~0 :
/** /**
* Raduino needs to keep track of current state of the transceiver. These are a few variables that do it * Raduino needs to keep track of current state of the transceiver. These are a few variables that do it
*/ */
bool txCAT = false; // 'True' if transmitting due to CAT command. volatile boolean txCAT = false; //turned on if the transmitting due to a CAT command
volatile bool inTx = false; // 'True' if transmitting (regardless of source: CW, PTT, or CAT) bool inTx = false; //it is set to 1 if in transmit mode (whatever the reason : cw, ptt or cat)
char splitOn = 0; //working split, uses VFO B as the transmit frequency char splitOn = 0; //working split, uses VFO B as the transmit frequency
//char keyDown = 0; //in cw mode, denotes the carrier is being transmitted //char keyDown = 0; //in cw mode, denotes the carrier is being transmitted
char isUSB = 0; //upper sideband was selected, this is reset to the default for the char isUSB = 0; //upper sideband was selected, this is reset to the default for the
@@ -318,6 +313,7 @@ void saveBandFreqByIndex(unsigned long f, unsigned long mode, char bandIndex) {
When the delay is used, the program will generate an error because it is not communicating, When the delay is used, the program will generate an error because it is not communicating,
so Create a new delay function that can do background processing. so Create a new delay function that can do background processing.
*/ */
unsigned long delayBeforeTime = 0; unsigned long delayBeforeTime = 0;
byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWKey -> Check Paddle byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWKey -> Check Paddle
delayBeforeTime = millis(); delayBeforeTime = millis();
@@ -327,11 +323,11 @@ byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWK
if (fromType == 4) if (fromType == 4)
{ {
//CHECK PADDLE //CHECK PADDLE
if (getPaddle() != 0) //Interrupt : Stop cw Auto mode by Paddle -> Change Auto to Manual // if (getPaddle() != 0) //Interrupt : Stop cw Auto mode by Paddle -> Change Auto to Manual
return 1; // return 1;
//Check PTT while auto Sending //Check PTT while auto Sending
autoSendPTTCheck(); //autoSendPTTCheck();
Check_Cat(3); Check_Cat(3);
} }
@@ -344,6 +340,7 @@ byte delay_background(unsigned delayTime, byte fromType){ //fromType : 4 autoCWK
return 0; return 0;
} }
/** /**
@@ -450,7 +447,7 @@ void setFrequency(unsigned long f){
f = (f / arTuneStep[tuneStepIndex -1]) * arTuneStep[tuneStepIndex -1]; f = (f / arTuneStep[tuneStepIndex -1]) * arTuneStep[tuneStepIndex -1];
setTXFilters(f); setTXFilters(f);
unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && !inTx) ? ifShiftValue : 0)); unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (!inTx) ? ifShiftValue : 0));
int appliedTuneValue = 0; int appliedTuneValue = 0;
//applied if tune //applied if tune
@@ -460,7 +457,7 @@ void setFrequency(unsigned long f){
appliedTuneValue = if1TuneValue; appliedTuneValue = if1TuneValue;
//In the LSB state, the optimum reception value was found. To apply to USB, 3Khz decrease is required. //In the LSB state, the optimum reception value was found. To apply to USB, 3Khz decrease is required.
if (sdrModeOn && !inTx) if (sdrModeOn && (!inTx))
appliedTuneValue -= 15; //decrease 1.55Khz appliedTuneValue -= 15; //decrease 1.55Khz
//if (isUSB) //if (isUSB)
@@ -470,13 +467,13 @@ void setFrequency(unsigned long f){
//if1Tune RX, TX Enabled, ATT : only RX Mode //if1Tune RX, TX Enabled, ATT : only RX Mode
//The IF Tune shall be measured at the LSB. Then, move the 3Khz down for USB. //The IF Tune shall be measured at the LSB. Then, move the 3Khz down for USB.
long if1AdjustValue = (!inTx ? (attLevel * 100) : 0) + (appliedTuneValue * 100); //if1Tune RX, TX Enabled, ATT : only RX Mode //5600 long if1AdjustValue = ((!inTx) ? (attLevel * 100) : 0) + (appliedTuneValue * 100); //if1Tune RX, TX Enabled, ATT : only RX Mode //5600
//for DIY uBITX (custom filter) //for DIY uBITX (custom filter)
if ((advancedFreqOption1 & 0x80) != 0x00) //Reverse IF Tune (- Value for DIY uBITX) if ((advancedFreqOption1 & 0x80) != 0x00) //Reverse IF Tune (- Value for DIY uBITX)
if1AdjustValue *= -1; if1AdjustValue *= -1;
if (sdrModeOn && !inTx) //IF SDR MODE if (sdrModeOn && (!inTx)) //IF SDR MODE
{ {
//Fixed Frequency SDR (Default Frequency : 32Mhz, available change sdr Frequency by uBITX Manager) //Fixed Frequency SDR (Default Frequency : 32Mhz, available change sdr Frequency by uBITX Manager)
//Dynamic Frequency is for SWL without cat //Dynamic Frequency is for SWL without cat
@@ -551,7 +548,7 @@ void setFrequency(unsigned long f){
* put the uBitx in tx mode. It takes care of rit settings, sideband settings * put the uBitx in tx mode. It takes care of rit settings, sideband settings
* Note: In cw mode, doesnt key the radio, only puts it in tx mode * Note: In cw mode, doesnt key the radio, only puts it in tx mode
*/ */
void startTx(byte txMode, byte isDisplayUpdate){ void startTx(byte txMode, byte isDisplayUpdate = 0){
//Check Hamband only TX //Not found Hamband index by now frequency //Check Hamband only TX //Not found Hamband index by now frequency
if (tuneTXType >= 100 && getIndexHambanBbyFreq(ritOn ? ritTxFrequency : frequency) == -1) { if (tuneTXType >= 100 && getIndexHambanBbyFreq(ritOn ? ritTxFrequency : frequency) == -1) {
//no message //no message
@@ -621,6 +618,8 @@ void startTx(byte txMode, byte isDisplayUpdate){
//reduce latency time when begin of CW mode //reduce latency time when begin of CW mode
if (isDisplayUpdate == 1) if (isDisplayUpdate == 1)
updateDisplay(); updateDisplay();
Serial.println("exiting startTx()");
} }
void stopTx(void){ void stopTx(void){
@@ -1298,6 +1297,11 @@ void initPorts(){
pinMode(ANALOG_KEYER, INPUT_PULLUP); pinMode(ANALOG_KEYER, INPUT_PULLUP);
pinMode(ANALOG_SMETER, INPUT); //by KD8CEC pinMode(ANALOG_SMETER, INPUT); //by KD8CEC
#ifdef USE_ALTKEYER
pinMode(DIGITAL_DOT, INPUT_PULLUP);
pinMode(DIGITAL_DASH, INPUT_PULLUP);
#endif
#ifdef USE_CUSTOM_LPF_FILTER #ifdef USE_CUSTOM_LPF_FILTER
if (isCustomFilter_A7) if (isCustomFilter_A7)
{ {
@@ -1439,6 +1443,7 @@ void setup()
#endif #endif
Connect_Interrupts(); Connect_Interrupts();
} }
//Auto save Frequency and Mode with Protected eeprom life by KD8CEC //Auto save Frequency and Mode with Protected eeprom life by KD8CEC
@@ -1467,14 +1472,21 @@ void checkAutoSaveFreqMode()
void loop(){ void loop(){
if (isCWAutoMode == 0){ //when CW AutoKey Mode, disable this process if (isCWAutoMode == 0){ //when CW AutoKey Mode, disable this process
if (!txCAT) #ifdef USE_ALTKEYER
checkPTT(); // when using the alternate keyer, don't check the PTT if we're in CW mode, because
// the PTT is also a straight key
// if (!txCAT && (cwMode == 0))
// checkPTT();
#else
// if (!txCAT)
// checkPTT();
#endif
checkButton(); checkButton();
} }
else else
controlAutoCW(); ; //controlAutoCW();
cwKeyer(); //cwKeyer();
//tune only when not tranmsitting //tune only when not tranmsitting
if (!inTx){ if (!inTx){
@@ -1494,6 +1506,7 @@ void loop(){
} //end of check TX Status } //end of check TX Status
//we check CAT after the encoder as it might put the radio into TX //we check CAT after the encoder as it might put the radio into TX
// Maybe make this do all four versions of Check_Cat depending on state
Check_Cat(inTx ? 1 : 0); Check_Cat(inTx ? 1 : 0);
//for SEND SW Serial //for SEND SW Serial

View File

@@ -10,107 +10,91 @@
* and putting the local oscillator directly at the CW transmit frequency. * and putting the local oscillator directly at the CW transmit frequency.
* The sidetone, generated by the Arduino is injected into the volume control * The sidetone, generated by the Arduino is injected into the volume control
*/ */
#include <Arduino.h>
#include "ubitx.h" #include "ubitx.h"
#include <Arduino.h>
extern void stopTx(void); extern void stopTx(void);
extern void startTx(byte txMode, byte isDisplayUpdate); extern void startTx(byte txMode, byte isDisplayUpdate = 0);
extern unsigned long sideTone; extern unsigned long sideTone;
extern int cwSpeed; extern int cwSpeed;
// extern long CW_TIMEOUT;
extern long cwTimeout;
#define CW_TIMEOUT (cwTimeout)
extern volatile bool inTx; extern volatile bool inTx;
//extern volatile int ubitx_mode; // extern volatile int ubitx_mode;
extern char isUSB; extern char isUSB;
extern char cwMode; extern char cwMode;
extern volatile unsigned char keyerControl; extern volatile unsigned char keyerControl;
extern volatile unsigned char keyerState; // extern volatile unsigned char keyerState;
extern unsigned volatile char IAMBIC; volatile unsigned char keyerState = IDLE;
extern unsigned volatile char PDLSWAP; // extern unsigned volatile char IAMBICB;
// extern unsigned volatile char PDLSWAP;
volatile bool keyDown = false; //in cw mode, denotes the carrier is being transmitted // extern volatile unsigned long Ubitx_Voltage;
volatile uint8_t Last_Bits = 0xFF;; // extern volatile int Ubitx_Voltage_Timer;
volatile bool keyDown = false; // in cw mode, denotes the carrier is being transmitted
volatile uint8_t Last_Bits = 0xFF;
;
volatile bool Dot_in_Progress = false; volatile bool Dot_in_Progress = false;
volatile unsigned long Dot_Timer_Count = 0; volatile unsigned long Dot_Timer_Count = 0;
volatile bool Dash_in_Progress = false; volatile bool Dash_in_Progress = false;
volatile unsigned long Dash_Timer_Count = 0; volatile unsigned long Dash_Timer_Count = 0;
volatile bool Inter_Bit_in_Progress = false; volatile bool Inter_Bit_in_Progress = false;
volatile unsigned long Inter_Bit_Timer_Count = 0; volatile unsigned long Inter_Bit_Timer_Count = 0;
volatile bool Turn_Off_Carrier_in_Progress = false; volatile bool Turn_Off_Carrier_in_Progress = false;
volatile unsigned long Turn_Off_Carrier_Timer_Count = 0; volatile unsigned long Turn_Off_Carrier_Timer_Count = 0;
volatile bool Ubitx_Voltage_Act = false;
volatile bool PTT_HANDKEY_ACTIVE = false; volatile bool PTT_HANDKEY_ACTIVE = false;
volatile long last_interrupt_time = 20; volatile long last_interrupt_time = 20;
// extern bool Cat_Lock;
extern bool txCAT; // extern volatile bool TX_In_Progress;
extern volatile bool txCAT;
// KC4UPR: These are some temporary (maybe?) translation macros to translate
// between the mode selection code in W0EB's software, versus the mode
// selection code in the basic (and CEC) software. I may replace this is the
// future, either by reworking the whole codebase to use the (superior) W0EB
// method, or else by modifying the keyer code to use the stock mode selection
// code.
#define MODE_USB 0
#define MODE_LSB 1
#define MODE_CW 2
#define MODE_CWR 3
#define ubitx_mode (cwMode == 0 ? (isUSB == 0) : ((cwMode == 1) + 2))
/* KC4UPR: Temporary holding ground for definitions etc that may need to get moved to other files. */
//#define DIGITAL_PTT (A3)
//#define DIGITAL_DOT (D11)
//#define DIGITAL_DASH (D12)
/*
Arduino Pin MC Pin Interrupt Mask
A3/D17 PC3 PCINT[11] PCMSK1/bit 3
D11 PB3 PCINT[3] PCMSK0/bit 3
D12 PB4 PCINT[4] PCMSK0/bit 4
*/
/** /**
* Starts transmitting the carrier with the sidetone * Starts transmitting the carrier with the sidetone
* It assumes that we have called cwTxStart and not called cwTxStop * It assumes that we have called cwTxStart and not called cwTxStop
* each time it is called, the cwTimeOut is pushed further into the future * each time it is called, the cwTimeOut is pushed further into the future
*/ */
void cwKeyDown(void) { void cwKeydown(void) {
keyDown = true; //tracks the CW_KEY keyDown = 1; // tracks the CW_KEY
tone(CW_TONE, (int)sideTone); tone(CW_TONE, (int)sideTone);
digitalWrite(CW_KEY, 1); digitalWrite(CW_KEY, 1);
#ifdef XMIT_LED #ifdef XMIT_LED
digitalWrite(ON_AIR, 0); // extinguish the LED on NANO's pin 13 digitalWrite(ON_AIR, 0); // extinguish the LED on NANO's pin 13
#endif #endif
} }
/** /**
* Stops the CW carrier transmission along with the sidetone * Stops the CW carrier transmission along with the sidetone
* Pushes the cwTimeout further into the future * Pushes the cwTimeout further into the future
*/ */
void cwKeyUp(void) { void cwKeyUp(void) {
keyDown = false; //tracks the CW_KEY keyDown = 0; // tracks the CW_KEY
noTone(CW_TONE); noTone(CW_TONE);
digitalWrite(CW_KEY, 0); digitalWrite(CW_KEY, 0);
#ifdef XMIT_LED #ifdef XMIT_LED
digitalWrite(ON_AIR, 1); // extinguish the LED on NANO's pin 13 digitalWrite(ON_AIR, 1); // extinguish the LED on NANO's pin 13
#endif #endif
} }
void update_PaddleLatch() { void update_PaddleLatch() {
if (digitalRead(DIGITAL_DOT) == LOW) { // if (!digitalRead(DIGITAL_DOT) ) keyerControl |= DIT_L;
if (keyerControl & PDLSWAP) // if (!digitalRead(DIGITAL_DASH) ) keyerControl |= DAH_L;
keyerControl |= DAH_L; if (digitalRead(DIGITAL_DOT) == LOW) {
else if (keyerControl & PDLSWAP)
keyerControl |= DIT_L; keyerControl |= DAH_L;
} else
if (digitalRead(DIGITAL_DASH) == LOW) { keyerControl |= DIT_L;
if (keyerControl & PDLSWAP) }
keyerControl |= DIT_L; if (digitalRead(DIGITAL_DASH) == LOW) {
else if (keyerControl & PDLSWAP)
keyerControl |= DAH_L; keyerControl |= DIT_L;
} else
keyerControl |= DAH_L;
}
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
@@ -118,204 +102,199 @@ void update_PaddleLatch() {
//// timers //// timers
ISR(TIMER1_OVF_vect) { ISR(TIMER1_OVF_vect) {
bool continue_loop = true; static volatile bool i_am_running = false;
bool continue_loop = true;
// process if CW modes if (i_am_running) return;
if ((ubitx_mode == MODE_CW) || (ubitx_mode == MODE_CWR)) { i_am_running = true;
// process DOT and DASH timing // process if CW modes
if (Dot_in_Progress && (Dot_Timer_Count > 0)) { // if( (ubitx_mode == MODE_CW)||(ubitx_mode == MODE_CWR)){
if (!inTx) { if (cwMode > 0) {
keyDown = false;
startTx(TX_CW, 0); // process DOT and DASH timing
} if ((Dot_in_Progress) && (Dot_Timer_Count > 0)) {
if (!keyDown) if (!inTx) {
cwKeyDown(); keyDown = 0;
Dot_Timer_Count = Dot_Timer_Count - 1; startTx(TX_CW);
if (Dot_Timer_Count <= 0) { }
Dot_Timer_Count = 0; if (keyDown == 0)
Dot_in_Progress = false; cwKeydown();
cwKeyUp(); Dot_Timer_Count = Dot_Timer_Count - 1;
} if (Dot_Timer_Count <= 0) {
Dot_Timer_Count = 0;
Dot_in_Progress = false;
cwKeyUp();
}
}
// process Inter Bit Timing
if ((Inter_Bit_in_Progress) && (Inter_Bit_Timer_Count > 0)) {
Inter_Bit_Timer_Count = Inter_Bit_Timer_Count - 1;
if (Inter_Bit_Timer_Count <= 0) {
Inter_Bit_Timer_Count = 0;
Inter_Bit_in_Progress = false;
}
}
// process turning off carrier
if ((Turn_Off_Carrier_in_Progress) && (Turn_Off_Carrier_Timer_Count > 0)) {
Turn_Off_Carrier_Timer_Count = Turn_Off_Carrier_Timer_Count - 1;
if (Turn_Off_Carrier_Timer_Count <= 0) {
Turn_Off_Carrier_in_Progress = false;
Turn_Off_Carrier_Timer_Count = 0;
stopTx();
}
}
// process hand key
if (digitalRead(DIGITAL_KEY) == 0) {
// If interrupts come faster than 5ms, assume it's a bounce and ignore
last_interrupt_time = last_interrupt_time - 1;
if (last_interrupt_time <= 0) {
last_interrupt_time = 0;
if (!inTx) {
keyDown = 0;
startTx(TX_CW);
} }
if (keyDown == 0)
cwKeydown();
PTT_HANDKEY_ACTIVE = true;
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT;
}
} else if ((keyDown == 1) && (PTT_HANDKEY_ACTIVE == true)) {
cwKeyUp();
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT;
Turn_Off_Carrier_in_Progress = true;
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
PTT_HANDKEY_ACTIVE = false;
} else
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
// process Inter Bit Timing if (PTT_HANDKEY_ACTIVE == false) {
if (Inter_Bit_in_Progress && (Inter_Bit_Timer_Count > 0)) { while (continue_loop) {
Inter_Bit_Timer_Count = Inter_Bit_Timer_Count - 1; switch (keyerState) {
if (Inter_Bit_Timer_Count <= 0) { case IDLE:
Inter_Bit_Timer_Count = 0; if ((!digitalRead(DIGITAL_DOT)) || (!digitalRead(DIGITAL_DASH)) ||
Inter_Bit_in_Progress = false; (keyerControl & 0x03)) {
} update_PaddleLatch();
} keyerState = CHK_DIT;
Dot_in_Progress = false;
Dot_Timer_Count = 0;
Turn_Off_Carrier_Timer_Count = 0;
Turn_Off_Carrier_in_Progress = false;
} else {
continue_loop = false;
}
break;
// process turning off carrier case CHK_DIT:
if (Turn_Off_Carrier_in_Progress && (Turn_Off_Carrier_Timer_Count > 0)) { if (keyerControl & DIT_L) {
Turn_Off_Carrier_Timer_Count = Turn_Off_Carrier_Timer_Count - 1; keyerControl |= DIT_PROC;
if (Turn_Off_Carrier_Timer_Count <= 0) { keyerState = KEYED_PREP;
Turn_Off_Carrier_in_Progress = false; Dot_Timer_Count = cwSpeed;
Turn_Off_Carrier_Timer_Count = 0; } else {
stopTx(); keyerState = CHK_DAH;
} }
} break;
// process hand key case CHK_DAH:
if (digitalRead(DIGITAL_KEY) == LOW) { if (keyerControl & DAH_L) {
// If interrupts come faster than 5ms, assume it's a bounce and ignore keyerState = KEYED_PREP;
last_interrupt_time = last_interrupt_time - 1; Dot_Timer_Count = cwSpeed * 3;
if (last_interrupt_time <= 0) { } else {
last_interrupt_time = 0; continue_loop = false;
if (!inTx) { keyerState = IDLE;
keyDown = false; }
startTx(TX_CW, 0); break;
}
if (!keyDown) case KEYED_PREP:
cwKeyDown(); keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
PTT_HANDKEY_ACTIVE = true; keyerState = KEYED; // next state
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT; Turn_Off_Carrier_Timer_Count = 0;
} Turn_Off_Carrier_in_Progress = false;
} else if (keyDown && PTT_HANDKEY_ACTIVE) { Dot_in_Progress = true;
cwKeyUp(); break;
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT;
case KEYED:
if (Dot_in_Progress == false) { // are we at end of key down ?
Inter_Bit_in_Progress = true;
Inter_Bit_Timer_Count = cwSpeed;
keyerState = INTER_ELEMENT; // next state
} else if (keyerControl & IAMBICB) {
update_PaddleLatch(); // early paddle latch in Iambic B mode
continue_loop = false;
} else
continue_loop = false;
break;
case INTER_ELEMENT:
// Insert time between dits/dahs
update_PaddleLatch(); // latch paddle state
if (Inter_Bit_in_Progress == false) { // are we at end of inter-space ?
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT;
Turn_Off_Carrier_in_Progress = true; Turn_Off_Carrier_in_Progress = true;
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT; if (keyerControl & DIT_PROC) { // was it a dit or dah ?
PTT_HANDKEY_ACTIVE = false; keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
} else { keyerState = CHK_DAH; // dit done, check for dah
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT; } else {
} keyerControl &= ~(DAH_L); // clear dah latch
keyerState = IDLE; // go idle
if (!PTT_HANDKEY_ACTIVE) {
while (continue_loop) {
switch (keyerState) {
case IDLE:
if ((digitalRead(DIGITAL_DOT) == LOW) ||
(digitalRead(DIGITAL_DASH) == LOW) ||
(keyerControl & 0x03)) {
update_PaddleLatch();
keyerState = CHK_DIT;
Dot_in_Progress = false;
Dot_Timer_Count = 0;
Turn_Off_Carrier_Timer_Count = 0;
Turn_Off_Carrier_in_Progress = false;
} else {
continue_loop = false;
}
break;
case CHK_DIT:
if (keyerControl & DIT_L) {
keyerControl |= DIT_PROC;
keyerState = KEYED_PREP;
Dot_Timer_Count = cwSpeed;
} else {
keyerState = CHK_DAH;
}
break;
case CHK_DAH:
if (keyerControl & DAH_L) {
keyerState = KEYED_PREP;
Dot_Timer_Count = cwSpeed*3;
} else {
continue_loop = false;
keyerState = IDLE;
}
break;
case KEYED_PREP:
keyerControl &= ~(DIT_L + DAH_L); // clear both paddle latch bits
keyerState = KEYED; // next state
Turn_Off_Carrier_Timer_Count = 0;
Turn_Off_Carrier_in_Progress = false;
Dot_in_Progress = true;
break;
case KEYED:
if (!Dot_in_Progress) { // are we at end of key down ?
Inter_Bit_in_Progress = true;
Inter_Bit_Timer_Count = cwSpeed;
keyerState = INTER_ELEMENT; // next state
} else if (keyerControl & IAMBIC) {
update_PaddleLatch(); // early paddle latch in Iambic B mode
continue_loop = false;
} else continue_loop = false;
break;
case INTER_ELEMENT:
// Insert time between dits/dahs
update_PaddleLatch(); // latch paddle state
if (!Inter_Bit_in_Progress) { // are we at end of inter-space ?
Turn_Off_Carrier_Timer_Count = CW_TIMEOUT;
Turn_Off_Carrier_in_Progress = true;
if (keyerControl & DIT_PROC) { // was it a dit or dah ?
keyerControl &= ~(DIT_L + DIT_PROC); // clear two bits
keyerState = CHK_DAH; // dit done, check for dah
} else {
keyerControl &= ~(DAH_L); // clear dah latch
keyerState = IDLE; // go idle
}
} else continue_loop = false;
break;
}
} }
} else
continue_loop = false;
break;
} }
}
} }
}
// process PTT // process PTT
if ((ubitx_mode == MODE_USB) || (ubitx_mode == MODE_LSB)) { // if( (ubitx_mode == MODE_USB)|| (ubitx_mode == MODE_LSB)){
if (digitalRead(PTT) == LOW) { if (cwMode == 0) {
// If interrupts come faster than 5ms, assume it's a bounce and ignore if (digitalRead(PTT) == 0) {
last_interrupt_time = last_interrupt_time - 1; // If interrupts come faster than 5ms, assume it's a bounce and ignore
if (last_interrupt_time <= 0) { last_interrupt_time = last_interrupt_time - 1;
last_interrupt_time = 0; if (last_interrupt_time <= 0) {
if (!inTx) { last_interrupt_time = 0;
startTx(TX_SSB, 0); if (!inTx)
} startTx(TX_SSB);
} }
} else if (inTx && !txCAT) { } else if ((inTx) && (txCAT == false)) {
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT; last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
stopTx(); stopTx();
} else { } else
last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT; last_interrupt_time = PTT_HNDKEY_DEBOUNCE_CT;
} }
}
i_am_running = false;
} }
void Connect_Interrupts(void) { void Connect_Interrupts(void) {
keyerControl = 0; keyerControl = 0;
cli(); cli();
TIMSK1 |= (1 << TOIE1);
PCMSK0 |- 0b00011000; // turn on dot/dash pins PB3/PB4, physical D11/D12 sei();
PCMSK1 |= 0b00001000; // turn on PTT and Handkey pin PC3, physical A3
PCICR |= 0b00000011; // turn on ports B and C
TIMSK1 |= (1<<TOIE1);
sei();
} }
/*
#define N_MORSE (sizeof(morsetab)/sizeof(morsetab[0])) #define N_MORSE (sizeof(morsetab)/sizeof(morsetab[0]))
// Morse table // Morse table
struct t_mtab { struct t_mtab { char c, pat; } ;
char c, pat;
} ;
struct t_mtab morsetab[] = { struct t_mtab morsetab[] = {
{'.', 106}, {',', 115}, {'?', 76}, {'/', 41}, {'A', 6}, {'B', 17}, {'C', 21}, {'D', 9}, {'.', 106}, {',', 115}, {'?', 76}, {'/', 41}, {'A', 6}, {'B', 17}, {'C', 21}, {'D', 9},
{'E', 2}, {'F', 20}, {'G', 11}, {'H', 16}, {'I', 4}, {'J', 30}, {'K', 13}, {'L', 18}, {'E', 2}, {'F', 20}, {'G', 11}, {'H', 16}, {'I', 4}, {'J', 30}, {'K', 13}, {'L', 18},
{'M', 7}, {'N', 5}, {'O', 15}, {'P', 22}, {'Q', 27}, {'R', 10}, {'S', 8}, {'T', 3}, {'M', 7}, {'N', 5}, {'O', 15}, {'P', 22}, {'Q', 27}, {'R', 10}, {'S', 8}, {'T', 3},
{'U', 12}, {'V', 24}, {'W', 14}, {'X', 25}, {'Y', 29}, {'Z', 19}, {'1', 62}, {'2', 60}, {'U', 12}, {'V', 24}, {'W', 14}, {'X', 25}, {'Y', 29}, {'Z', 19}, {'1', 62}, {'2', 60},
{'3', 56}, {'4', 48}, {'5', 32}, {'6', 33}, {'7', 35}, {'8', 39}, {'9', 47}, {'0', 63} {'3', 56}, {'4', 48}, {'5', 32}, {'6', 33}, {'7', 35}, {'8', 39}, {'9', 47}, {'0', 63}
}; };
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
// CW generation routines for CQ message // CW generation routines for CQ message
void key(int LENGTH) { void key(int LENGTH){
if( !inTx ) startTx(TX_CW, 0); if( !inTx ) startTx(TX_CW);
cwKeyDown(); cwKeydown();
delay(LENGTH*2); delay(LENGTH*2);
cwKeyUp(); cwKeyUp();
delay(cwSpeed*2); delay(cwSpeed*2);
@@ -323,34 +302,35 @@ void key(int LENGTH) {
} }
void send(char c) { void send(char c){
int i ; int i ;
if (c == ' ') { if (c == ' ') {
delay(7*cwSpeed) ; delay(7*cwSpeed) ;
return ; return ;
} }
for (i=0; i<N_MORSE; i++) { for (i=0; i<N_MORSE; i++){
if (morsetab[i].c == c) { if (morsetab[i].c == c){
unsigned char p = morsetab[i].pat ; unsigned char p = morsetab[i].pat ;
while (p != 1) { while (p != 1) {
if (p & 1) Dot_Timer_Count = cwSpeed*3; if (p & 1) Dot_Timer_Count = cwSpeed*3;
else Dot_Timer_Count = cwSpeed; else Dot_Timer_Count = cwSpeed;
key(Dot_Timer_Count); key(Dot_Timer_Count);
p = p / 2 ; p = p / 2 ;
} }
delay(cwSpeed*5) ; delay(cwSpeed*5) ;
return ; return ;
}
} }
}
} }
void sendmsg(char *str) { void sendmsg(char *str){
while (*str) send(*str++); while (*str) send(*str++);
delay(650); delay(650);
stopTx(); stopTx();
} }
*/

790
ubitx_20/ubitx_lcd_1602.ino Normal file
View File

@@ -0,0 +1,790 @@
/*************************************************************************
KD8CEC's uBITX Display Routine for LCD1602 Parrel
1.This is the display code for the default LCD mounted in uBITX.
2.Some functions moved from uBITX_Ui.
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#include "ubitx.h"
#include "ubitx_lcd.h"
//========================================================================
//Begin of TinyLCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD1602P
/*************************************************************************
LCD1602_TINY Library for 16 x 2 LCD
Referecnce Source : LiquidCrystal.cpp
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
DE Ian KD8CEC
**************************************************************************/
#define LCD_Command(x) (LCD_Send(x, LOW))
#define LCD_Write(x) (LCD_Send(x, HIGH))
#define UBITX_DISPLAY_LCD1602_BASE
//Define connected PIN
#define LCD_PIN_RS 8
#define LCD_PIN_EN 9
uint8_t LCD_PIN_DAT[4] = {10, 11, 12, 13};
void write4bits(uint8_t value)
{
for (int i = 0; i < 4; i++)
digitalWrite(LCD_PIN_DAT[i], (value >> i) & 0x01);
digitalWrite(LCD_PIN_EN, LOW);
delayMicroseconds(1);
digitalWrite(LCD_PIN_EN, HIGH);
delayMicroseconds(1); // enable pulse must be >450ns
digitalWrite(LCD_PIN_EN, LOW);
delayMicroseconds(100); // commands need > 37us to settle
}
void LCD_Send(uint8_t value, uint8_t mode)
{
digitalWrite(LCD_PIN_RS, mode);
write4bits(value>>4);
write4bits(value);
}
void LCD1602_Init()
{
pinMode(LCD_PIN_RS, OUTPUT);
pinMode(LCD_PIN_EN, OUTPUT);
for (int i = 0; i < 4; i++)
pinMode(LCD_PIN_DAT[i], OUTPUT);
delayMicroseconds(50);
// Now we pull both RS and R/W low to begin commands
digitalWrite(LCD_PIN_RS, LOW);
digitalWrite(LCD_PIN_EN, LOW);
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
}
#endif
//========================================================================
//End of TinyLCD Library by KD8CEC
//========================================================================
//========================================================================
//Begin of I2CTinyLCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD1602I
#include <Wire.h>
/*************************************************************************
I2C Tiny LCD Library
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal_I2C Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
Ian KD8CEC
**************************************************************************/
#define UBITX_DISPLAY_LCD1602_BASE
#define En B00000100 // Enable bit
#define Rw B00000010 // Read/Write bit
#define Rs B00000001 // Register select bit
#define LCD_Command(x) (LCD_Send(x, 0))
#define LCD_Write(x) (LCD_Send(x, Rs))
uint8_t _Addr;
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _numlines;
uint8_t _cols;
uint8_t _rows;
uint8_t _backlightval;
#define printIIC(args) Wire.write(args)
void expanderWrite(uint8_t _data)
{
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission();
}
void pulseEnable(uint8_t _data){
expanderWrite(_data | En); // En high
delayMicroseconds(1); // enable pulse must be >450ns
expanderWrite(_data & ~En); // En low
delayMicroseconds(50); // commands need > 37us to settle
}
void write4bits(uint8_t value)
{
expanderWrite(value);
pulseEnable(value);
}
void LCD_Send(uint8_t value, uint8_t mode)
{
uint8_t highnib=value&0xf0;
uint8_t lownib=(value<<4)&0xf0;
write4bits((highnib)|mode);
write4bits((lownib)|mode);
}
// Turn the (optional) backlight off/on
void noBacklight(void) {
_backlightval=LCD_NOBACKLIGHT;
expanderWrite(0);
}
void backlight(void) {
_backlightval=LCD_BACKLIGHT;
expanderWrite(0);
}
void LCD1602_Init()
{
//I2C Init
_Addr = I2C_LCD_MASTER_ADDRESS;
_cols = 16;
_rows = 2;
_backlightval = LCD_NOBACKLIGHT;
Wire.begin();
delay(50);
// Now we pull both RS and R/W low to begin commands
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
delay(1000);
//put the LCD into 4 bit mode
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03 << 4);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02 << 4);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
//delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(1000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
backlight();
}
/*
void LCD_Print(const char *c)
{
for (uint8_t i = 0; i < strlen(c); i++)
{
if (*(c + i) == 0x00) return;
LCD_Write(*(c + i));
}
}
void LCD_SetCursor(uint8_t col, uint8_t row)
{
LCD_Command(LCD_SETDDRAMADDR | (col + row * 0x40)); //0 : 0x00, 1 : 0x40, only for 16 x 2 lcd
}
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
LCD_Write(charmap[i]);
}
*/
#endif
//========================================================================
//End of I2CTinyLCD Library by KD8CEC
//========================================================================
//========================================================================
// 16 X 02 LCD Routines
//Begin of Display Base Routines (Init, printLine..)
//========================================================================
#ifdef UBITX_DISPLAY_LCD1602_BASE
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
#define OPTION_SKINNYBARS
char c[30], b[30];
char printBuff[2][17]; //mirrors what is showing on the two lines of the display
void LCD_Print(const char *c)
{
for (uint8_t i = 0; i < strlen(c); i++)
{
if (*(c + i) == 0x00) return;
LCD_Write(*(c + i));
}
}
void LCD_SetCursor(uint8_t col, uint8_t row)
{
LCD_Command(LCD_SETDDRAMADDR | (col + row * 0x40)); //0 : 0x00, 1 : 0x40, only for 16 x 2 lcd
}
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
LCD_Write(charmap[i]);
}
void LCD_Init(void)
{
LCD1602_Init();
initMeter(); //for Meter Display
}
// The generic routine to display one line on the LCD
void printLine(unsigned char linenmbr, const char *c) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
LCD_SetCursor(0, linenmbr); // place the cursor at the beginning of the selected line
LCD_Print(c);
strcpy(printBuff[linenmbr], c);
for (byte i = strlen(c); i < 16; i++) { // add white spaces until the end of the 16 characters line is reached
LCD_Write(' ');
}
}
}
void printLineF(char linenmbr, const __FlashStringHelper *c)
{
int i;
char tmpBuff[17];
PGM_P p = reinterpret_cast<PGM_P>(c);
for (i = 0; i < 17; i++){
unsigned char fChar = pgm_read_byte(p++);
tmpBuff[i] = fChar;
if (fChar == 0)
break;
}
printLine(linenmbr, tmpBuff);
}
#define LCD_MAX_COLUMN 16
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
LCD_SetCursor(lcdColumn, linenmbr);
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
{
if (++lcdColumn <= LCD_MAX_COLUMN)
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
else
break;
}
for (byte i = lcdColumn; i < 16; i++) //Right Padding by Space
LCD_Write(' ');
}
// short cut to print to the first line
void printLine1(const char *c)
{
printLine(1,c);
}
// short cut to print to the first line
void printLine2(const char *c)
{
printLine(0,c);
}
void clearLine2()
{
printLine2("");
line2DisplayStatus = 0;
}
// short cut to print to the first line
void printLine1Clear(){
printLine(1,"");
}
// short cut to print to the first line
void printLine2Clear(){
printLine(0, "");
}
void printLine2ClearAndUpdate(){
printLine(0, "");
line2DisplayStatus = 0;
updateDisplay();
}
//==================================================================================
//End of Display Base Routines
//==================================================================================
//==================================================================================
//Begin of User Interface Routines
//==================================================================================
//Main Display
// this builds up the top line of the display with frequency and mode
void updateDisplay() {
// tks Jack Purdum W8TEE
// replaced fsprint commmands by str commands for code size reduction
// replace code for Frequency numbering error (alignment, point...) by KD8CEC
int i;
unsigned long tmpFreq = frequency; //
memset(c, 0, sizeof(c));
if (inTx){
if (isCWAutoMode == 2) {
for (i = 0; i < 4; i++)
c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' ');
//display Sending Index
c[4] = byteToChar(sendingCWTextIndex);
c[5] = '=';
}
else {
if (cwTimeout > 0)
strcpy(c, " CW:");
else
strcpy(c, " TX:");
}
}
else {
if (ritOn)
strcpy(c, "RIT ");
else {
if (cwMode == 0)
{
if (isUSB)
strcpy(c, "USB ");
else
strcpy(c, "LSB ");
}
else if (cwMode == 1)
{
strcpy(c, "CWL ");
}
else
{
strcpy(c, "CWU ");
}
}
if (vfoActive == VFO_A) // VFO A is active
strcat(c, "A:");
else
strcat(c, "B:");
}
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
//display frequency
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
//remarked by KD8CEC
//already RX/TX status display, and over index (16 x 2 LCD)
//if (inTx)
// strcat(c, " TX");
printLine(1, c);
byte diplayVFOLine = 1;
if ((displayOption1 & 0x01) == 0x01)
diplayVFOLine = 0;
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
LCD_SetCursor(5,diplayVFOLine);
LCD_Write((uint8_t)0);
}
else if (isCWAutoMode == 2){
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(0x7E);
}
else
{
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(':');
}
}
char line2Buffer[17];
//KD8CEC 200Hz ST
//L14.150 200Hz ST
//U14.150 +150khz
int freqScrollPosition = 0;
//Example Line2 Optinal Display
//immediate execution, not call by scheulder
//warning : unused parameter 'displayType' <-- ignore, this is reserve
void updateLine2Buffer(char displayType)
{
unsigned long tmpFreq = 0;
if (ritOn)
{
strcpy(line2Buffer, "RitTX:");
//display frequency
tmpFreq = ritTxFrequency;
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
return;
} //end of ritOn display
//other VFO display
if (vfoActive == VFO_B)
{
tmpFreq = vfoA;
}
else
{
tmpFreq = vfoB;
}
// EXAMPLE 1 & 2
//U14.150.100
//display frequency
for (int i = 9; i >= 0; i--) {
if (tmpFreq > 0) {
if (i == 2 || i == 6) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
//EXAMPLE #1
if ((displayOption1 & 0x04) == 0x00) //none scroll display
line2Buffer[6] = 'M';
else
{
//example #2
if (freqScrollPosition++ > 18) //none scroll display time
{
line2Buffer[6] = 'M';
if (freqScrollPosition > 25)
freqScrollPosition = -1;
}
else //scroll frequency
{
line2Buffer[10] = 'H';
line2Buffer[11] = 'z';
if (freqScrollPosition < 7)
{
for (int i = 11; i >= 0; i--)
if (i - (7 - freqScrollPosition) >= 0)
line2Buffer[i] = line2Buffer[i - (7 - freqScrollPosition)];
else
line2Buffer[i] = ' ';
}
else
{
for (int i = 0; i < 11; i++)
if (i + (freqScrollPosition - 7) <= 11)
line2Buffer[i] = line2Buffer[i + (freqScrollPosition - 7)];
else
line2Buffer[i] = ' ';
}
}
} //scroll
line2Buffer[7] = ' ';
if (isIFShift)
{
// if (isDirectCall == 1)
// for (int i = 0; i < 16; i++)
// line2Buffer[i] = ' ';
//IFShift Offset Value
line2Buffer[8] = 'I';
line2Buffer[9] = 'F';
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
line2Buffer[11] = 0;
line2Buffer[12] = ' ';
//11, 12, 13, 14, 15
memset(b, 0, sizeof(b));
ltoa(ifShiftValue, b, DEC);
strncat(line2Buffer, b, 5);
//if (isDirectCall == 1) //if call by encoder (not scheduler), immediate print value
printLine2(line2Buffer);
} // end of display IF
else // step & Key Type display
{
//if (isDirectCall != 0)
// return;
memset(&line2Buffer[8], ' ', 8);
//Step
long tmpStep = arTuneStep[tuneStepIndex -1];
byte isStepKhz = 0;
if (tmpStep >= 1000)
{
isStepKhz = 2;
}
for (int i = 10; i >= 8 - isStepKhz; i--) {
if (tmpStep > 0) {
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
tmpStep /= 10;
}
else
line2Buffer[i +isStepKhz] = ' ';
}
if (isStepKhz == 0)
{
line2Buffer[11] = 'H';
line2Buffer[12] = 'z';
}
line2Buffer[13] = ' ';
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
if (sdrModeOn == 1)
{
line2Buffer[13] = 'S';
line2Buffer[14] = 'D';
line2Buffer[15] = 'R';
}
else if (cwKeyType == 0)
{
line2Buffer[14] = 'S';
line2Buffer[15] = 'T';
}
else if (cwKeyType == 1)
{
line2Buffer[14] = 'I';
line2Buffer[15] = 'A';
}
else
{
line2Buffer[14] = 'I';
line2Buffer[15] = 'B';
}
}
}
//meterType : 0 = S.Meter, 1 : P.Meter
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
{
if (meterType == 0 || meterType == 1 || meterType == 2)
{
drawMeter(meterValue);
int lineNumber = 0;
if ((displayOption1 & 0x01) == 0x01)
lineNumber = 1;
LCD_SetCursor(drawPosition, lineNumber);
LCD_Write(lcdMeter[0]);
LCD_Write(lcdMeter[1]);
LCD_Write(lcdMeter[2]);
}
}
char checkCount = 0;
char checkCountSMeter = 0;
void idle_process()
{
//space for user graphic display
if (menuOn == 0)
{
if ((displayOption1 & 0x10) == 0x10) //always empty topline
return;
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
if (checkCount++ > 1)
{
updateLine2Buffer(0); //call by scheduler
printLine2(line2Buffer);
line2DisplayStatus = 2;
checkCount = 0;
}
}
//S-Meter Display
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
{
int newSMeter;
#ifdef USE_I2CSMETER
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
#else
//VK2ETA S-Meter from MAX9814 TC pin / divide 4 by KD8CEC for reduce EEPromSize
newSMeter = analogRead(ANALOG_SMETER) / 4;
//Faster attack, Slower release
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10) / 4;
currentSMeter = newSMeter;
scaledSMeter = 0;
for (byte s = 8; s >= 1; s--) {
if (currentSMeter > sMeterLevels[s]) {
scaledSMeter = s;
break;
}
}
#endif
DisplayMeter(0, scaledSMeter, 13);
checkCountSMeter = 0; //Reset Latency time
} //end of S-Meter
}
}
//AutoKey LCD Display Routine
void Display_AutoKeyTextIndex(byte textIndex)
{
byte diplayAutoCWLine = 0;
if ((displayOption1 & 0x01) == 0x01)
diplayAutoCWLine = 1;
LCD_SetCursor(0, diplayAutoCWLine);
LCD_Write(byteToChar(textIndex));
LCD_Write(':');
}
void DisplayCallsign(byte callSignLength)
{
printLineFromEEPRom(0, 0, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
//delay(500);
}
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
{
printLineF(1, fwVersionInfo);
}
#endif

View File

@@ -0,0 +1,727 @@
/*************************************************************************
KD8CEC's uBITX Display Routine for LCD1602 Dual LCD
1.This is the display code for the 16x02 Dual LCD
2.Some functions moved from uBITX_Ui.
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#include "ubitx.h"
#include "ubitx_lcd.h"
//========================================================================
//Begin of I2CTinyLCD Library for Dual LCD by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD1602I_DUAL
#include <Wire.h>
/*************************************************************************
I2C Tiny LCD Library
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal_I2C Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
Ian KD8CEC
**************************************************************************/
#define UBITX_DISPLAY_LCD1602_BASE
#define En B00000100 // Enable bit
#define Rw B00000010 // Read/Write bit
#define Rs B00000001 // Register select bit
#define LCD_Command(x) (LCD_Send(x, 0))
#define LCD_Write(x) (LCD_Send(x, Rs))
uint8_t _Addr;
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _numlines;
uint8_t _cols;
uint8_t _rows;
uint8_t _backlightval;
#define printIIC(args) Wire.write(args)
void expanderWrite(uint8_t _data)
{
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission();
}
void pulseEnable(uint8_t _data){
expanderWrite(_data | En); // En high
delayMicroseconds(1); // enable pulse must be >450ns
expanderWrite(_data & ~En); // En low
delayMicroseconds(50); // commands need > 37us to settle
}
void write4bits(uint8_t value)
{
expanderWrite(value);
pulseEnable(value);
}
void LCD_Send(uint8_t value, uint8_t mode)
{
uint8_t highnib=value&0xf0;
uint8_t lownib=(value<<4)&0xf0;
write4bits((highnib)|mode);
write4bits((lownib)|mode);
}
// Turn the (optional) backlight off/on
void noBacklight(void) {
_backlightval=LCD_NOBACKLIGHT;
expanderWrite(0);
}
void backlight(void) {
_backlightval=LCD_BACKLIGHT;
expanderWrite(0);
}
void LCD1602_Dual_Init()
{
//I2C Init
_cols = 16;
_rows = 2;
_backlightval = LCD_NOBACKLIGHT;
Wire.begin();
delay(50);
// Now we pull both RS and R/W low to begin commands
_Addr = I2C_LCD_MASTER_ADDRESS;
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
_Addr = I2C_LCD_SECOND_ADDRESS;
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
delay(1000);
//put the LCD into 4 bit mode
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
_Addr = I2C_LCD_MASTER_ADDRESS;
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03 << 4);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02 << 4);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
//delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(1000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
backlight();
_Addr = I2C_LCD_SECOND_ADDRESS;
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03 << 4);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02 << 4);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
//delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(1000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
backlight();
//Change to Default LCD (Master)
_Addr = I2C_LCD_MASTER_ADDRESS;
}
//========================================================================
// 16 X 02 LCD Routines
//Begin of Display Base Routines (Init, printLine..)
//========================================================================
void LCD_Print(const char *c)
{
for (uint8_t i = 0; i < strlen(c); i++)
{
if (*(c + i) == 0x00) return;
LCD_Write(*(c + i));
}
}
const int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
void LCD_SetCursor(uint8_t col, uint8_t row)
{
LCD_Command(LCD_SETDDRAMADDR | (col + row_offsets[row])); //0 : 0x00, 1 : 0x40, only for 20 x 4 lcd
}
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
LCD_Write(charmap[i]);
}
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
//#define OPTION_SKINNYBARS
char c[30], b[30];
char printBuff[4][20]; //mirrors what is showing on the two lines of the display
void LCD_Init(void)
{
LCD1602_Dual_Init();
_Addr = I2C_LCD_SECOND_ADDRESS;
initMeter(); //for Meter Display //when dual LCD, S.Meter on second LCD
_Addr = I2C_LCD_MASTER_ADDRESS;
}
// The generic routine to display one line on the LCD
void printLine(unsigned char linenmbr, const char *c) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
LCD_SetCursor(0, linenmbr); // place the cursor at the beginning of the selected line
LCD_Print(c);
strcpy(printBuff[linenmbr], c);
for (byte i = strlen(c); i < 20; i++) { // add white spaces until the end of the 20 characters line is reached
LCD_Write(' ');
}
}
}
void printLineF(char linenmbr, const __FlashStringHelper *c)
{
int i;
char tmpBuff[21];
PGM_P p = reinterpret_cast<PGM_P>(c);
for (i = 0; i < 21; i++){
unsigned char fChar = pgm_read_byte(p++);
tmpBuff[i] = fChar;
if (fChar == 0)
break;
}
printLine(linenmbr, tmpBuff);
}
#define LCD_MAX_COLUMN 20
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
LCD_SetCursor(lcdColumn, linenmbr);
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
{
if (++lcdColumn <= LCD_MAX_COLUMN)
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
else
break;
}
for (byte i = lcdColumn; i < 20; i++) //Right Padding by Space
LCD_Write(' ');
}
// short cut to print to the first line
void printLine1(const char *c)
{
printLine(1,c);
}
// short cut to print to the first line
void printLine2(const char *c)
{
printLine(0,c);
}
void clearLine2()
{
printLine2("");
line2DisplayStatus = 0;
}
// short cut to print to the first line
void printLine1Clear(){
printLine(1,"");
}
// short cut to print to the first line
void printLine2Clear(){
printLine(0, "");
}
void printLine2ClearAndUpdate(){
printLine(0, "");
line2DisplayStatus = 0;
updateDisplay();
}
//==================================================================================
//End of Display Base Routines
//==================================================================================
//==================================================================================
//Begin of User Interface Routines
//==================================================================================
//Main Display
// this builds up the top line of the display with frequency and mode
void updateDisplay() {
// tks Jack Purdum W8TEE
// replaced fsprint commmands by str commands for code size reduction
// replace code for Frequency numbering error (alignment, point...) by KD8CEC
// i also Very TNX Purdum for good source code
int i;
unsigned long tmpFreq = frequency; //
memset(c, 0, sizeof(c));
if (inTx){
if (isCWAutoMode == 2) {
for (i = 0; i < 4; i++)
c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' ');
//display Sending Index
c[4] = byteToChar(sendingCWTextIndex);
c[5] = '=';
}
else {
if (cwTimeout > 0)
strcpy(c, " CW:");
else
strcpy(c, " TX:");
}
}
else {
if (ritOn)
strcpy(c, "RIT ");
else {
if (cwMode == 0)
{
if (isUSB)
strcpy(c, "USB ");
else
strcpy(c, "LSB ");
}
else if (cwMode == 1)
{
strcpy(c, "CWL ");
}
else
{
strcpy(c, "CWU ");
}
}
if (vfoActive == VFO_A) // VFO A is active
strcat(c, "A:");
else
strcat(c, "B:");
}
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
//display frequency
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
//remarked by KD8CEC
//already RX/TX status display, and over index (16 x 2 LCD)
printLine(1, c);
byte diplayVFOLine = 1;
if ((displayOption1 & 0x01) == 0x01)
diplayVFOLine = 0;
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
LCD_SetCursor(5,diplayVFOLine);
LCD_Write((uint8_t)0);
}
else if (isCWAutoMode == 2){
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(0x7E);
}
else
{
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(':');
}
}
char line2Buffer[20];
//KD8CEC 200Hz ST
//L14.150 200Hz ST
//U14.150 +150khz
int freqScrollPosition = 0;
//Example Line2 Optinal Display
//immediate execution, not call by scheulder
//warning : unused parameter 'displayType' <-- ignore, this is reserve
void updateLine2Buffer(char displayType)
{
unsigned long tmpFreq = 0;
if (ritOn)
{
strcpy(line2Buffer, "RitTX:");
//display frequency
tmpFreq = ritTxFrequency;
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
return;
} //end of ritOn display
//other VFO display
if (vfoActive == VFO_B)
{
tmpFreq = vfoA;
}
else
{
tmpFreq = vfoB;
}
// EXAMPLE 1 & 2
//U14.150.100
//display frequency
for (int i = 9; i >= 0; i--) {
if (tmpFreq > 0) {
if (i == 2 || i == 6) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
memset(&line2Buffer[10], ' ', 10);
if (isIFShift)
{
line2Buffer[6] = 'M';
line2Buffer[7] = ' ';
//IFShift Offset Value
line2Buffer[8] = 'I';
line2Buffer[9] = 'F';
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
line2Buffer[11] = 0;
line2Buffer[12] = ' ';
//11, 12, 13, 14, 15
memset(b, 0, sizeof(b));
ltoa(ifShiftValue, b, DEC);
strncat(line2Buffer, b, 5);
for (int i = 12; i < 17; i++)
{
if (line2Buffer[i] == 0)
line2Buffer[i] = ' ';
}
} // end of display IF
else // step & Key Type display
{
//Step
long tmpStep = arTuneStep[tuneStepIndex -1];
byte isStepKhz = 0;
if (tmpStep >= 1000)
{
isStepKhz = 2;
}
for (int i = 13; i >= 11 - isStepKhz; i--) {
if (tmpStep > 0) {
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
tmpStep /= 10;
}
else
line2Buffer[i +isStepKhz] = ' ';
}
if (isStepKhz == 0)
{
line2Buffer[14] = 'H';
line2Buffer[15] = 'z';
}
}
//line2Buffer[17] = ' ';
/* ianlee
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
if (cwKeyType == 0)
{
line2Buffer[18] = 'S';
line2Buffer[19] = 'T';
}
else if (cwKeyType == 1)
{
line2Buffer[18] = 'I';
line2Buffer[19] = 'A';
}
else
{
line2Buffer[18] = 'I';
line2Buffer[19] = 'B';
}
*/
}
//meterType : 0 = S.Meter, 1 : P.Meter
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
{
if (meterType == 0 || meterType == 1 || meterType == 2)
{
drawMeter(meterValue);
LCD_SetCursor(drawPosition, 0);
LCD_Write('S');
LCD_Write(':');
for (int i = 0; i < 7; i++)
LCD_Write(lcdMeter[i]);
}
}
char checkCount = 0;
char checkCountSMeter = 0;
char beforeKeyType = -1;
char displaySDRON = 0;
//execute interval : 0.25sec
void idle_process()
{
//space for user graphic display
if (menuOn == 0)
{
if ((displayOption1 & 0x10) == 0x10) //always empty topline
return;
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
if (checkCount++ > 1)
{
updateLine2Buffer(0); //call by scheduler
printLine2(line2Buffer);
line2DisplayStatus = 2;
checkCount = 0;
//check change CW Key Type
if (beforeKeyType != cwKeyType)
{
_Addr = I2C_LCD_SECOND_ADDRESS;
LCD_SetCursor(10, 0);
LCD_Write('K');
LCD_Write('E');
LCD_Write('Y');
LCD_Write(':');
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
if (cwKeyType == 0)
{
LCD_Write('S');
LCD_Write('T');
}
else if (cwKeyType == 1)
{
LCD_Write('I');
LCD_Write('A');
}
else
{
LCD_Write('I');
LCD_Write('B');
}
beforeKeyType = cwKeyType;
_Addr = I2C_LCD_MASTER_ADDRESS;
} //Display Second Screen
}
}
//EX for Meters
//S-Meter Display
_Addr = I2C_LCD_SECOND_ADDRESS;
if (sdrModeOn == 1)
{
if (displaySDRON == 0) //once display
{
displaySDRON = 1;
LCD_SetCursor(0, 0);
LCD_Write('S');
LCD_Write('D');
LCD_Write('R');
LCD_Write(' ');
LCD_Write('M');
LCD_Write('O');
LCD_Write('D');
LCD_Write('E');
}
}
else if (((displayOption1 & 0x08) == 0x08) && (++checkCountSMeter > 3))
{
int newSMeter;
displaySDRON = 0;
#ifdef USE_I2CSMETER
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
#else
//VK2ETA S-Meter from MAX9814 TC pin / divide 4 by KD8CEC for reduce EEPromSize
newSMeter = analogRead(ANALOG_SMETER) / 4;
//Faster attack, Slower release
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10);
//currentSMeter = (currentSMeter * 3 + newSMeter * 7) / 10; //remarked becaused of have already Latency time
currentSMeter = newSMeter;
scaledSMeter = 0;
for (byte s = 8; s >= 1; s--) {
if (currentSMeter > sMeterLevels[s]) {
scaledSMeter = s;
break;
}
}
#endif
DisplayMeter(0, scaledSMeter, 0);
checkCountSMeter = 0;
} //end of S-Meter
_Addr = I2C_LCD_MASTER_ADDRESS;
}
}
//AutoKey LCD Display Routine
void Display_AutoKeyTextIndex(byte textIndex)
{
byte diplayAutoCWLine = 0;
if ((displayOption1 & 0x01) == 0x01)
diplayAutoCWLine = 1;
LCD_SetCursor(0, diplayAutoCWLine);
LCD_Write(byteToChar(textIndex));
LCD_Write(':');
}
void DisplayCallsign(byte callSignLength)
{
_Addr = I2C_LCD_SECOND_ADDRESS;
printLineFromEEPRom(1, 16 - userCallsignLength, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
_Addr = I2C_LCD_MASTER_ADDRESS;
}
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
{
_Addr = I2C_LCD_SECOND_ADDRESS;
printLineF(1, fwVersionInfo);
_Addr = I2C_LCD_MASTER_ADDRESS;
}
#endif

743
ubitx_20/ubitx_lcd_2004.ino Normal file
View File

@@ -0,0 +1,743 @@
/*************************************************************************
KD8CEC's uBITX Display Routine for LCD2004 Parrel & I2C
1.This is the display code for the 20x04 LCD
2.Some functions moved from uBITX_Ui.
-----------------------------------------------------------------------------
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
#include "ubitx.h"
#include "ubitx_lcd.h"
//========================================================================
//Begin of TinyLCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD2004P
/*************************************************************************
LCD2004TINY Library for 20 x 4 LCD
Referecnce Source : LiquidCrystal.cpp
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
DE Ian KD8CEC
**************************************************************************/
#define LCD_Command(x) (LCD_Send(x, LOW))
#define LCD_Write(x) (LCD_Send(x, HIGH))
#define UBITX_DISPLAY_LCD2004_BASE
//Define connected PIN
#define LCD_PIN_RS 8
#define LCD_PIN_EN 9
uint8_t LCD_PIN_DAT[4] = {10, 11, 12, 13};
void write4bits(uint8_t value)
{
for (int i = 0; i < 4; i++)
digitalWrite(LCD_PIN_DAT[i], (value >> i) & 0x01);
digitalWrite(LCD_PIN_EN, LOW);
delayMicroseconds(1);
digitalWrite(LCD_PIN_EN, HIGH);
delayMicroseconds(1); // enable pulse must be >450ns
digitalWrite(LCD_PIN_EN, LOW);
delayMicroseconds(100); // commands need > 37us to settle
}
void LCD_Send(uint8_t value, uint8_t mode)
{
digitalWrite(LCD_PIN_RS, mode);
write4bits(value>>4);
write4bits(value);
}
void LCD2004_Init()
{
pinMode(LCD_PIN_RS, OUTPUT);
pinMode(LCD_PIN_EN, OUTPUT);
for (int i = 0; i < 4; i++)
pinMode(LCD_PIN_DAT[i], OUTPUT);
delayMicroseconds(50);
// Now we pull both RS and R/W low to begin commands
digitalWrite(LCD_PIN_RS, LOW);
digitalWrite(LCD_PIN_EN, LOW);
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
delayMicroseconds(2000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
}
#endif
//========================================================================
//End of TinyLCD Library by KD8CEC
//========================================================================
//========================================================================
//Begin of I2CTinyLCD Library by KD8CEC
//========================================================================
#ifdef UBITX_DISPLAY_LCD2004I
#include <Wire.h>
/*************************************************************************
I2C Tiny LCD Library
Referecnce Source : LiquidCrystal_I2C.cpp // Based on the work by DFRobot
KD8CEC
This source code is modified version for small program memory
from Arduino LiquidCrystal_I2C Library
I wrote this code myself, so there is no license restriction.
So this code allows anyone to write with confidence.
But keep it as long as the original author of the code.
Ian KD8CEC
**************************************************************************/
#define UBITX_DISPLAY_LCD2004_BASE
#define En B00000100 // Enable bit
#define Rw B00000010 // Read/Write bit
#define Rs B00000001 // Register select bit
#define LCD_Command(x) (LCD_Send(x, 0))
#define LCD_Write(x) (LCD_Send(x, Rs))
uint8_t _Addr;
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _numlines;
uint8_t _cols;
uint8_t _rows;
uint8_t _backlightval;
#define printIIC(args) Wire.write(args)
void expanderWrite(uint8_t _data)
{
Wire.beginTransmission(_Addr);
printIIC((int)(_data) | _backlightval);
Wire.endTransmission();
}
void pulseEnable(uint8_t _data){
expanderWrite(_data | En); // En high
delayMicroseconds(1); // enable pulse must be >450ns
expanderWrite(_data & ~En); // En low
delayMicroseconds(50); // commands need > 37us to settle
}
void write4bits(uint8_t value)
{
expanderWrite(value);
pulseEnable(value);
}
void LCD_Send(uint8_t value, uint8_t mode)
{
uint8_t highnib=value&0xf0;
uint8_t lownib=(value<<4)&0xf0;
write4bits((highnib)|mode);
write4bits((lownib)|mode);
}
// Turn the (optional) backlight off/on
void noBacklight(void) {
_backlightval=LCD_NOBACKLIGHT;
expanderWrite(0);
}
void backlight(void) {
_backlightval=LCD_BACKLIGHT;
expanderWrite(0);
}
void LCD2004_Init()
{
//I2C Init
_Addr = I2C_LCD_MASTER_ADDRESS;
_cols = 20;
_rows = 4;
_backlightval = LCD_NOBACKLIGHT;
Wire.begin();
delay(50);
// Now we pull both RS and R/W low to begin commands
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
delay(1000);
//put the LCD into 4 bit mode
// this is according to the hitachi HD44780 datasheet
// figure 24, pg 46
// we start in 8bit mode, try to set 4 bit mode
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// second try
write4bits(0x03 << 4);
delayMicroseconds(4500); // wait min 4.1ms
// third go!
write4bits(0x03 << 4);
delayMicroseconds(150);
// finally, set to 4-bit interface
write4bits(0x02 << 4);
// finally, set # lines, font size, etc.
LCD_Command(LCD_FUNCTIONSET | LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS | LCD_2LINE);
// turn the display on with no cursor or blinking default
LCD_Command(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF);
// clear it off
LCD_Command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
//delayMicroseconds(2000); // this command takes a long time!
delayMicroseconds(1000); // this command takes a long time!
LCD_Command(LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT);
backlight();
}
#endif
//========================================================================
//End of I2CTinyLCD Library by KD8CEC
//========================================================================
//========================================================================
// 20 X 04 LCD Routines
//Begin of Display Base Routines (Init, printLine..)
//========================================================================
#ifdef UBITX_DISPLAY_LCD2004_BASE
void LCD_Print(const char *c)
{
for (uint8_t i = 0; i < strlen(c); i++)
{
if (*(c + i) == 0x00) return;
LCD_Write(*(c + i));
}
}
const int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
void LCD_SetCursor(uint8_t col, uint8_t row)
{
LCD_Command(LCD_SETDDRAMADDR | (col + row_offsets[row])); //0 : 0x00, 1 : 0x40, only for 20 x 4 lcd
}
void LCD_CreateChar(uint8_t location, uint8_t charmap[])
{
location &= 0x7; // we only have 8 locations 0-7
LCD_Command(LCD_SETCGRAMADDR | (location << 3));
for (int i=0; i<8; i++)
LCD_Write(charmap[i]);
}
//SWR GRAPH, DrawMeter and drawingMeter Logic function by VK2ETA
//#define OPTION_SKINNYBARS
char c[30], b[30];
char printBuff[4][21]; //mirrors what is showing on the two lines of the display
void LCD_Init(void)
{
LCD2004_Init();
initMeter(); //for Meter Display
}
// The generic routine to display one line on the LCD
void printLine(unsigned char linenmbr, const char *c) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
if (strcmp(c, printBuff[linenmbr])) { // only refresh the display when there was a change
LCD_SetCursor(0, linenmbr); // place the cursor at the beginning of the selected line
LCD_Print(c);
strcpy(printBuff[linenmbr], c);
for (byte i = strlen(c); i < 20; i++) { // add white spaces until the end of the 20 characters line is reached
LCD_Write(' ');
}
}
}
void printLineF(char linenmbr, const __FlashStringHelper *c)
{
int i;
char tmpBuff[21];
PGM_P p = reinterpret_cast<PGM_P>(c);
for (i = 0; i < 21; i++){
unsigned char fChar = pgm_read_byte(p++);
tmpBuff[i] = fChar;
if (fChar == 0)
break;
}
printLine(linenmbr, tmpBuff);
}
#define LCD_MAX_COLUMN 20
void printLineFromEEPRom(char linenmbr, char lcdColumn, byte eepromStartIndex, byte eepromEndIndex, char offsetTtype) {
if ((displayOption1 & 0x01) == 0x01)
linenmbr = (linenmbr == 0 ? 1 : 0); //Line Toggle
LCD_SetCursor(lcdColumn, linenmbr);
for (byte i = eepromStartIndex; i <= eepromEndIndex; i++)
{
if (++lcdColumn <= LCD_MAX_COLUMN)
LCD_Write(EEPROM.read((offsetTtype == 0 ? USER_CALLSIGN_DAT : WSPR_MESSAGE1) + i));
else
break;
}
for (byte i = lcdColumn; i < 20; i++) //Right Padding by Space
LCD_Write(' ');
}
// short cut to print to the first line
void printLine1(const char *c)
{
printLine(1,c);
}
// short cut to print to the first line
void printLine2(const char *c)
{
printLine(0,c);
}
void clearLine2()
{
printLine2("");
line2DisplayStatus = 0;
}
// short cut to print to the first line
void printLine1Clear(){
printLine(1,"");
}
// short cut to print to the first line
void printLine2Clear(){
printLine(0, "");
}
void printLine2ClearAndUpdate(){
printLine(0, "");
line2DisplayStatus = 0;
updateDisplay();
}
//==================================================================================
//End of Display Base Routines
//==================================================================================
//==================================================================================
//Begin of User Interface Routines
//==================================================================================
//Main Display
// this builds up the top line of the display with frequency and mode
void updateDisplay() {
// tks Jack Purdum W8TEE
// replaced fsprint commmands by str commands for code size reduction
// replace code for Frequency numbering error (alignment, point...) by KD8CEC
// i also Very TNX Purdum for good source code
int i;
unsigned long tmpFreq = frequency; //
memset(c, 0, sizeof(c));
if (inTx){
if (isCWAutoMode == 2) {
for (i = 0; i < 4; i++)
c[3-i] = (i < autoCWSendReservCount ? byteToChar(autoCWSendReserv[i]) : ' ');
//display Sending Index
c[4] = byteToChar(sendingCWTextIndex);
c[5] = '=';
}
else {
if (cwTimeout > 0)
strcpy(c, " CW:");
else
strcpy(c, " TX:");
}
}
else {
if (ritOn)
strcpy(c, "RIT ");
else {
if (cwMode == 0)
{
if (isUSB)
strcpy(c, "USB ");
else
strcpy(c, "LSB ");
}
else if (cwMode == 1)
{
strcpy(c, "CWL ");
}
else
{
strcpy(c, "CWU ");
}
}
if (vfoActive == VFO_A) // VFO A is active
strcat(c, "A:");
else
strcat(c, "B:");
}
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
//display frequency
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) c[i] = '.';
else {
c[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
c[i] = ' ';
}
if (sdrModeOn)
strcat(c, " SDR");
else
strcat(c, " SPK");
//remarked by KD8CEC
//already RX/TX status display, and over index (20 x 4 LCD)
//if (inTx)
// strcat(c, " TX");
printLine(1, c);
byte diplayVFOLine = 1;
if ((displayOption1 & 0x01) == 0x01)
diplayVFOLine = 0;
if ((vfoActive == VFO_A && ((isDialLock & 0x01) == 0x01)) ||
(vfoActive == VFO_B && ((isDialLock & 0x02) == 0x02))) {
LCD_SetCursor(5,diplayVFOLine);
LCD_Write((uint8_t)0);
}
else if (isCWAutoMode == 2){
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(0x7E);
}
else
{
LCD_SetCursor(5,diplayVFOLine);
LCD_Write(':');
}
}
char line2Buffer[20];
//KD8CEC 200Hz ST
//L14.150 200Hz ST
//U14.150 +150khz
int freqScrollPosition = 0;
//Example Line2 Optinal Display
//immediate execution, not call by scheulder
//warning : unused parameter 'displayType' <-- ignore, this is reserve
void updateLine2Buffer(char displayType)
{
unsigned long tmpFreq = 0;
if (ritOn)
{
strcpy(line2Buffer, "RitTX:");
//display frequency
tmpFreq = ritTxFrequency;
//Fixed by Mitani Massaru (JE4SMQ)
if (isShiftDisplayCWFreq == 1)
{
if (cwMode == 1) //CWL
tmpFreq = tmpFreq - sideTone + shiftDisplayAdjustVal;
else if (cwMode == 2) //CWU
tmpFreq = tmpFreq + sideTone + shiftDisplayAdjustVal;
}
for (int i = 15; i >= 6; i--) {
if (tmpFreq > 0) {
if (i == 12 || i == 8) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
return;
} //end of ritOn display
//other VFO display
if (vfoActive == VFO_B)
{
tmpFreq = vfoA;
}
else
{
tmpFreq = vfoB;
}
// EXAMPLE 1 & 2
//U14.150.100
//display frequency
for (int i = 9; i >= 0; i--) {
if (tmpFreq > 0) {
if (i == 2 || i == 6) line2Buffer[i] = '.';
else {
line2Buffer[i] = tmpFreq % 10 + 0x30;
tmpFreq /= 10;
}
}
else
line2Buffer[i] = ' ';
}
memset(&line2Buffer[10], ' ', 10);
if (isIFShift)
{
line2Buffer[6] = 'M';
line2Buffer[7] = ' ';
//IFShift Offset Value
line2Buffer[8] = 'I';
line2Buffer[9] = 'F';
line2Buffer[10] = ifShiftValue >= 0 ? '+' : 0;
line2Buffer[11] = 0;
line2Buffer[12] = ' ';
//11, 12, 13, 14, 15
memset(b, 0, sizeof(b));
ltoa(ifShiftValue, b, DEC);
strncat(line2Buffer, b, 5);
for (int i = 12; i < 17; i++)
{
if (line2Buffer[i] == 0)
line2Buffer[i] = ' ';
}
} // end of display IF
else // step & Key Type display
{
//Step
long tmpStep = arTuneStep[tuneStepIndex -1];
byte isStepKhz = 0;
if (tmpStep >= 1000)
{
isStepKhz = 2;
}
for (int i = 14; i >= 12 - isStepKhz; i--) {
if (tmpStep > 0) {
line2Buffer[i + isStepKhz] = tmpStep % 10 + 0x30;
tmpStep /= 10;
}
else
line2Buffer[i +isStepKhz] = ' ';
}
if (isStepKhz == 0)
{
line2Buffer[15] = 'H';
line2Buffer[16] = 'z';
}
}
line2Buffer[17] = ' ';
//Check CW Key cwKeyType = 0; //0: straight, 1 : iambica, 2: iambicb
if (cwKeyType == 0)
{
line2Buffer[18] = 'S';
line2Buffer[19] = 'T';
}
else if (cwKeyType == 1)
{
line2Buffer[18] = 'I';
line2Buffer[19] = 'A';
}
else
{
line2Buffer[18] = 'I';
line2Buffer[19] = 'B';
}
}
//meterType : 0 = S.Meter, 1 : P.Meter
void DisplayMeter(byte meterType, byte meterValue, char drawPosition)
{
if (meterType == 0 || meterType == 1 || meterType == 2)
{
drawMeter(meterValue);
LCD_SetCursor(drawPosition, 2);
LCD_Write('S');
LCD_Write(':');
for (int i = 0; i < 7; i++) //meter 5 + +db 1 = 6
LCD_Write(lcdMeter[i]);
}
}
char checkCount = 0;
char checkCountSMeter = 0;
//execute interval : 0.25sec
void idle_process()
{
//space for user graphic display
if (menuOn == 0)
{
if ((displayOption1 & 0x10) == 0x10) //always empty topline
return;
//if line2DisplayStatus == 0 <-- this condition is clear Line, you can display any message
if (line2DisplayStatus == 0 || (((displayOption1 & 0x04) == 0x04) && line2DisplayStatus == 2)) {
if (checkCount++ > 1)
{
updateLine2Buffer(0); //call by scheduler
printLine2(line2Buffer);
line2DisplayStatus = 2;
checkCount = 0;
}
}
//EX for Meters
/*
DisplayMeter(0, testValue++, 0);
if (testValue > 30)
testValue = 0;
*/
//Sample
//DisplayMeter(0, analogRead(ANALOG_SMETER) / 30, 0);
//DisplayMeter(0, analogRead(ANALOG_SMETER) / 10, 0);
//delay_background(10, 0);
//DisplayMeter(0, analogRead(ANALOG_SMETER), 0);
//if (testValue > 30)
// testValue = 0;
//S-Meter Display
if (((displayOption1 & 0x08) == 0x08 && (sdrModeOn == 0)) && (++checkCountSMeter > SMeterLatency))
{
int newSMeter;
#ifdef USE_I2CSMETER
scaledSMeter = GetI2CSmeterValue(I2CMETER_CALCS);
#else
//VK2ETA S-Meter from MAX9814 TC pin
newSMeter = analogRead(ANALOG_SMETER) / 4;
//Faster attack, Slower release
//currentSMeter = (newSMeter > currentSMeter ? ((currentSMeter * 3 + newSMeter * 7) + 5) / 10 : ((currentSMeter * 7 + newSMeter * 3) + 5) / 10);
//currentSMeter = ((currentSMeter * 7 + newSMeter * 3) + 5) / 10;
currentSMeter = newSMeter;
scaledSMeter = 0;
for (byte s = 8; s >= 1; s--) {
if (currentSMeter > sMeterLevels[s]) {
scaledSMeter = s;
break;
}
}
#endif
DisplayMeter(0, scaledSMeter, 0);
checkCountSMeter = 0; //Reset Latency time
} //end of S-Meter
}
}
//AutoKey LCD Display Routine
void Display_AutoKeyTextIndex(byte textIndex)
{
byte diplayAutoCWLine = 0;
if ((displayOption1 & 0x01) == 0x01)
diplayAutoCWLine = 1;
LCD_SetCursor(0, diplayAutoCWLine);
LCD_Write(byteToChar(textIndex));
LCD_Write(':');
}
void DisplayCallsign(byte callSignLength)
{
printLineFromEEPRom(3, 20 - userCallsignLength, 0, userCallsignLength -1, 0); //eeprom to lcd use offset (USER_CALLSIGN_DAT)
}
void DisplayVersionInfo(const __FlashStringHelper * fwVersionInfo)
{
printLineF(3, fwVersionInfo);
}
#endif

View File

@@ -535,7 +535,7 @@ void sendUIData(int sendType)
if (L_inTx != inTx) if (L_inTx != inTx)
{ {
L_inTx = inTx; L_inTx = inTx;
SendCommand1Num(CMD_IS_TX, L_inTx ? 1 : 0); SendCommand1Num(CMD_IS_TX, L_inTx);
} }
//#define CMD_IS_DIALLOCK 'l' //cl //#define CMD_IS_DIALLOCK 'l' //cl

View File

@@ -8,6 +8,10 @@ Ian KD8CEC
#include "ubitx.h" #include "ubitx.h"
#include "ubitx_eemap.h" #include "ubitx_eemap.h"
extern void cwKeydown();
extern void cwKeyUp();
extern volatile bool keyDown;
//Current Frequency and mode to active VFO by KD8CEC //Current Frequency and mode to active VFO by KD8CEC
void FrequencyToVFO(byte isSaveFreq) void FrequencyToVFO(byte isSaveFreq)
{ {
@@ -1528,7 +1532,7 @@ void factoryCalibration(int btn){
{ {
if (digitalRead(PTT) == LOW && !keyDown) if (digitalRead(PTT) == LOW && !keyDown)
cwKeyDown(); cwKeydown();
if (digitalRead(PTT) == HIGH && keyDown) if (digitalRead(PTT) == HIGH && keyDown)
cwKeyUp(); cwKeyUp();
@@ -1550,7 +1554,7 @@ void factoryCalibration(int btn){
} }
cwTimeout = 0; cwTimeout = 0;
keyDown = false; keyDown = 0;
stopTx(); stopTx();
printLineF2(F("Calibration set!")); printLineF2(F("Calibration set!"));

View File

@@ -145,9 +145,9 @@ void si5351_set_calibration(int32_t cal){
void SetCarrierFreq() void SetCarrierFreq()
{ {
unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && !inTx ? ifShiftValue : 0)); unsigned long appliedCarrier = ((cwMode == 0 ? usbCarrier : cwmCarrier) + (isIFShift && (!inTx) ? ifShiftValue : 0));
//si5351bx_setfreq(0, (sdrModeOn ? 0 : appliedCarrier)); //si5351bx_setfreq(0, (sdrModeOn ? 0 : appliedCarrier));
si5351bx_setfreq(0, ((sdrModeOn && !inTx) ? 0 : appliedCarrier)); //found bug by KG4GEK si5351bx_setfreq(0, ((sdrModeOn && (!inTx)) ? 0 : appliedCarrier)); //found bug by KG4GEK
/* /*