Формат знакогенератора символов MAX7456 Печать
Добавил(а) microsin   

Формат файлов `.mcm` для микросхемы MAX7456 [1] - простой текстовый формат, содержащий данные для знакогенератора — то есть растровые изображения всех 256 символов, которые можно выводить на экран.

Вот ключевые сведения об этом формате из официальной документации Maxim (ныне Analog Devices) и практических руководств:

[Структура и содержание файла .mcm]

● Основное назначение: хранение данных неперезаписываемой(1) памяти знакогенератора (Character Memory, NVM) MAX7456. Каждый файл содержит полный набор из 256 символов.

● Физическая организация: память микросхемы организована в 256 блоков по 64 байта, соответствующих 256 символам. Однако для описания одного символа размером 12x18 пикселей используется только 54 байта данных (оставшиеся 10 байт в блоке не используются).

● Кодирование пикселей: Каждый пиксель кодируется двумя битами:

   `00` — черный, непрозрачный
   `01` — прозрачный
   `10` — белый, непрозрачный
   `11` — прозрачный

● Текстовый формат: Файл `.mcm` — это обычный ASCII-текстовый файл. Его можно открыть и просмотреть в любом текстовом редакторе, например, в Блокноте Windows. Данные в файле представлены в виде последовательности шестнадцатеричных или двоичных строк (в зависимости от версии ПО), описывающих каждый байт памяти символа (одна строка содержит 1 байт, кодирующий 4 точки символа).

Примечание (1): память знакогенератора не перезаписываемая, при включении питания её содержимое автоматически переписывается в специальную оперативную память, которая используется для синтеза графики символов на экране. Эту оперативную память можно перепрограммировать через интерфейс SPI микросхемы MAX7456, изменив тем самым символы до следующего сброса или включения питания.

[Как создавать и редактировать файлы .mcm]

Работать с битовыми картами символов напрямую в текстовом виде неудобно. Для этого существуют специальные редакторы:

1. MAX7456 Font Editor — популярная бесплатная программа с открытым исходным кодом. Она позволяет графически редактировать каждый символ, а также конвертировать файлы между форматами `.mcm` и `.h` (используемым в проектах Arduino).

2. Официальное ПО Maxim (Analog Devices) — оценочный комплект (EV kit) от производителя включает программу для создания и загрузки пользовательской графики, которая также работает с файлами `.mcm`.

3. Редактирование через Excel: в официальном руководстве описан метод использования таблиц Excel для пакетного преобразования цветов пикселей в существующем файле `.mcm` с помощью формул.

4. Ниже во врезке приведен код скрипта Python, который позволяет редактировать графику символов знакогенератора.

[Практическое использование]

● Совместно с .mdm файлом: для полной работы OSD также нужен файл `.mdm` (Display Memory File), который определяет, какие именно символы из `.mcm` и в каком порядке выводятся на экран.

● Загрузка в микросхему:

   - с помощью оценочного комплекта производителя по последовательному интерфейсу.
   - с помощью платформы Arduino и специального скетча-загрузчика, который передает данные из файла `.mcm` (часто предварительно сконвертированного в `.h`) в MAX7456 по интерфейсу SPI.
   - в терминальных программах (например, Tera Term, putty) через последовательный порт.

● Важное замечание о кодировке: символы в стандартной поставке микросхемы не соответствуют кодировке ASCII, что может приводить к выводу "кракозябр" при попытке прямого вывода текста. Поэтому для нормальной работы с латиницей и кириллицей необходимо загрузить пользовательский знакогенератор, где символы расставлены в правильном порядке.

Этот скрипт позволяет конвертировать файл *.mcm в заголовочный файл C, где находятся данные массива знакогенератора. Кроме того, он позволяет интерактивно редактировать графику каждого символа. Запуск скрипта без опций выводит справку по командной строке:

$ python ./MAX7456_font_editor.py
usage: MAX7456_font_editor.py [ОПЦИИ] [ВХОДНОЙ_ФАЙЛ]
Конвертер шрифтов MAX7456 из MCM в C заголовочный файл
positional arguments: input_file Входной MCM файл
options: --output, -o OUTPUT Выходной заголовочный файл --show, -s N Показать символ с индексом N (0-255) --graphical, -g Показать символ в графическом окне (требуется PyGame) --help, -h Показать справку
Примеры: MAX7456_font_editor.py font.mcm Конвертировать font.mcm в MAX7456font.h MAX7456_font_editor.py font.mcm -o output.h Конвертировать с указанием выходного файла MAX7456_font_editor.py font.mcm -s 65 Показать символ #65 в консоли MAX7456_font_editor.py font.mcm -s 65 -g Показать символ #65 в графическом окне MAX7456_font_editor.py font.mcm -s 65 -o out.h -g Показать символ #65 и конвертировать MAX7456_font_editor.py --help Показать эту справку
Управление в графическом режиме: ← → Переключение между символами ESC/Q Выход из программы

MAX7456 charset editor Python

Содержимое скрипта (MAX7456_font_editor.py):

import sys
import argparse
import os

# Константы для символов отображения в консоли BLACK = '■' # 00 — черный, непрозрачный TRANSP1 = '⬝' # 01 — прозрачный (темно-серый) WHITE = '□' # 10 — белый, непрозрачный TRANSP2 = ' ' # 11 — прозрачный (пробел)

def try_import_pygame():
"""Пытается импортировать PyGame и возвращает статус""" try: import pygame pygame_available = True return pygame, pygame_available except ImportError: return None, False

def display_character_graphical(initial_char_index, data_lines, input_file=None):
"""Отображает символ в графическом окне PyGame с возможностью редактирования""" pygame, pygame_available = try_import_pygame() if not pygame_available: print("Предупреждение: PyGame не установлен. Графический режим недоступен.") print("Установите PyGame: pip install pygame") return False try: # Инициализация PyGame pygame.init() # Размеры окна pixel_size = 24 # Увеличиваем для удобства кликов width = 12 * pixel_size + 300 # Больше места для кнопок height = 18 * pixel_size + 250 # Создаем окно screen = pygame.display.set_mode((width, height)) # Текущий символ current_char_index = initial_char_index # Загружаем исходные данные original_char_data = data_lines.copy() # Функция для получения данных текущего символа def get_current_pixel_data(): pixel_data = extract_pixel_data(data_lines, current_char_index) if pixel_data is None: return [['01'] * 12 for _ in range(18)] return pixel_data # Получаем начальные данные pixel_data = get_current_pixel_data() # Максимальное количество символов в файле max_char_in_file = (len(data_lines) // 64) - 1 if data_lines else 0 # Состояние редактирования edit_mode = True changes_made = False # Соответствие состояний и их смены state_cycle = { '00': '01', '01': '10', '10': '11', '11': '00' } # Кнопки button_height = 30 button_width = 200 button_margin = 10 # Создаем кнопки class Button: def __init__(self, x, y, width, height, text, color=(70, 70, 70), hover_color=(100, 100, 100)): self.rect = pygame.Rect(x, y, width, height) self.text = text self.color = color self.hover_color = hover_color self.current_color = color self.font = pygame.font.SysFont(None, 20) def draw(self, screen): pygame.draw.rect(screen, self.current_color, self.rect, border_radius=5) pygame.draw.rect(screen, (120, 120, 120), self.rect, 2, border_radius=5) text_surf = self.font.render(self.text, True, (220, 220, 220)) text_rect = text_surf.get_rect(center=self.rect.center) screen.blit(text_surf, text_rect) def check_hover(self, pos): self.current_color = self.hover_color if self.rect.collidepoint(pos) else self.color return self.rect.collidepoint(pos) def is_clicked(self, pos, event_type): return self.rect.collidepoint(pos) and event_type == pygame.MOUSEBUTTONDOWN # Создаем кнопки y_pos = 100 save_button = Button(width - button_width - button_margin, y_pos, button_width, button_height, "Сохранить", (60, 100, 60)) y_pos += (button_height + button_margin) reset_button = Button(width - button_width - button_margin, y_pos, button_width, button_height, "Сбросить", (100, 60, 60)) y_pos += (button_height + button_margin) edit_toggle = Button(width - button_width - button_margin, y_pos, button_width, button_height, "Редактирование: ВКЛ", (70, 70, 120)) running = True while running: # Обновляем заголовок окна title = f"MAX7456 Символ #{current_char_index} (0x{current_char_index:02X})" if changes_made: title += " *ИЗМЕНЕНО*" pygame.display.set_caption(title) # Получаем позицию мыши mouse_pos = pygame.mouse.get_pos() # Обрабатываем события for event in pygame.event.get(): if event.type == pygame.QUIT: if changes_made: # Спросим о сохранении print("\nЕсть несохраненные изменения!") print("Закройте окно снова для выхода без сохранения") changes_made = False # Сбросим, чтобы можно было выйти continue running = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE or event.key == pygame.K_q: if changes_made: print("\nЕсть несохраненные изменения! Используйте кнопку 'Сохранить'") continue running = False elif event.key == pygame.K_RIGHT: if changes_made: print("Предупреждение: есть несохраненные изменения!") new_index = current_char_index + 1 if new_index > 255: new_index = 0 if new_index < = max_char_in_file: current_char_index = new_index pixel_data = get_current_pixel_data() changes_made = False print(f"\nПереключено на символ #{current_char_index} (0x{current_char_index:02X})") display_character_console(data_lines, current_char_index, pixel_data) elif event.key == pygame.K_LEFT: if changes_made: print("Предупреждение: есть несохраненные изменения!") new_index = current_char_index - 1 if new_index < 0: new_index = 255 if new_index < = max_char_in_file: current_char_index = new_index pixel_data = get_current_pixel_data() changes_made = False print(f"\nПереключено на символ #{current_char_index} (0x{current_char_index:02X})") display_character_console(data_lines, current_char_index, pixel_data) elif event.type == pygame.MOUSEBUTTONDOWN: # Проверяем клики по пикселям (только в режиме редактирования) if edit_mode: offset_x = 50 offset_y = 100 # Проверяем попал ли клик в область сетки grid_rect = pygame.Rect(offset_x, offset_y, 12 * pixel_size, 18 * pixel_size) if grid_rect.collidepoint(mouse_pos): # Определяем координаты пикселя rel_x = mouse_pos[0] - offset_x rel_y = mouse_pos[1] - offset_y pixel_x = rel_x // pixel_size pixel_y = rel_y // pixel_size if 0 < = pixel_x < 12 and 0 < = pixel_y < 18: # Меняем состояние пикселя current_state = pixel_data[pixel_y][pixel_x] new_state = state_cycle.get(current_state, '00') pixel_data[pixel_y][pixel_x] = new_state # Обновляем исходные данные update_binary_data(data_lines, current_char_index, pixel_data) changes_made = True print(f"Пиксель [{pixel_y},{pixel_x}] изменен: {current_state} -> {new_state}") # Проверяем клики по кнопкам if save_button.is_clicked(mouse_pos, pygame.MOUSEBUTTONDOWN): if save_changes(input_file, data_lines, original_char_data): changes_made = False original_char_data = data_lines.copy() print("✓ Изменения сохранены в исходный файл!") elif reset_button.is_clicked(mouse_pos, pygame.MOUSEBUTTONDOWN): if changes_made: # Восстанавливаем оригинальные данные start_idx = current_char_index * 64 end_idx = start_idx + 64 data_lines[start_idx:end_idx] = original_char_data[start_idx:end_idx] pixel_data = get_current_pixel_data() changes_made = False print("✓ Изменения сброшены!") elif edit_toggle.is_clicked(mouse_pos, pygame.MOUSEBUTTONDOWN): edit_mode = not edit_mode edit_toggle.text = f"Редактирование: {'ВКЛ' if edit_mode else 'ВЫКЛ'}" edit_toggle.color = (70, 120, 70) if edit_mode else (120, 70, 70) print(f"Режим редактирования: {'ВКЛ' if edit_mode else 'ВЫКЛ'}") # Проверяем ховер кнопок save_button.check_hover(mouse_pos) reset_button.check_hover(mouse_pos) edit_toggle.check_hover(mouse_pos) # Очистка экрана screen.fill((30, 30, 30)) # Отступы для сетки offset_x = 50 offset_y = 100 # Рисуем сетку for x in range(13): pygame.draw.line(screen, (80, 80, 80), (offset_x + x * pixel_size, offset_y), (offset_x + x * pixel_size, offset_y + 18 * pixel_size), 1) for y in range(19): pygame.draw.line(screen, (80, 80, 80), (offset_x, offset_y + y * pixel_size), (offset_x + 12 * pixel_size, offset_y + y * pixel_size), 1) # Рисуем пиксели for y in range(18): for x in range(12): if y < len(pixel_data) and x < len(pixel_data[y]): pixel_type = pixel_data[y][x] colors = { '00': (0, 0, 0), # черный '01': (100, 100, 100), # серый '10': (255, 255, 255), # белый '11': (50, 50, 50) # темно-серый } color = colors.get(pixel_type, (255, 0, 0)) # Подсветка при наведении (в режиме редактирования) pixel_rect = pygame.Rect( offset_x + x * pixel_size + 1, offset_y + y * pixel_size + 1, pixel_size - 2, pixel_size - 2 ) if edit_mode and pixel_rect.collidepoint(mouse_pos): # Подсветка при наведении highlight_color = ( min(color[0] + 40, 255), min(color[1] + 40, 255), min(color[2] + 40, 255) ) pygame.draw.rect(screen, highlight_color, pixel_rect) else: pygame.draw.rect(screen, color, pixel_rect) # Если пиксель прозрачный, рисуем крестик if pixel_type in ['01', '11']: pygame.draw.line(screen, (150, 150, 150), (offset_x + x * pixel_size + 3, offset_y + y * pixel_size + 3), (offset_x + (x + 1) * pixel_size - 3, offset_y + (y + 1) * pixel_size - 3), 1) pygame.draw.line(screen, (150, 150, 150), (offset_x + (x + 1) * pixel_size - 3, offset_y + y * pixel_size + 3), (offset_x + x * pixel_size + 3, offset_y + (y + 1) * pixel_size - 3), 1) # Шрифты font = pygame.font.SysFont(None, 24) small_font = pygame.font.SysFont(None, 18) # Отображаем заголовок title_text = f"Символ #{current_char_index} (0x{current_char_index:02X})" if changes_made: title_text += " *" title_surf = font.render(title_text, True, (255, 255, 255)) screen.blit(title_surf, (width // 2 - title_surf.get_width() // 2, 20)) # Информация о файле info_text = f"Символов в файле: 0-{max_char_in_file}" info_surf = small_font.render(info_text, True, (200, 200, 200)) screen.blit(info_surf, (width // 2 - info_surf.get_width() // 2, 50)) # Легенда с интерактивными примерами - В 4 СТРОКИ # legend_y = offset_y + 18 * pixel_size + 20 legend_y = 300 legend_items = [ ("00: Чёрный", (0, 0, 0), "00"), ("01: Прозрачный", (100, 100, 100), "01"), ("10: Белый", (255, 255, 255), "10"), ("11: Прозрачный", (50, 50, 50), "11") ] # Отображаем цветные квадраты и названия в 4 строках (по одному в строке) for i, (text, color, state) in enumerate(legend_items): # Цветной квадрат rect_x = 400 # Фиксированная позиция X для всех строк color_rect = pygame.Rect(rect_x, legend_y + i * 25, 15, 15) # Смещаем по Y на 25px для каждой строки pygame.draw.rect(screen, color, color_rect) # Текст состояния legend_text = small_font.render(text, True, (200, 200, 200)) screen.blit(legend_text, (rect_x + 25, legend_y + i * 25 - 2)) # Текст правее квадрата # Рисуем кнопки save_button.draw(screen) reset_button.draw(screen) edit_toggle.draw(screen) # Инструкции instructions = [ "Клик по пикселю: изменить состояние (00 -> 01 -> 10 -> 11 -> 00)", "Стрелки влево/вправо: переключение символов", "ESC или Q: выход (только если нет изменений)" ] for i, instruction in enumerate(instructions): instr_text = small_font.render(instruction, True, (180, 180, 180)) screen.blit(instr_text, (width // 2 - instr_text.get_width() // 2, height - 100 + i * 20)) # Статус редактирования status_color = (150, 200, 150) if edit_mode else (200, 150, 150) status_text = "РЕЖИМ РЕДАКТИРОВАНИЯ: АКТИВЕН" if edit_mode else "Режим редактирования: выключен" status_surf = small_font.render(status_text, True, status_color) screen.blit(status_surf, (width // 2 - status_surf.get_width() // 2, height - 30)) pygame.display.flip() pygame.quit() return True except Exception as e: print(f"Ошибка в графическом режиме: {e}") import traceback traceback.print_exc() return False

def update_binary_data(data_lines, char_index, pixel_data):
"""Обновляет бинарные данные на основе измененных пикселей""" start_line = char_index * 64 # Преобразуем пиксели обратно в бинарные строки for row in range(18): # Получаем 12 пикселей строки row_pixels = pixel_data[row] # Преобразуем в 24 бита (12 пикселей × 2 бита) binary_str = "" for pixel in row_pixels: binary_str += pixel # Разбиваем на 3 строки по 8 бит line1 = binary_str[0:8] line2 = binary_str[8:16] line3 = binary_str[16:24] # Обновляем данные line_idx1 = row * 3 line_idx2 = row * 3 + 1 line_idx3 = row * 3 + 2 if line_idx1 < 54 and start_line + line_idx1 < len(data_lines): data_lines[start_line + line_idx1] = line1 if line_idx2 < 54 and start_line + line_idx2 < len(data_lines): data_lines[start_line + line_idx2] = line2 if line_idx3 < 54 and start_line + line_idx3 < len(data_lines): data_lines[start_line + line_idx3] = line3

def save_changes(filename, data_lines, original_data):
"""Сохраняет изменения обратно в файл""" if not filename: print("Ошибка: имя файла не указано для сохранения") return False try: # Создаем содержимое файла content = "MAX7456\n" + "\n".join(data_lines) # Сохраняем файл with open(filename, 'w') as f: f.write(content) return True except Exception as e: print(f"Ошибка при сохранении файла: {e}") return False

def extract_pixel_data(data_lines, char_index):
"""Извлекает данные пикселей для символа""" start_line = char_index * 64 end_line = start_line + 64 if start_line >= len(data_lines): return None char_data = data_lines[start_line:end_line] pixel_data = [] # Преобразуем каждые 3 строки данных в строку пикселей for row in range(18): line_idx1 = row * 3 line_idx2 = row * 3 + 1 line_idx3 = row * 3 + 2 if line_idx1 >= 54 or line_idx1 >= len(char_data): # Заполняем прозрачным если данных нет pixel_data.append(['01'] * 12) continue line1 = char_data[line_idx1] line2 = char_data[line_idx2] if line_idx2 < len(char_data) else "00000000" line3 = char_data[line_idx3] if line_idx3 < len(char_data) else "00000000" # Объединяем три байта combined = line1 + line2 + line3 # Извлекаем 12 пар битов (12 пикселей) row_pixels = [] for i in range(0, 24, 2): bit_pair = combined[i:i+2] row_pixels.append(bit_pair) pixel_data.append(row_pixels) return pixel_data

def display_character_console(data_lines, char_index, pixel_data=None):
"""Отображает символ в консоли в текстовом виде""" if pixel_data is None: pixel_data = extract_pixel_data(data_lines, char_index) if pixel_data is None: print(f"Ошибка: символ с индексом {char_index} не найден в файле") print(f"В файле {len(data_lines)} строк данных, максимум {len(data_lines)//64} символов") return False, None # Получаем полные данные символа (64 строки) start_line = char_index * 64 end_line = start_line + 64 char_data = data_lines[start_line:end_line] if start_line < len(data_lines) else [] print(f"\nСимвол #{char_index} (0x{char_index:02X}):") print(" " + "─" * 13 + "→" + " 12 пикселей") # Отображаем пиксели for row in range(18): display_line = "" if row < len(pixel_data): for pixel in pixel_data[row]: if pixel == "00": display_line += BLACK elif pixel == "01": display_line += TRANSP1 elif pixel == "10": display_line += WHITE elif pixel == "11": display_line += TRANSP2 else: display_line += "?" else: display_line = TRANSP2 * 12 print(f"{row:2d}{display_line}") print(" " + "─" * 13) # Легенда print("\nЛегенда:") print(f" {BLACK} - черный, непрозрачный (00)") print(f" {TRANSP1} - прозрачный (01)") print(f" {WHITE} - белый, непрозрачный (10)") print(f" '{TRANSP2}' - прозрачный (пробел) (11)") # Дополнительная информация print(f"\nИнформация о данных:") print(f" Всего строк данных для символа: {len(char_data)}") print(f" Используется строк: 54 (18 строк × 3)") print(f" Не используется строк: 10") print(f" Пикселей в строке: 12") print(f" Строк в символе: 18") # Показываем неиспользуемые данные, если они есть if len(char_data) > 54: unused_data = char_data[54:] print(f"\nНеиспользуемые данные (строки 54-63):") for i, line in enumerate(unused_data): print(f" [{i+54:2d}] {line}") return True, pixel_data

def convert_mcm_to_header(input_file, output_file, show_char=None, graphical=False):
"""Конвертирует MCM файл в C заголовочный файл""" # Читаем входной файл with open(input_file, 'r') as f: lines = f.readlines() # Удаляем пустые строки и пробелы lines = [line.strip() for line in lines if line.strip()] # Проверяем заголовок if len(lines) == 0: raise ValueError("Файл пуст") if lines[0] != 'MAX7456': raise ValueError("Неверный формат MCM файла. Первая строка должна быть 'MAX7456'") # Проверяем строки с данными char_data = [] for i, line in enumerate(lines[1:], 1): if len(line) != 8 or not all(c in '01' for c in line): raise ValueError(f"Неверная строка данных #{i}: '{line}' (должно быть 8 бит)") char_data.append(line) # Проверяем полный набор символов total_data_lines = len(char_data) lines_per_char = 64 if total_data_lines % lines_per_char != 0: print(f"Внимание: файл содержит {total_data_lines} строк данных,") print(f"что не кратно {lines_per_char} (64 строки на символ).") # Если запрошен показ символа if show_char is not None: if not 0 < = show_char < = 255: raise ValueError("Индекс символа должен быть в диапазоне 0-255") # Проверяем, есть ли символ в файле max_char = (len(char_data) // lines_per_char) - 1 if show_char > max_char: print(f"Внимание: файл содержит только символы 0-{max_char}") if max_char >= 0: print(f"Показываю символ #{max_char} вместо #{show_char}") show_char = max_char # Извлекаем данные пикселей pixel_data = extract_pixel_data(char_data, show_char) if pixel_data: # Отображаем в консоли начальный символ success, _ = display_character_console(char_data, show_char, pixel_data) # Если запрошен графический режим if success and graphical: print("\n" + "="*50) print("Запуск графического режима с редактированием...") print("Клик по пикселю: 00 → 01 → 10 → 11 → 00") print("Стрелки: переключение символов") print("Кнопки: Сохранить, Сбросить, Вкл/Выкл редактирование") print("="*50) # Передаем также имя файла для возможности сохранения display_character_graphical(show_char, char_data, input_file) # Если только показ символа без конвертации - завершаем if output_file is None: return None # Если нужна конвертация if output_file is not None: num_chars = len(char_data) // lines_per_char char_arrays = [] for char_idx in range(num_chars): start = char_idx * lines_per_char end = start + lines_per_char char_lines = char_data[start:end] hex_lines = [] for line in char_lines: hex_val = format(int(line, 2), '02x') hex_lines.append(f"0x{hex_val}") char_array = " " + ",".join(hex_lines) char_arrays.append(char_array) header_content = f"""// MAX7456 Font Data
// Converted from {os.path.basename(input_file)}
// Total characters: {num_chars}
// Total bytes: {len(char_data)}
// Structure: 18 rows × 12 pixels, 2 bits per pixel
// Memory layout: 64 bytes per character (54 used, 10 unused)

PROGMEM const byte fontdata[{len(char_data)}] = {{{",\n".join(char_arrays)}}};""" with open(output_file, 'w') as f: f.write(header_content) return len(char_data) return None

def main(): parser = argparse.ArgumentParser( description="Конвертер шрифтов MAX7456 из MCM в C заголовочный файл", formatter_class=argparse.RawDescriptionHelpFormatter, usage='%(prog)s [ОПЦИИ] [ВХОДНОЙ_ФАЙЛ]', add_help=False, epilog="""
Примеры:
%(prog)s font.mcm Конвертировать font.mcm в MAX7456font.h
%(prog)s font.mcm -o output.h Конвертировать с указанием выходного файла
%(prog)s font.mcm -s 65 Показать символ #65 в консоли
%(prog)s font.mcm -s 65 -g Показать символ #65 в графическом окне
%(prog)s font.mcm -s 65 -o out.h -g Показать символ #65 и конвертировать
%(prog)s --help Показать эту справку

Управление в графическом режиме:
← → Переключение между символами
ESC/Q Выход из программы
""" ) # Аргументы parser.add_argument( 'input_file', nargs='?', help='Входной MCM файл' ) parser.add_argument( '--output', '-o', help='Выходной заголовочный файл' ) parser.add_argument( '--show', '-s', type=int, metavar='N', help='Показать символ с индексом N (0-255)' ) parser.add_argument( '--graphical', '-g', action='store_true', help='Показать символ в графическом окне (требуется PyGame)' ) parser.add_argument( '--help', '-h', action='store_true', help='Показать справку' ) # Парсим аргументы if len(sys.argv) == 1: parser.print_help() sys.exit(0) args = parser.parse_args() # Показываем справку если запрошено if args.help: parser.print_help() sys.exit(0) # Проверяем обязательные аргументы if not args.input_file: print("Ошибка: необходимо указать входной файл\n") parser.print_usage() print("\nИспользуйте --help для полной справки") sys.exit(1) # Проверяем существование файла if not os.path.exists(args.input_file): print(f"Ошибка: файл '{args.input_file}' не найден") sys.exit(1) # Проверяем расширение файла if not args.input_file.lower().endswith('.mcm'): print(f"Внимание: файл '{args.input_file}' не имеет расширения .mcm") # Проверяем диапазон индекса символа if args.show is not None and not (0 < = args.show < = 255): print("Ошибка: индекс символа должен быть в диапазоне 0-255") sys.exit(1) try: # Конвертируем или показываем символ if args.show is not None: print(f"Обработка файла: {args.input_file}") if args.output: print(f"Выходной файл: {args.output}") if args.graphical: print(f"Режим: графический") result = convert_mcm_to_header( args.input_file, args.output, args.show, args.graphical ) # Если была конвертация if args.output and result: lines_per_char = 64 num_chars = result // lines_per_char print(f"\nКонвертация завершена успешно!") print(f"Сконвертировано символов: {num_chars}") print(f"Всего строк данных: {result}") elif args.output and args.show is not None: # И показ и конвертация print(f"\nКонвертация также выполнена в файл: {args.output}") elif args.output and result: # Только конвертация без показа print(f"\nКонвертация завершена успешно!") except ValueError as e: print(f"Ошибка: {e}") sys.exit(1) except Exception as e: print(f"Неожиданная ошибка: {e}") import traceback traceback.print_exc() sys.exit(1)

if __name__ == "__main__": main()

[Ссылки]

1. MAX7456: микросхема OSD.
2. ascended / MAX7456FontEditor site:github.com - GUI-редактор знакогенератора MAX7456, с исходным кодом (C#, Windows).