-
-
Save xand79/2765c7f69804ad036e7260f7819c57d3 to your computer and use it in GitHub Desktop.
Generate PSK31 with an Si5351A
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Эта версия передатчика читает символы из последовательного порта и передаёт построчно. | |
* BPSK31/63 выбирается в переменной. | |
* Частота формируется биениями между выходами 0 и 1, в схеме нужен смеситель для сложения: | |
* выходы соединяются резистором 100 Ом, за ним трансформатор на ферритовом кольце. | |
*/ | |
#include "si5351.h" | |
#include "Wire.h" | |
#include "varicode.h" | |
Si5351 si5351; | |
volatile int index = 0; | |
volatile uint16_t symbol; | |
volatile int psk_bit = 0; | |
volatile int zero_count = 0; | |
volatile int set_vfo = 0; | |
#define BPSK31_baud 3125; | |
#define BPSK63_baud 6250; | |
unsigned int baud_rate = BPSK31_baud //выбор режима модуляции | |
uint64_t freq = 1014400000ULL; //частота передачи | |
String mystring = ""; //передаваемая строка | |
int psk_bit_prev = 0; //предыдущий переданный бит | |
unsigned int Nch = 0; //номер передаваемого символа строки | |
unsigned long period = 0; //время между передачами битов | |
boolean TXed = 0; //признак конца передачи | |
unsigned int led = 13; //индикатор модуляции | |
unsigned int prm = 7; //переключатель антенна-приёмник | |
unsigned int prd = 8; //переключатель антенна-передатчик | |
int32_t cal_factor = 10; //90680 готовый китайский модуль из моего анализатора; | |
void setup() { | |
Serial.begin(115200); | |
//инициализация синтезатора | |
si5351.init(SI5351_CRYSTAL_LOAD_8PF, 0, 0); //8 пикофарад нагрузки на кварц | |
delay(10); | |
//зададим нагрузку поменьше из 2/4/6/8 мА, чтобы увеличить время нарастания-спада (8 мА = 1 нс) | |
//и уменьшить дрожание, то есть jitter; но не сильно мало, чтобы хорошо работал смеситель | |
si5351.drive_strength(SI5351_CLK0, SI5351_DRIVE_4MA); | |
si5351.drive_strength(SI5351_CLK1, SI5351_DRIVE_4MA); | |
//коррекция в зависимости от фактически установленного кварца | |
si5351.set_correction(cal_factor, SI5351_PLL_INPUT_XO); | |
//разрешаем дробные делители | |
si5351.set_clock_fanout(SI5351_FANOUT_XO, 1); | |
//включаем ФАПЧ А на частоте 870 000 000 | |
si5351.set_pll(87000000000ULL, SI5351_PLLA); | |
//задействуем ФАПЧ А на выходах 0 и 1 | |
si5351.set_ms_source(SI5351_CLK0, SI5351_PLLA); | |
si5351.set_ms_source(SI5351_CLK1, SI5351_PLLA); | |
//изначально ставим передачу в нули, чтобы приёмник лучше синхронизировался в начале передачи | |
si5351.set_freq(freq + (baud_rate / 2), SI5351_CLK0); | |
si5351.set_freq(freq - (baud_rate / 2), SI5351_CLK1); | |
//устанавливаем фазу в 0 | |
si5351.set_phase(SI5351_CLK0, 0); | |
si5351.set_phase(SI5351_CLK1, 0); | |
//сброс ФАПЧ | |
si5351.si5351_write(SI5351_PLL_RESET, 0xAC); | |
//загружаем первый символ согласно варикоду | |
symbol = varicode[0]; //mystring.charAt(index)]; | |
//выключаем все выходы | |
si5351.output_enable(SI5351_CLK0, 0); | |
si5351.output_enable(SI5351_CLK1, 0); | |
si5351.output_enable(SI5351_CLK2, 0); | |
//будем мигать светодиодом синхронно с модуляцией | |
pinMode(led, OUTPUT); | |
pinMode(prm, OUTPUT); | |
pinMode(prd, OUTPUT); | |
digitalWrite(led, 0); | |
digitalWrite(prm, 1); | |
digitalWrite(prd, 0); | |
Serial.println("Setup OK"); | |
delay(3000); | |
} | |
//читаем строку из последовательного порта | |
void serialEvent() { | |
while(Serial.available()) { | |
char ch = Serial.read(); | |
if (ch == 10) { | |
if ((mystring.substring(0,1)=="*")) { | |
Serial.print("Freq. set to "); | |
mystring = mystring.substring(1,10); | |
Serial.println(mystring); | |
freq = mystring.toInt() * 100; | |
} else { | |
mystring = mystring + "\n"; | |
Serial.println(mystring); | |
Serial.println(mystring.length()); | |
Transmit(); | |
} | |
Nch = 0; | |
mystring = ""; | |
} else { | |
mystring = mystring + ch; | |
Nch++; | |
} | |
} | |
} | |
//выборка символа | |
void selChar() { | |
if (symbol == 0) { | |
if(zero_count) { | |
psk_bit = 0; | |
zero_count--; | |
} else { | |
index++; | |
// сбросим указатель символа в сообщении на начальный, если строка подошла к концу | |
if(index >= mystring.length()) { | |
index = 0; | |
TXed = 1; //сигнализируем, что передача всё | |
} | |
symbol = varicode[mystring.charAt(index)]; | |
} | |
} else { | |
if(symbol & 0x8000) {// 1 in the MSB position | |
psk_bit = 1; | |
} else { // 0 in the MSB position | |
psk_bit = 0; | |
} | |
symbol <<= 1; | |
if(symbol == 0) { | |
zero_count = 2; | |
} else { | |
zero_count = 0; | |
} | |
} | |
set_vfo = 1; | |
} | |
//переключение состояний | |
void tx() { | |
if(set_vfo) { | |
set_vfo = 0; | |
if(psk_bit) { | |
if(psk_bit_prev == 0) { | |
psk_one(); | |
digitalWrite(led, HIGH); | |
} | |
psk_bit_prev = 1; | |
} else { | |
if(psk_bit_prev == 1) { | |
psk_zero(); | |
digitalWrite(led, LOW); | |
} | |
psk_bit_prev = 0; | |
} | |
} | |
} | |
//непосредственно передача строки | |
void Transmit() { | |
unsigned int baud_period = 100000/baud_rate*1000; //период следования бит | |
psk_zero(); //по нулям лучше синхронизируется в начале передачи | |
digitalWrite(prm, 0); //переключаем антенну | |
digitalWrite(prd, 1); | |
delay(20); //переходные процессы | |
si5351.output_enable(SI5351_CLK0, 1); | |
si5351.output_enable(SI5351_CLK1, 1); | |
delay(2000); //дождаться, пока приёмник подхватит | |
while (!TXed) { | |
//каждые 32 мс => 31.25 Гц или 16 мс => 62.5 Гц в зависимости от скорости | |
if ((micros()-period) > baud_period) { | |
period = micros(); | |
selChar(); | |
tx(); | |
} | |
} | |
psk_one(); //в конце единицы | |
delay(1000); //в виде паузы после передачи | |
si5351.output_enable(SI5351_CLK0, 0); | |
si5351.output_enable(SI5351_CLK1, 0); | |
delay(20); //переходные процессы | |
digitalWrite(prm, 0); //переключаем антенну | |
digitalWrite(prd, 1); | |
TXed = 0; | |
} | |
void loop() { | |
} | |
void psk_zero() { | |
si5351.set_freq(freq + (baud_rate / 2), SI5351_CLK0); | |
si5351.set_freq(freq - (baud_rate / 2), SI5351_CLK1); | |
} | |
void psk_one() { | |
si5351.set_freq(freq, SI5351_CLK0); | |
si5351.set_freq(freq, SI5351_CLK1); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
uint16_t varicode[] = | |
{ | |
0b1010101011000000, // 0 NUL | |
0b1011011011000000, // 1 SOH | |
0b1011101101000000, // 2 STX | |
0b1101110111000000, // 3 ETX | |
0b1011101011000000, // 4 EOT | |
0b1101011111000000, // 5 ENQ | |
0b1011101111000000, // 6 ACK | |
0b1011111101000000, // 7 BEL | |
0b1011111111000000, // 8 BS | |
0b1110111100000000, // 9 HT | |
0b1110100000000000, // 10 LF | |
0b1101101111000000, // 11 VT | |
0b1011011101000000, // 12 FF | |
0b1111100000000000, // 13 CR | |
0b1101110101000000, // 14 SO | |
0b1110101011000000, // 15 SI | |
0b1011110111000000, // 16 DLE | |
0b1011110101000000, // 17 DC1 | |
0b1110101101000000, // 18 DC2 | |
0b1110101111000000, // 19 DC3 | |
0b1101011011000000, // 20 DC4 | |
0b1101101011000000, // 21 NAK | |
0b1101101101000000, // 22 SYN | |
0b1101010111000000, // 23 ETB | |
0b1101111011000000, // 24 CAN | |
0b1101111101000000, // 25 EM | |
0b1110110111000000, // 26 SUB | |
0b1101010101000000, // 27 ESC | |
0b1101011101000000, // 28 FS | |
0b1110111011000000, // 29 GS | |
0b1011111011000000, // 30 RS | |
0b1101111111000000, // 31 US | |
0b1000000000000000, // 32 SP | |
0b1111111110000000, // 33 ! | |
0b1010111110000000, // 34 " | |
0b1111101010000000, // 35 # | |
0b1110110110000000, // 36 $ | |
0b1011010101000000, // 37 % | |
0b1010111011000000, // 38 & | |
0b1011111110000000, // 39 ' | |
0b1111101100000000, // 40 ( | |
0b1111011100000000, // 41 ) | |
0b1011011110000000, // 42 * | |
0b1110111110000000, // 43 + | |
0b1110101000000000, // 44 , | |
0b1101010000000000, // 45 - | |
0b1010111000000000, // 46 . | |
0b1101011110000000, // 47 / | |
0b1011011100000000, // 48 0 | |
0b1011110100000000, // 49 1 | |
0b1110110100000000, // 50 2 | |
0b1111111100000000, // 51 3 | |
0b1011101110000000, // 52 4 | |
0b1010110110000000, // 53 5 | |
0b1011010110000000, // 54 6 | |
0b1101011010000000, // 55 7 | |
0b1101010110000000, // 56 8 | |
0b1101101110000000, // 57 9 | |
0b1111010100000000, // 58 : | |
0b1101111010000000, // 59 ; | |
0b1111011010000000, // 60 < | |
0b1010101000000000, // 61 = | |
0b1110101110000000, // 62 > | |
0b1010101111000000, // 63 ? | |
0b1010111101000000, // 64 @ | |
0b1111101000000000, // 65 A | |
0b1110101100000000, // 66 B | |
0b1010110100000000, // 67 C | |
0b1011010100000000, // 68 D | |
0b1110111000000000, // 69 E | |
0b1101101100000000, // 70 F | |
0b1111110100000000, // 71 G | |
0b1010101010000000, // 72 H | |
0b1111111000000000, // 73 I | |
0b1111111010000000, // 74 J | |
0b1011111010000000, // 75 K | |
0b1101011100000000, // 76 L | |
0b1011101100000000, // 77 M | |
0b1101110100000000, // 78 N | |
0b1010101100000000, // 79 O | |
0b1101010100000000, // 80 P | |
0b1110111010000000, // 81 Q | |
0b1010111100000000, // 82 R | |
0b1101111000000000, // 83 S | |
0b1101101000000000, // 84 T | |
0b1010101110000000, // 85 U | |
0b1101101010000000, // 86 V | |
0b1010111010000000, // 87 W | |
0b1011101010000000, // 88 X | |
0b1011110110000000, // 89 Y | |
0b1010101101000000, // 90 Z | |
0b1111101110000000, // 91 [ | |
0b1111011110000000, // 92 backslash | |
0b1111110110000000, // 93 ] | |
0b1010111111000000, // 94 ^ | |
0b1011011010000000, // 95 _ | |
0b1011011111000000, // 96 ` | |
0b1011000000000000, // 97 a | |
0b1011111000000000, // 98 b | |
0b1011110000000000, // 99 c | |
0b1011010000000000, // 100 d | |
0b1100000000000000, // 101 e | |
0b1111010000000000, // 102 f | |
0b1011011000000000, // 103 g | |
0b1010110000000000, // 104 h | |
0b1101000000000000, // 105 i | |
0b1111010110000000, // 106 j | |
0b1011111100000000, // 107 k | |
0b1101100000000000, // 108 l | |
0b1110110000000000, // 109 m | |
0b1111000000000000, // 110 n | |
0b1110000000000000, // 111 o | |
0b1111110000000000, // 112 p | |
0b1101111110000000, // 113 q | |
0b1010100000000000, // 114 r | |
0b1011100000000000, // 115 s | |
0b1010000000000000, // 116 t | |
0b1101110000000000, // 117 u | |
0b1111011000000000, // 118 v | |
0b1101011000000000, // 119 w | |
0b1101111100000000, // 120 x | |
0b1011101000000000, // 121 y | |
0b1110101010000000, // 122 z | |
0b1010110111000000, // 123 { | |
0b1101110110000000, // 124 | | |
0b1010110101000000, // 125 } | |
0b1011010111000000, // 126 ~ | |
0b1110110101000000 // 127 (del) | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment