Лаб.работа №5
Дописываем кодировочные таблицы
МТК-2 для латинский и русской раскладки.
Прописные и строчные буквы проще сразу прописать в таблицах.
Код:
#include "hardware/pio.h"
#include "hardware/clocks.h"
const float RTTY_BAUD = 45.45f;
const float PIO_FREQ = RTTY_BAUD * 2071.0f;
const float PIO_FREQ_FSK = 117000.0f;
const uint pin_rtty_out = 13;
const uint pin_fsk_in = 14;
const uint pin_fsk_out = 15;
PIO pio = pio0;
uint sm_fsk;
uint sm_id;
// Коды управления регистрами
#define MTK2_LAT 0x1F // 000 11111
#define MTK2_FIG 0x1B // 000 11011
#define MTK2_RUS 0x00 // 000 00000
// Структура для поиска символа
typedef struct {
const char* s; // Строка вместо одного символа
uint8_t code;
} mtk2_map_t;
// Латинский регистр
const mtk2_map_t table_lat[] = {
{"A", 0x03}, {"B", 0x19}, {"C", 0x0E}, {"D", 0x09}, {"E", 0x01},
{"F", 0x0D}, {"G", 0x1A}, {"H", 0x14}, {"I", 0x06}, {"J", 0x0B},
{"K", 0x0F}, {"L", 0x12}, {"M", 0x1C}, {"N", 0x0C}, {"O", 0x18},
{"P", 0x16}, {"Q", 0x17}, {"R", 0x0A}, {"S", 0x05}, {"T", 0x10},
{"U", 0x07}, {"V", 0x1E}, {"W", 0x13}, {"X", 0x1D}, {"Y", 0x15},
{"Z", 0x11},
{"a", 0x03}, {"b", 0x19}, {"c", 0x0E}, {"d", 0x09}, {"e", 0x01},
{"f", 0x0D}, {"g", 0x1A}, {"h", 0x14}, {"i", 0x06}, {"j", 0x0B},
{"k", 0x0F}, {"l", 0x12}, {"m", 0x1C}, {"n", 0x0C}, {"o", 0x18},
{"p", 0x16}, {"q", 0x17}, {"r", 0x0A}, {"s", 0x05}, {"t", 0x10},
{"u", 0x07}, {"v", 0x1E}, {"w", 0x13}, {"x", 0x1D}, {"y", 0x15},
{"z", 0x11},
{" ", 0x04}, {"\n", 0x08}, {"\r", 0x02}, {NULL, 0}
};
// Цифровой регистр (ФИГ)
const mtk2_map_t table_fig[] = {
{"-", 0x03}, {"?", 0x19}, {":", 0x0E}, {"3", 0x01}, {"Э", 0x0D},
{"Ш", 0x1A}, {"Щ", 0x14}, {"8", 0x06}, {"Ю", 0x0B}, {"(", 0x0F},
{")", 0x12}, {".", 0x1C}, {",", 0x0C}, {"9", 0x18}, {"0", 0x16},
{"1", 0x17}, {"4", 0x0A}, {"'", 0x05}, {"5", 0x10}, {"7", 0x07},
{"=", 0x1E}, {"2", 0x13}, {"/", 0x1D}, {"6", 0x15}, {"+", 0x11},
{"э", 0x0D}, {"ш", 0x1A}, {"щ", 0x14}, {"ю", 0x0B}, {"Ч", 0x0A},
{"ч", 0x0A},
{NULL, 0}
};
// Русский регистр (РУС)
const mtk2_map_t table_rus[] = {
{"А", 0x03}, {"Б", 0x19}, {"Ц", 0x0E}, {"Д", 0x09}, {"Е", 0x01},
{"Ф", 0x0D}, {"Г", 0x1A}, {"Х", 0x14}, {"И", 0x06}, {"Й", 0x0B},
{"К", 0x0F}, {"Л", 0x12}, {"М", 0x1C}, {"Н", 0x0C}, {"О", 0x18},
{"П", 0x16}, {"Я", 0x17}, {"Р", 0x0A}, {"С", 0x05}, {"Т", 0x10},
{"У", 0x07}, {"Ж", 0x1E}, {"В", 0x13}, {"Ь", 0x1D}, {"Ы", 0x15},
{"З", 0x11}, {"Ъ", 0x1D}, {"Ё", 0x01},
{"а", 0x03}, {"б", 0x19}, {"ц", 0x0E}, {"д", 0x09}, {"е", 0x01},
{"ф", 0x0D}, {"г", 0x1A}, {"х", 0x14}, {"и", 0x06}, {"й", 0x0B},
{"к", 0x0F}, {"л", 0x12}, {"м", 0x1C}, {"н", 0x0C}, {"о", 0x18},
{"п", 0x16}, {"я", 0x17}, {"р", 0x0A}, {"с", 0x05}, {"т", 0x10},
{"у", 0x07}, {"ж", 0x1E}, {"в", 0x13}, {"ь", 0x1D}, {"ы", 0x15},
{"з", 0x11}, {"ъ", 0x1D}, {"ё", 0x01},
{NULL, 0}
};
enum MTK2_STATE { LAT, FIG, RUS };
MTK2_STATE current_reg = LAT;
// Функция поиска последовательности байт в таблице
bool find_in_table(const mtk2_map_t* table, const char* s, uint8_t &code, int &len) {
for (int i = 0; table[i].s != NULL; i++) {
int l = strlen(table[i].s);
if (strncmp(table[i].s, s, l) == 0) {
code = table[i].code;
len = l;
return true;
}
}
return false;
}
// Вспомогательная функция для упаковки 5-битного кода в 8-битный кадр
uint8_t pack_frame(uint8_t code) {
// 1. Разворачиваем биты (Bit Reversal)
uint8_t code_rev = 0;
if (code & 0x01) code_rev |= 0x10;
if (code & 0x02) code_rev |= 0x08;
if (code & 0x04) code_rev |= 0x04;
if (code & 0x08) code_rev |= 0x02;
if (code & 0x10) code_rev |= 0x01;
// 2. Упаковываем: Старт в 7-й бит (0), Данные в 6-2, Стопы в 1-0 (1)
uint8_t frame = 0;
frame |= (1 << 0); // Стоп 1
frame |= (1 << 1); // Стоп 2
frame |= (code_rev << 2); // Данные
frame |= (0 << 7); // Старт
return frame;
}
// Новая основная функция отправки строки
void send_rtty_string(const char* s) {
if (!Serial) Serial.begin(115200);
while (*s) {
uint8_t code = 0;
int char_len = 1;
MTK2_STATE target_reg = current_reg;
bool found = false;
if (find_in_table(table_lat, s, code, char_len)) { target_reg = LAT; found = true; }
else if (find_in_table(table_fig, s, code, char_len)) { target_reg = FIG; found = true; }
else if (find_in_table(table_rus, s, code, char_len)) { target_reg = RUS; found = true; }
if (found) {
// Смена регистра
if (target_reg != current_reg) {
uint8_t reg_code = (target_reg == LAT) ? MTK2_LAT : (target_reg == FIG ? MTK2_FIG : MTK2_RUS);
uint8_t reg_frame = pack_frame(reg_code);
if (target_reg==LAT) Serial.print("[LAT]");
if (target_reg==FIG) Serial.print("[FIG]");
if (target_reg==RUS) Serial.print("[RUS]");
Serial.print(" BIN: ");
for (int i = 7; i >= 0; i--) Serial.print(bitRead(reg_frame, i));
Serial.println();
pio_sm_put_blocking(pio0, sm_id, (uint32_t)reg_frame << 24);
current_reg = target_reg;
delay(45);
}
// Отправка символа
uint8_t frame = pack_frame(code);
Serial.print("SENDING '");
for(int i=0; i<char_len; i++) Serial.print(s[i]);
Serial.print("' FRAME: ");
for (int i = 7; i >= 0; i--) Serial.print(bitRead(frame, i));
Serial.println();
pio_sm_put_blocking(pio0, sm_id, (uint32_t)frame << 24);
s += char_len;
} else {
s++;
}
delay(45);
}
// --- ДОБАВЛЕНИЕ CR + LF В КОНЦЕ ПЕРЕДАЧИ ---
uint8_t cr_frame = pack_frame(0x02); // Код Carriage Return
uint8_t lf_frame = pack_frame(0x08); // Код Line Feed
Serial.println("SENDING CR+LF...");
pio_sm_put_blocking(pio0, sm_id, (uint32_t)cr_frame << 24);
delay(45);
pio_sm_put_blocking(pio0, sm_id, (uint32_t)lf_frame << 24);
delay(45);
}
static const uint16_t rtty_modem_instructions[] = {
0x80a0, // 0: pull block
0xe047, // 1: set y, 7
0x7401, // 2: out pins, 1 [20]
0xe03f, // 3: set x, 31
0xbf42, // 4: nop [31]
0x0074, // 5: jmp x-- 4 [31]
0x0082, // 6: jmp y-- 2
0xe001, // 7: set pins, 1
};
static const struct pio_program rtty_prog = {
.instructions = rtty_modem_instructions,
.length = 8,
.origin = -1,
};
static const uint16_t fsk_modulator_instructions[] = {
0x00C7, // 0: jmp pin 7
0xfc01, // 1: set pins, 1 [28]
0xbc42, // 2: nop [28]
0xfc00, // 3: set pins, 0 [28]
0xbb42, // 4: nop [27]
0x0000, // 5: jmp 0 (Возврат на проверку пина)
0x0001, // 6: jmp 1
0xf801, // 7: set pins, 1 [24]
0xb842, // 8: nop [24]
0xf800, // 9: set pins, 0 [24]
0xb742 // 10: nop [23]
};
static const struct pio_program fsk_mod_prog = {
.instructions = fsk_modulator_instructions,
.length = 11,
.origin = -1,
};
void fsk_mod_setup() {
uint offset = pio_add_program(pio, &fsk_mod_prog);
sm_fsk = pio_claim_unused_sm(pio, true);
pio_gpio_init(pio, pin_fsk_out);
pio_gpio_init(pio, pin_fsk_in);
pio_sm_set_consecutive_pindirs(pio, sm_fsk, pin_fsk_out, 1, true);
pio_sm_set_consecutive_pindirs(pio, sm_fsk, pin_fsk_in, 1, false);
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_set_pins(&c, pin_fsk_out, 1);
sm_config_set_jmp_pin(&c, pin_fsk_in);
float div = (float)clock_get_hz(clk_sys) / PIO_FREQ_FSK;
sm_config_set_clkdiv(&c, div);
// Явный wrap для FSK модулятора
sm_config_set_wrap(&c, offset, offset + 10);
pio_sm_init(pio, sm_fsk, offset, &c);
pio_sm_set_enabled(pio, sm_fsk, true);
}
void rtty_modem_setup() {
uint offset = pio_add_program(pio0, &rtty_prog);
sm_id = pio_claim_unused_sm(pio0, true);
// Твоя динамическая коррекция прыжков
pio0->instr_mem[offset + 5] = 0x0040 | (offset + 4) | (31 << 8);
pio0->instr_mem[offset + 6] = 0x0080 | (offset + 2);
pio_gpio_init(pio0, pin_rtty_out);
pio_sm_set_consecutive_pindirs(pio0, sm_id, pin_rtty_out, 1, true);
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_out_pins(&c, pin_rtty_out, 1);
sm_config_set_set_pins(&c, pin_rtty_out, 1);
sm_config_set_out_shift(&c, false, false, 8);
sm_config_set_wrap(&c, offset, offset + 7);
float div = (float)clock_get_hz(clk_sys) / PIO_FREQ;
sm_config_set_clkdiv(&c, div);
pio_sm_init(pio0, sm_id, offset, &c);
pio_sm_set_enabled(pio0, sm_id, true);
}
void setup() {
set_sys_clock_khz(125000, true);
Serial.begin(115200);
rtty_modem_setup();
fsk_mod_setup();
}
void loop() {
send_rtty_string("CQ CQ CQ DE RU0AOG ПРИВЕТ");
send_rtty_string("Съешь ещё этих мягких французских булок, да выпей же чаю (русский)");
send_rtty_string("The quick brown fox jumps over the lazy dog (english)");
send_rtty_string("0123456789,+/-.=(:'?)");
Serial.println("pause");
delay(5000);
}
В порт происходит вывод передаваемых символов и кодов
Вложение:
02.jpg [ 161.49 КБ | 89 просмотров ]
.
Проверяем программой передачу символов.
Цифра 0 почему-то принимается как что-то непонятное, хотя код соответствует.
Вложение:
01.jpg [ 256.45 КБ | 89 просмотров ]
.
Вложение:
Sound002.mp3 [296.25 КБ]
2 скачивания
.
Вложение:
RTTY_GEN.rar [398.56 КБ]
3 скачивания