# 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 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152``` ```/** \file * Implement a PSK31 encoder. * * 8-bit output of */ #include "WProgram.h" #include "sin-table.h" #include "varicode.h" static const char msg[] = "ny3u KD4ISF QSO cq 0123456789\n"; static uint8_t phase; static void output_bit( 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]; int16_t c = 128; // if we are outputting a zero, // multiple the scale of this cycle // by the cosine of the cycle. if (bit == 0) c = sin_table[64 + cycle * 4 + i / 16]; // Multiply by the cosine and add a DC offset // to get an unsigned value uint16_t u = (s * c) + 128 * 128; // Convert to an unsigned 5 bit value with dc offset PORTB = u >> 11; OCR1A += 250; // 16 MHz / 128 / 250 == 500 Hz TIFR1 |= 1 << OCF1A; // clear the OCF1A timer while ((TIFR1 & (1 << OCF1A)) == 0) ; } } } #if 0 static void output_bit(unsigned bit) { // 1 bits go out with no change in phase or amplitude if (1 || bit) { output_bit_constant(); return; } // 0 bits ramp down to zero amplitude and then back up for (int16_t i = 0 ; i < 1024 ; i++) { int16_t s = (uint16_t) sin_table[phase++ & 127]; // Shift it to the center of the waveform s -= 16; // scale it linearly s = (s * (1024 - i)) >> 10; // Shift it back to the DC offset s += 16; uint8_t spin = 28; while(spin--) PORTB = s; } // Shift the phase phase = (phase + 64) & 127; // And ramp up down to zero amplitude and then back up for (int16_t i = 0 ; i < 1024 ; i++) { int16_t s = (uint16_t) sin_table[phase++ & 127]; // Shift it to the center of the waveform s -= 16; // scale it linearly s = (s * i) >> 10; // Shift it back to the DC offset s += 16; uint8_t spin = 28; while(spin--) PORTB = s; } // And now constant amplitude to round it out for (int16_t i = 0 ; i < bit_width - 1024 * 2 ; i++) { uint8_t s = sin_table[phase++ & 127]; uint8_t spin = 32; while(spin--) PORTB = s; } } #endif static void output_word(uint16_t word) { while (word) { unsigned bit = word & 0x8000; word <<= 1; output_bit(bit); } // 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); } } ```