Showing posts with label ab9lm. Show all posts
Showing posts with label ab9lm. Show all posts

Wednesday, February 3, 2016

Straight Key Keyer

There was talk recently on the QRP-L mailing list about making an automatic keyer that could record and playback a straight key.  Oddly enough, this is something that I've always considered doing. I'm a fan of the Farnsworth CW method, and I typically need a longer space between letters to accurately copy what I'm receiving. One issue I have always had with other keyers is that the time between characters isn't usually adjustable.

The solution seemed like an easy enough job for any PIC with an EEPROM. After a little fiddling I came up with a simple but effective code in MPLAB XC8. My PIC of choice was a 16LF1938. This chip really is overkill for this application, but it at least gives me tons of room to expand to other functions as I decide.

PORTB.3 = output
PORTB.0 = yellow LED recording indicator
PORTB.1 = key
PORTB.2 = record/play/cancel button


This video is a quick demonstration of how it will record anything, including a sloppy fist.

  1. Is key pressed?
    1. Key radio.
  2. Is record button held down for 3 seconds?
    1. Erase eeprom.
    2. Watch for first key press.
      1. Loop until key is released. Checking every 10ms. (This gives a total recordable time of 2.55 seconds per mark or space.)
      2. Record the duration in EEPROM and increment the EEPROM address.
      3. Record duration until key pressed again or until 2.54s reached. Increment EEPROM address.
      4. Continue loop until record button is pressed again.
  3. When record button is clicked briefly, EEPROM is 'played back' in a key down/key up rotating format until an EEPROM value of 255 is read, or EEPROM address of 255 is reached which equates to ~126 marks (more than enough for even the windiest CQ call).
That's all there is to it. I've posted my code below incase anyone is interested. I realize using interrupts would be much more efficient, but this was just a quick hack job to get it working. Also, I'm hardly a programmer, just a tinkerer...


 /*  
  * File:  SKeyer.c  
  * Author: AB9LM  
  *  
  * Created on January 26, 2016, 6:06 PM  
  */  
 #define _XTAL_FREQ 8000000  
 #include <xc.h>  
 // #pragma config statements should precede project file includes.  
 // Use project enums instead of #define for ON and OFF.  
 // CONFIG1  
 #pragma config FOSC = INTOSC  // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)  
 #pragma config WDTE = OFF    // Watchdog Timer Enable (WDT disabled)  
 #pragma config PWRTE = OFF   // Power-up Timer Enable (PWRT disabled)  
 #pragma config MCLRE = OFF   // MCLR Pin Function Select (MCLR/VPP pin function is digital input)  
 #pragma config CP = OFF     // Flash Program Memory Code Protection (Program memory code protection is disabled)  
 #pragma config CPD = OFF    // Data Memory Code Protection (Data memory code protection is disabled)  
 #pragma config BOREN = ON    // Brown-out Reset Enable (Brown-out Reset enabled)  
 #pragma config CLKOUTEN = OFF  // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)  
 #pragma config IESO = ON    // Internal/External Switchover (Internal/External Switchover mode is enabled)  
 #pragma config FCMEN = ON    // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)  
 // CONFIG2  
 #pragma config WRT = OFF    // Flash Memory Self-Write Protection (Write protection off)  
 #pragma config PLLEN = OFF    // PLL Enable (4x PLL enabled)  
 #pragma config STVREN = ON   // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)  
 #pragma config BORV = LO    // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)  
 #pragma config LVP = ON     // Low-Voltage Programming Enable (Low-voltage programming enabled)  
 //End config  
 char address;  
 void blink_yellow(void);  
 void system_setup(){  
  OSCCON = 0b01110000;  
  OPTION_REG = 0b00000000;  
  TRISB = 0b00000110;  
  PORTB = 0b00000000;  
  TRISC = 0b00010000;  
  ANSELB = 0b00000000;  
  WPUB1 = 1;  
  WPUB2 = 1;  
 }  
 void delay_ms(unsigned int milliseconds)  
 {  
   while(milliseconds > 0)  
   {  
    milliseconds--;  
     __delay_us(990);  
   }  
 }  
 void erase_eeprom(){  
   char i = 0;  
   for(i=0; i != 255; i++){  
     eeprom_write(i, 0xff);  
   }  
 }  
 void record_mark(){  
   char count = 0;  
   while(!RB1){  
     LATBbits.LATB3 = 1;  
     count += 1;  
     delay_ms(10);  
   }  
   LATBbits.LATB3 = 0;  
   eeprom_write(address, count);  
 }  
 void record_space(){  
   char count = 0;  
   while(RB1){  
     count += 1;  
     delay_ms(10);  
     if(!RB2 | count == 255){  
       eeprom_write(address, count - 1);  
       break;  
     }  
   }  
   eeprom_write(address, count);  
 }  
 void blink_yellow(void){  
   LATBbits.LATB0 = 0;    
   delay_ms(50);  
   LATBbits.LATB0 = 1;  
   delay_ms(50);  
   LATBbits.LATB0 = 0;  
 }  
 void send_eeprom(){  
   char delay = 0x00;  
   char address = 0x00;  
   while(delay != 0xFF){  
     if(!RB1){  
       LATBbits.LATB3 = 0;  
       blink_yellow();  
       delay_ms(100);  
       while(!RB1){}  
       break;  
     }  
     delay = eeprom_read(address);  
     if(delay == 0xFF){  
       break;  
     }  
     LATBbits.LATB3 = 1;  
     delay_ms(delay * 10);  
     LATBbits.LATB3 = 0;  
     address += 1;  
     delay = eeprom_read(address);  
     delay_ms(delay * 10);  
     address += 1;  
   }  
 }  
 int main(){  
   address = 0x00;  
   int ms_count = 0;  
   system_setup();  
   while(1){  
     if(RB1 == 0){  
       LATBbits.LATB3 = 1;  
     }  
     else{  
       LATBbits.LATB3 = 0;  
     }  
     ms_count = 0;  
     while(!RB2){  
       ms_count += 1;  
       delay_ms(10);  
       if(RB2){  
         delay_ms(100);  
         send_eeprom();  
       }  
       if(ms_count > 200){  
         erase_eeprom();  
         address = 0x00;  
         while(1){  
           LATBbits.LATB0 = 1;  
           while(!RB2){}  
           if(!RB1){  
             record_mark();  
             address += 1;  
             record_space();  
             address += 1;  
             eeprom_write(0xFF,address);  
           }          
           if(!RB2 | address >= 0xF0){  
             while(!RB2){}  
             LATBbits.LATB0 = 0;  
             delay_ms(100);  
             break;  
           }  
         }  
       }  
     }  
   }  
   return 0;  
 }  

Tuesday, September 13, 2011

40m Tiny Tornado w/ PTO

I recently completed building a 40m Tiny Tornado with PTO VFO from scrounged parts.

Tiny Tornado details can be found at:
http://www.indianapolis.net/QRPp-I/KA8MAV_VFO-TT-40.html

I wanted a small cw transceiver that was easy to build, super cheap, and that would fit inside my favorite project enclosure.




Although I wanted to fit the 9v battery inside, I felt that it was a waste of precious altoids real estate.
Instead, I soldered some 9v snaps to a piece of PCB and attached it to the side. Doing this, I'm left w/ some extra room to put a key, or maybe an earbud.





The circuitry turned out a bit messier than I would have liked... I'm certainly no master at Manhattan style building. Not to mention, after soldering the board into the tin, I realized I still needed to drill some holes in the chasis. Booo!

Anyway.. The important part is that it works, and works well as far as I'm concerned. I'm able to tune the entire 40m band... From the CW side, all the way to the end of the phone portion. After a couple minutes of warmup, the VFO is quite stable. With a tuned antenna connected, I'm able to copy even weak signals with little trouble. Although this is a direct conversion receiver, and would need a RIT ordinarily, I think that keying down pulls the VFO just enough to give me the proper amount of shift. .. Which is a good thing, because I dunno how to put a RIT into this PTO VFO.

Into a dummy load, I measured about 300mw on a 9v. I've not had a QSO yet, but very close. I heard a station calling CQ, so I replied... He came back with AB9DM? My attempt to correct him failed as my paddle hose up.

I plan to post a video showing the audio, but as of this writing, I have S9 QRN at my location.
I'll also be putting up a pic of the compact EFHW tuner that I'm working on exclusively for this rig.

73 and good QRPing
Jim - AB9LM