НИИЭТ К1921ВГ1Т : бегущие огни
Бегущие огни с выбором направления кнопкой
Введение
В бегущих огнях видимое движение создаётся последовательным включением соседних светодиодов. Состояние такого устройства определяется двумя величинами: текущей позицией и направлением. Если хранить их раздельно, направление можно менять без скачка позиции.
В проекте световая точка делает пять шагов за секунду. Кнопка переключает направление, а временная сетка движения остаётся прежней. Сначала рассмотрим эту логику на графиках, затем воспроизведём её на четырёх светодиодах платы.
Постановка задачи и исходные данные
Начальная позиция – LED1, направление – к LED2. Переход между соседними позициями происходит каждые 0,2 с, то есть с частотой 5 Гц. Полный обход четырёх светодиодов занимает 0,8 с. Каждое нажатие меняет направление; удержание кнопки не создаёт новых переключений. В расчёте два нажатия возвращают исходное направление.
Для воспроизведения откройте эту папку в Engee. Расчётная модель находится в NIIET03_running_sim.engee, версия для платы – в NIIET03_running_target.engee. Кодовые ячейки ниже выполняются последовательно; путь к моделям определяется каталогом самого скрипта.
Алгоритм
Кнопка переключает двоичный признак направления r. Позиция j изменяется только по собственной сетке 0,2 с; клик не сбрасывает её.
5 Гц – частота переходов между соседними светодиодами; полный обход четырёх позиций занимает 0,8 с.
Рисунок 1. Алгоритм работы устройства.
Построение модели в Engee
Подсистема ButtonEvent подтверждает изменение уровня после 20 одинаковых отсчётов с интервалом 1 мс и формирует одиночный Click. Счётчик DirectionMemory изменяется по модулю 2: значение 0 означает прямое направление, 1 – обратное. Switch выбирает приращение +1 или −1.
Для движения нужен собственный ритм, независимый от кнопки. TickMemory считает такты 1 мс по модулю 200. Сравнение с 199 разрешает обновление позиции на следующем такте, то есть ровно раз в 0,2 с. Между такими моментами StepEnable сохраняет прежнюю позицию.
LEDIndex хранит индекс 0…3, а сумма с выбранным приращением и остаток по модулю 4 дают новую позицию. Четыре Compare To Constant с константами 0, 1, 2, 3 включают ровно один светодиод. Поскольку направление обновляется быстрее, ближайший шаг движения уже использует новое значение.
Рисунок 2. Расчётная модель NIIET03_running_sim.
В расчётной модели блок Engee Function формирует сигнал кнопки с шагом 1 мс. Интервалы нажатий заданы в целых миллисекундах. В первые 6 мс каждого нажатия уровень чередуется, имитируя дребезг контакта.
Запуск расчёта
Теперь запустим сохранённую модель. Первая ячейка открывает её и задаёт исходные параметры примера, чтобы значения в коде можно было сопоставить с настройками блоков. После engee.run станут доступны временные ряды измеряемых сигналов.
using Plots
gr(format=:png)
demo_dir = @__DIR__
model_name = "NIIET03_running_sim"
if !any(m -> string(m.name) == model_name, engee.get_all_models())
engee.load(joinpath(demo_dir, model_name * ".engee"))
end
engee.open(model_name)
f_step = 5.0
step_ticks = round(Int, 1 / (f_step * 0.001))
engee.set_param!(model_name * "/TickPeriod", "Value" => string(Float64(step_ticks)))
engee.set_param!(model_name * "/StepTick", "const" => string(Float64(step_ticks - 1)))
engee.run(model_name)
Считаем результаты моделирования. Каждый временной ряд содержит время и значение сигнала.
measurements = Dict(
"RawButton" => collect(NIIET03_running_sim_RawButton),
"Click" => collect(NIIET03_running_sim_Click),
"Pressed" => collect(NIIET03_running_sim_Pressed),
"LED1" => collect(NIIET03_running_sim_LED1),
"LED2" => collect(NIIET03_running_sim_LED2),
"LED3" => collect(NIIET03_running_sim_LED3),
"LED4" => collect(NIIET03_running_sim_LED4),
"Index" => collect(NIIET03_running_sim_Index),
"Direction" => collect(NIIET03_running_sim_Direction)
)
nothing
Разбор результатов
Построим временные диаграммы, чтобы сопоставить входные события, внутреннее состояние и видимую индикацию.
state_data = measurements["Index"]
p_state = plot(state_data.time, state_data.value;
seriestype=:steppost, ylabel="Позиция", label=false, lw=1.8)
p_led = plot(; ylabel="LED + смещение", xlabel="Время, с")
for i in 1:4
led = measurements["LED" * string(i)]
plot!(p_led, led.time, Float64.(led.value) .+ 1.5(i-1);
seriestype=:steppost, label="LED" * string(i), lw=1.6)
end
input_data = measurements["Direction"]
p_input = plot(input_data.time, input_data.value;
ylabel="Направление", label=false, seriestype=:steppost)
niiet_overview = plot(p_input, p_state, p_led; layout=(3,1), size=(1100,850), margin=6Plots.mm)
Рисунок 3. Состояния и выходные сигналы устройства.
Позиция меняется с интервалом 0,2 с на всём участке расчёта. Направление проходит последовательность 0→1→0. При смене направления индекс не сбрасывается: следующая позиция получается из текущей с новым знаком приращения. Поэтому обратный ход начинается с того места, где находилась световая точка.
Сумма четырёх сигналов LED во всех отсчётах равна единице. Это подтверждает, что две позиции не включаются одновременно и между ними нет отдельного погашенного состояния.
Увеличим первое нажатие. Здесь особенно хорошо видны дребезг, задержка подтверждения устойчивого состояния и единственный импульс Click.
panels = []
for (key, title) in [("RawButton","Сырой вход"),
("Pressed","Устойчивое нажатие"), ("Click","Событие нажатия")]
signal = measurements[key]
window = 0.84 .<= signal.time .<= 0.92
push!(panels, plot(signal.time[window], signal.value[window];
ylabel=title, label=false, seriestype=:steppost))
end
plot!(panels[end]; xlabel="Время, с")
niiet_detail = plot(panels...; layout=(3,1), size=(1100,800), margin=6Plots.mm)
Рисунок 4. Обработка первого нажатия.
Перенос на НИИЭТ
После моделирования перейдём к плате K1921VG1T. В таргетной версии сигналы светодиодов поступают на цифровые выходы. Источник кнопки теперь является физическим входом USER_BTN. Математическая часть определяет те же состояния и переходы, которые мы только что рассмотрели на графиках.
Таблица 1. Параметры моделей.
| Параметр | Расчёт в Engee | Выполнение на плате |
|---|---|---|
| Решатель | Euler, фиксированный шаг | Euler, фиксированный шаг |
| Шаг | 1 мс | 1 мс |
| Начало | 0 с | 0 с |
| Конец | 3.2 с | 600 с |
Таблица 2. Подключение сигналов платы.
| Сигнал | Вывод микроконтроллера | Назначение |
|---|---|---|
| USER_BTN | PB3 | Кнопка, активный уровень 0 |
| LED1 | PC12 | Позиция 0 |
| LED2 | PC13 | Позиция 1 |
| LED3 | PC14 | Позиция 2 |
| LED4 | PC15 | Позиция 3 |
Для DI зададим m_port = B, m_input = 3, SampleTime = 0.001. Низкий уровень соответствует нажатию USER_BTN. Для DO выбираются порт C и выводы m_output = 12…15 в порядке LED1…LED4; на вход подаётся UInt8. Номера PA/PB/PC обозначают выводы микроконтроллера. Их расположение на разъёмах следует найти в схеме своей ревизии платы. Для измерения PWM осциллограф подключают между сигнальным выводом и общей землёй.
Перед сборкой настроим EDM-Target-NIIETK1921VG1T. Путь к тулчейну должен указывать на установленную инфраструктуру компьютера стенда. Настройки запуска приведены отдельно, в таблице 3.
Таблица 3. Параметры EDM-Target.
| Поле | Значение |
|---|---|
| Таргет | Niietk1921vg1t |
toolchain_root |
D:\DEMO\NIIET\niietk1291vg1t_infrastructure |
programmer_type |
jlink |
toolchain_via |
auto |
code_gen_path |
. |
com_port |
COM10 |
Для прошивки подключим J-Link и установим соединение с платой в Engee.Интеграциях. Пример запускается независимо от обмена измеренными сигналами с компьютером. Время выполнения таргетной модели задано как StopTime = 600 с; его можно увеличить перед новой сборкой.
Рисунок 5. Таргетная модель NIIET03_running_target.
В следующей ячейке показана вся последовательность аппаратного запуска: открытие модели, выбор K1921VG1T, генерация кода, сборка, прошивка и старт. Для выполнения на подключённой плате установите PROGRAM_TARGET = true. При обычном повторном расчёте графиков оставьте значение false.
PROGRAM_TARGET = false
if PROGRAM_TARGET
target_name = "NIIET03_running_target"
if !any(m -> string(m.name) == target_name, engee.get_all_models())
engee.load(joinpath(demo_dir, target_name * ".engee"))
end
engee.open(target_name)
model = engee.gcm()
target = Main.EngeeDeviceManager.Targets.NIIETK1921VG1T.Niietk1921vg1t()
Main.EngeeDeviceManager.Targets.generate_executable_code(target, model, false)
Main.EngeeDeviceManager.Targets.compile_model(target, model)
Main.EngeeDeviceManager.Targets.upload_model(target, model)
Main.EngeeDeviceManager.Targets.start_model(target, model, false)
end
Светодиоды переключаются с интервалом 0,2 с. Затем нажмите кнопку и убедитесь, что ближайший шаг меняет направление без возврата к LED1. Приведённые графики получены при моделировании в Engee; результаты измерений физических выходов можно сопоставить с ними в том же масштабе времени.
Выводы
Разделение позиции, направления и разрешения временного шага позволяет независимо управлять движением. Частота 5 Гц сохраняется при нажатиях, а знак приращения определяет порядок обхода. Новое направление действует с ближайшего шага после нажатия.

