# psk31 / psk.c

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106``` ```/** \file * Implement a PSK31 encoder. * * 8-bit output of */ #include "WProgram.h" #include "sin-table.h" #include "varicode.h" static char msg[] = "ny3u KD4ISF QSO cq 0123456789\n"; static uint8_t phase; static void output_bit( const uint8_t bit ) { for (uint8_t cycle = 0 ; cycle < 16 ; cycle++) { // If we are outputting a zero, swap the phase if (cycle == 8 && bit == 0) phase += 64; for (uint8_t i = 0 ; i < 128 ; i++) { int16_t s = sin_table[(i + phase) & 127]; uint16_t u; // if we are outputting a zero, // multiple the scale of this cycle // by the cosine of the cycle. if (bit == 0) { int16_t c = cycle < 8 ? sin_table[32 + cycle * 4 + i / 32] : sin_table[96 - cycle * 4 - i / 32]; // Multiply by the cosine and add a DC offset // to get an unsigned value u = (s * c) + 128 * 128; } else { // Just output it straight u = (s + 128) * 128; } // Convert to an unsigned 5 bit value with dc offset PORTB = u >> 11; // Output this for 500 Hz / 128 clock ticks OCR1A += 250; // 16 MHz / 128 / 250 == 500 Hz TIFR1 |= 1 << OCF1A; // clear the OCF1A timer while ((TIFR1 & (1 << OCF1A)) == 0) ; } } } static void output_word(uint16_t word) { while (word) { uint8_t bit = (word & 0x8000) ? 1 : 0; word <<= 1; output_bit(bit); //output_bit(TCNT1 & 1); } // Mark the end ofthe word with two zeros output_bit(0); output_bit(0); } static void psk_main(void) { // Port B has 6 bits of output on pins 8-13 DDRB = 0x3F; // Timer1 at clk/1 TCCR1B = 1; // Clock is 16 MHz // 512 Hz sine wave is 32768 instructions per cycle // 6 bits of output == 64 steps from 0 to 1 // 128 steps in the sin table above // 32768 / 128 == 256 instructions per step uint8_t i = 0; while (1) { unsigned char c = msg[i++]; if (c == '\0') { i = 0; continue; } uint16_t word = varicode[c]; output_word(word); } } ```