/**************************************************************************** * keyer.c * (c) 2007 Michael Wichmann * * This code is under the MIT-License * ****************************************************************************/ #include #include #include #include #include // shorthand for a nop operation #define nop() asm volatile("nop" ::) // define our ports and pins we will be using #define PORTINP PORTB #define PININP PINB #define nDOT PORTB0 #define nDASH PORTB1 #define nBUT1 PORTB2 #define nBUT2 PORTB3 #define PORTOUT PORTA #define DDROUT DDRA #define nLED PORTA0 #define nKEY PORTA1 // some shorthands #define ledon() PORTOUT |= _BV(nLED) #define ledoff() PORTOUT &= ~_BV(nLED) //#define keydown() DDROUT |= _BV(nKEY) //#define keyup() DDROUT &= ~_BV(nKEY) #define keydown() PORTOUT |= _BV(nKEY) #define keyup() PORTOUT &= ~_BV(nKEY) #define TMRCLKSRC (_BV(CS12)) #define timeroff() TCCR1B &= ~TMRCLKSRC #define timeron() TCCR1B |= TMRCLKSRC // timing issues #define FOSC 1000000 // counts per msec #define CNTSPERMSEC (FOSC/256)/1000 // forward declarations void calcspeed(); void delay(uint16_t n); #define SEND_DOT 1 #define SEND_DASH 2 #define SEND_PAUSE 3 void send(uint8_t ch); // global variables // uint8_t EEMEM eeSpeed = 20; uint8_t gSpeed; uint16_t gDotLength; uint16_t gDashLength; //uint16_t gIntraSignPauseLength = 234; #define gIntraSignPauseLength gDotLength // blink? uint8_t bBlink = 1; // state variables for dot/dash paddles // declare volatile to be able to change within isr() volatile uint8_t gDot = 0; volatile uint8_t gDash = 0; volatile uint8_t gBut1 = 0; volatile uint8_t gBut2 = 0; #define BUF_EMPTY 0 #define BUF_DOT 1 #define BUF_DASH 2 #define BUFSTAT_IDLE 5 #define BUFSTAT_PLAYING 3 #define BUFSTAT_PAUSE 4 uint8_t buf[2]; uint8_t bufstat; // PCINT interrupt vector ISR(PCINT_vect) { // setup initial state of pininp... dot,dash,buttons are in unpressed status // and are therefore pulled up by internal pullup therefor pinstatus is one static uint8_t oldval = _BV(nBUT1)|_BV(nDOT)|_BV(nDASH); // get current value of ports register uint8_t val = PININP; // button one changed if ((val^oldval)&_BV(nBUT1)) { // button released if (val&_BV(nBUT1)) { gBut1 = 0; } // button depressed else { gBut1 = 1; } } // button two changed if ((val^oldval)&_BV(nBUT2)) { // button released if (val&_BV(nBUT2)) { gBut2 = 0; keyup(); } // button depressed else { gBut2 = 1; } } // dot lever changed if ((val^oldval)&_BV(nDOT)) { // dot lever released if (val&_BV(nDOT)) { gDot = 0; } // dot lever depressed else { gDot = 1; } } // dash lever changed if ((val^oldval)&_BV(nDASH)) { // dash lever released if (val&_BV(nDASH)) { gDash = 0; } // dash lever depressed else { gDash = 1; } } // save the current value so next time we know exactly what pin has changed oldval = val; } ISR(TIMER1_COMPA_vect) { timeroff(); if (bufstat == BUFSTAT_PLAYING) { keyup(); ledoff(); // pause OCR1A = gIntraSignPauseLength; bufstat = BUFSTAT_PAUSE; timeron(); } else if (bufstat == BUFSTAT_PAUSE) { buf[0] = buf[1]; buf[1] = BUF_EMPTY; bufstat = BUFSTAT_IDLE; } } void delay(uint16_t n) { for (uint16_t i=0; ithen hiz, output->gnd //DDROUT &= ~_BV(nKEY); // is used to switch // NOW: // use BC547 or BS170 as switch therefore do the same as with led DDROUT |= _BV(nKEY); // reset led and key PORTOUT &= ~_BV(nLED); PORTOUT &= ~_BV(nKEY); // activate internal pullup PORTINP = _BV(nDOT)|_BV(nDASH)|_BV(nBUT1)|_BV(nBUT2); // pc int enable PCMSK = _BV(nDOT)|_BV(nDASH)|_BV(nBUT1)|_BV(nBUT2); GIMSK |= _BV(PCIE); // setup timer/counter1 // select timer mode TCCR1B = _BV(WGM12); // timer output compare interrupt TIMSK |= _BV(OCIE1A); // init buffer buf[0] = BUF_EMPTY; buf[1] = BUF_EMPTY; bufstat = BUFSTAT_IDLE; // set the sleep mode set_sleep_mode(SLEEP_MODE_IDLE); // calculate speeds gSpeed = eeprom_read_byte(&eeSpeed); if ((gSpeed < 10) || (gSpeed > 30)) gSpeed = 20; calcspeed(); // allow interrupts sei(); // enter the loop while(1) { // go to sleep sleep_mode(); // woke up, so some interrupt must have happened // check paddle and fill buffer if ((gDot || gDash) && (!(gBut1 || gBut2))) { if (buf[0] == BUF_EMPTY) { if (gDot == 1) { buf[0] = BUF_DOT; } else { buf[0] = BUF_DASH; } } else if (buf[1] == BUF_EMPTY) { if ((buf[0] == BUF_DOT) && (gDash == 1)) { buf[1] = BUF_DASH; } else if ((buf[0] == BUF_DASH ) && (gDot == 1)) { buf[1] = BUF_DOT; } } } // button pressed if (gBut1 && (buf[0] == BUF_EMPTY)) { if (gDot) { gSpeed -= 1; calcspeed(); buf[0] = BUF_DOT; buf[1] = BUF_DASH; if (gSpeed==20) buf[1] = BUF_DOT; } else if (gDash) { gSpeed += 1; calcspeed(); buf[0] = BUF_DOT; buf[1] = BUF_DASH; if (gSpeed==20) buf[1] = BUF_DOT; } if (gSpeed < 10) { gSpeed = 10; calcspeed(); } else if (gSpeed > 30) { gSpeed = 30; calcspeed(); } if (eeprom_read_byte(&eeSpeed) != gSpeed) { eeprom_write_byte(&eeSpeed, gSpeed); } } // button2 pressed ... output tune carrier if (gBut2) { keydown(); } // empty the buffer if (bufstat == BUFSTAT_IDLE) { if (buf[0] == BUF_DOT) { bufstat = BUFSTAT_PLAYING; send(SEND_DOT); } else if (buf[0] == BUF_DASH) { bufstat = BUFSTAT_PLAYING; send(SEND_DASH); } } } return 0; }