Как сделать светофор в лабвью

Обновлено: 05.07.2024

На стороне компьютера применяют различные терминальные программы, коих сотни. Но эти программы обеспечивают лишь прием и передачу информации. Как то обрабатывать и визуализировать ее в наглядной форме затруднительно.

Некоторые пишут подобное ПО самостоятельно на каком либо языке программирования (Delphi, C++), наделяя необходимым функционалом. Но эта задача не из легких, нужно знать, помимо самого языка, устройство операционной системы, способы работы с комуникационными портами, множество других технических тонкостей, которые отвлекают от главного — реализации алгоритма программы. В общем, быть попутно еще Windows/Unix программистом.

На фоне этих подходов резко отличается концепция виртуальных приборов (vi). В этой статье пойдет речь о программном продукте LabView фирмы Nationals Instruments. Я только начинаю осваивать этот замечательный продукт, поэтому могу допускать неточности и ошибки. Спецы поправят :-)) Собственно что такое LabView?

Задача
У нас есть плата с микроконтроллером AVR, соединенная с компьютером по RS232. В контроллер залита прошивка, согласно которой контроллер измеряет значение напряжения на одном из входов АЦП, и передает код АЦП (от 0 до 1023) в компьютер по последовательному каналу. Необходимо написать программу для ПК, которая будет принимать поток данных от АЦП, отображать код АЦП, преобразовывать код АЦП в значение напряжения в вольтах, отображать значение напряжения в вольтах, строить график изменения напряжения во времени.

Ну наверное хватит лирики, начнем пожалуй!

Итак что нам потребуется для работы:

Первым делом нам нужно убедится, что VISA нашла в системе COM порт и корректно с ним работает. Проверить это можно так: запускаем программу Measurement & Automation. Она ставится вместе с LabView. Если она не установилась, установить можно вручную. На диске (образе с LabView она есть).


Запускаем LabView. В окне Getting Started выбираем пункт Blank Vi, тобишь новый виртуальный прибор.


Получаем вот такую штуку:


Итак что мы имеем. Рабочая область состоит из двух больших панелей Front Panel и Block Diagram. На лицевой панели мы будем составлять интерфейс нашей программы, используя элементы управления с панели Controls. Эти элементы представляют собой привычные нам ручки переменных резисторов, светодиоды, кнопки, стрелочные приборы, экран осциллографа и т.п. Они служат для ввода информации в программу и отображения результатов выполнения. На панели Block Diagram распологается непосредственно программный код. Тут надо немного отступить и пояснить принцип программирования на LabView. Небольшой пример. Принято работу над прогой начинать с оформления интерфейса, а затем реализации алгоритма работы на блок-диаграмме. Сделаем простейшую прогу умножения двух чисел. Для этого разместим на лицевой панели путем перетаскивания три элемента управления, скажем элементы Knob и Numeric Indicator для отображения результата.


Сформируем интерфейс как душа пожелает, например вот так:



Теперь нужно добавить на блок-диаграмму функцию умножения. Щелкаем ПКМ на блок-диаграмме и из палитры Numeric выбираем функцию умножения Multiply. Преносим ее на диаграмму. Стоит заметить, что LabView имеет просто огромный набор функций. Это и различная математика, статистика, анализ сигналов, PID регулирование, обработка видео, звука и изображений. Всего не перечислишь.


Важнейшей концепцией программирования на LabView является концепция потоков данных DataFlow. Суть такова: В отличие от императивных языков программирования, где операторы выполняются в порядке следования, в LabView функции работают только если на всех входах функции есть информация (каждая функция имеет входные и выходные значения). Только тогда функция реализует свой алгоритм, а результат направляет на выход, который может быть использован другой функцией. Таким образом в пределах одного виртуального прибора функции могут работать независимо друг от друга.

Теперь, для того чтобы оживить наш примерчик, нам необходимо последовать этой концепции и подать на вход функции числовые значения, которые мы устанавливаем контролами, а с выхода получить результат и отобразить его.

Для соединения элементов на блок-диаграмме используется инструмент Connect Wire с панели Tools. Выбираем его и рисуем наши соединения.


Собственно все, можно запустить эту тупую программку на циклическое выполнение и покрутить ручки, наблюдая результат умножения.


Как видно, ничего сложного вроде бы нет. Но в то же время LabView позволяет решать задачи любой сложности! Епт, система управления БАК на нем сделана! Так то.

Ну а теперь займемся более интересными вещами, а именно сделаем наш простейший вольтметр, о котором я говорил в самом начале.

Итак, что нам необходимо сделать. Сначала нужно настроить и проинициализировать последовательный порт. Запустить бесконечный цикл . В цикле мы используем функцию чтения из порта и принимаем информацию. Преобразуем инфу для отображения на графике, пересчитываем код АЦП в значение напряжения в вольтах. При выходе из цикла закрываем порт.
Так в интерфейсе нашей проги не будет никаких управляющих элементов кроме кнопки Стоп, а будет лишь отображение результата, мы поступим так: сначала создадим блок-диаграмму, а потом добавим недостающие элементы на лицевую панель. Хотя делать нужно наоборот! Но в данном случае так удобнее.

На панели блок-диаграммы помещаем из палитры Structures элемент While Loop, это наш бесконечный цикл. Обводим рамкой цикла область, достаточную для размещения внутри алгоритма. В правом нижнем углу есть красная точка, щелкнем по ней ПКМ и выберем Create Control. На лицевой панели у нас тут же появится кнопка Stop. При щелчке на ней наша прога завершится.


Теперь вне цикла мы должны разместить функции инициализации и закрытия порта. Слева инициализация, справа закрытие. Опять же щелкаем ПКМ и выбираем функции Configure Port, Read и Close. Эти функции находятся в палитре Instrument I/O —> Serial. Функцию чтения помещаем внутрь цикла. Соединяем с помощью катушки с проводами выходы и входы функций. Для функции Read мы должны задать количество байт, которая она будет принимать. Щелкаем ПКМ на среднем входе функции Read и выбираем Create->Constant, вводим значение, например 200. На данном этапе должно получится как на скрине.


Нужно создать контролы для функции инициализации порта. Нам вполне хватит двух — скорость порта и имя порта. Точно так же как мы создавали константу для функции чтения, создаем контролы. ПКМ на нужных входах функции инициализации и пункт

Нас интересуют два входа: Visa resourse name и Baud Rate (по умолчанию 9600). Таперь перейдем на лицевую панель и добавим необходимые компоненты, а именно экран отрисовки графика и метки для отображения кода АЦП и напряжения в вольтах.
Соответственно это элементы Waweform Chart c палитры Graph и два элемента Numeric Indicator с палитры Numeric.

Вернемся к блок-диаграмме и переместим появившиеся элементы внутрь цикла. Мы близимся к завершению! Единственное, нам нужно еще преобразовать строку символов, поступающих с выхода функции Read к формату, который переварят наши индикаторы. И еще реализовать простейшую математику по переводу кода АЦП в вольты. Ниже скрины лицевой панели и блок-диаграммы на данном этапе:



Для преобразования строки мы воспользуемся функцией Scan from string из палитры String. Помещаем ее внутрь цикла. Теперь математика. Для того чтобы преобразовать код АЦП в значение напряжения в вольтах нужно умножить код на величину опорного напряжения (в моем случае это пять вольт) и получившееся значение разделить на 1023 (так как АЦП имеет разрядность 10 бит). Необходимые функции умножения и деления, а также константы (5 и 1023) разместим в цикле. Скрины каждого соединения делать не буду, ибо и так картинок дофига. Приведу финальный скрин всех соединений. Там все предельно просто.


Я думаю все понятно, если будут вопросы спрашивайте в каментах. Вместе разберемся :-))) Тем временем прога готова.

Перейдем к нашему интерфейсу и немного настроим график. Выделим нижнее значение по оси Y и поставим 0. Выделем верхнее и поставим 5. Таким образом наша шкала по оси Y в диапазоне 0-5 вольт. Ну что, выбираем COM порт, вводим скорость обмена, запускаем по кнопке со стрелкой нашу прогу и яростно крутим резистор на плате, невозбранно наблюдая при этом на экране результат нашего труда. Щелкаем на кнопке Stop чтобы остановить прогу.


Как видите все достаточно просто. Данный пример это лишь мизерная часть всех возможностей LabView. Если кому поможет данная статья, буду рад. Только в коментах сильно не бейте я же не профи. Еще один маленький трюк. Если диаграмма стала похожа на Ктулху, можно попробовать воспользоваться кнопкой CleanUp Diagram. Она приведет диаграмму в более-менее божеский вид, но пользоваться надо осторожно. Вот результат ее работы


А еще можно куски объединять в функциональные блоки, чтобы они не загромождали схему.

Спасибо. Вы потрясающие! Всего за месяц мы собрали нужную сумму в 500000 на хоккейную коробку для детского дома Аистенок. Из которых 125000+ было от вас, читателей EasyElectronics. Были даже переводы на 25000+ и просто поток платежей на 251 рубль. Это невероятно круто. Сейчас идет заключение договора и подготовка к строительству!

А я встрял на три года, как минимум, ежемесячной пахоты над статьями :)))))))))))) Спасибо вам за такой мощный пинок.

198 thoughts on “Знакомимся с LabView”

Спасибо за статью!
Весьма интересная вещь, можно замутить удобную отладку через ком-порт с визуализацией, графиками. Просто про возможности LV слышал, а только сейчас начало доходить возможное реальное применение)

Автору Спасибо! Хорошая статья для начала.
Прочитал, и уже чтото да стало ясно.
Если я верно помню(не помню гто читал или говорили), то можно результаом делать в .EXE?

ТАм как то можно компилировать эти виртуальные приборы, что получается экзешник.

Это так, но для того чтобы перенести на другой комп нужно создавать не exe, а инсталлятор куда включен Run-Time Engine и другие используемые компоненты (если есть). Нужно поставить Run-Time Engine, а затем проинсталлировать прогу.

Разве? А у нас в виртуальной лаборатории оно работало экзешниками. Причем ничего предыварительно ставить не надо было.

Не не не, без Runtime engine на компе без LabView виртуальный прибор никогда не стартует. Видимо всетаки либо сама LabView, либо RT engine было там. Но более вероятно, что прога была написана не на LabView, а на LabWindows/ Там таки да, компилируется в exe, который можно запустить где угодно.

уточнил я сегодня у спецов по лабвью, для того чтобы екзешники делатьь, есть спец тулза от NI и стоит она около 10Куе. ну или закормить таблетками естно.

Возможно. Я не в курсе. Но, по моему проще поставить бесплатную RT Engine и дело в шляпе. Кроме того, есть такая вещь, как LabView Player, тоже вроде позволяет запускать программы на других компах, но я пока не пробовал. На днях постараюсь поэкспериментировать.

РАСШИФРОВКА ВИДЕОУРОКА ПО СОЗДАНИЮ ФАЙЛА .exe в Labview начиная с 55 секунды просмотра:
-проверить правильность работы программы;
-остановить работу программы;
File> Save As…> в появившемся окне уточнить (задать) имя файла с расширением .vi > OK > Project > New Project… > Add >
в появившемся окне выбрать Build Specifications > Правая Кнопка Мыши (ПКМ) > New -> Application (EXE) > в появившемся окне Save > OK > Source Files > выделить файл с расширением .vi => Previent > Build > Done > My Application > ПКМ > Explore > выделить Application.exe > Enter >
-убедиться, что программа по прежнему работает;
-остановить программу;
-закрыть программу кликом по красному кресту;
-закрыть окно из которого запустили Application.exe кликом по красному кресту;
-В окне Project Explore выделить > Build Specifications > ПКМ > New -> Installer >
выделить Source Files > перейдя в среднее окно выделить My Application => OK > My Installer > ПКМ > Build > Done > My Application ПКМ > Explore > Volume > Enter > Setup.exe > Next
НА ЭТОМ ВИДЕОУРОУК ЗАКАНЧИВАЕТСЯ.

Спасибо большое за статью! У меня вопрос,
1.Количество байт что задает ? .
2.Если мы задали 200 то только когда Функции чтения приймет 200 байт дале будет выполняеться функция Scan from string ?

Большое спасибо ) Буду ждать с нетерпением следующих статей .

1. Ну собственно и задает количество байт, которое будет прочитано из порта. Я просто для примера 200 поставил. Эту константу можно заменить на контрол, и выбирать необходимое количество байт с лицевой панели.
2. Все верно, считывается заданное количество байт, и передается в буфер. Там данные доступны для других функций.

Риспект за статью!
Уже давно назревало испытать лаб вью для похожих дел.
Хотя, весьма успешно до этого юзал visual basic 6. Но там красивые контролы-приборы надо рисовать самому, а тут все годово! Кул!

Ага. Писал диплом. Приём\обработка в пару строчек влезла, а вот отрисовка\визуализация — несколько десятков страниц. При этом так и не смог сделать человеческого вида развёртку как в осциллографе.

О госпади. Наконец-то статья о LabView)))))
Очень полезная штука+к ней материала полно на официальном сайте!

Интересно, конечно. Только одного не пойму: она создает какой нить exe-шник, чтобы можно было не в среде запускать, а отдельно, без Lab?

Да, конечно. Можно прямо из LabView создать инсталлятор. Для того чтобы запускать программы, созданные в LabView на машине где она не установлена, необходимо установить на этот компьютер среду NI Run-Time Engine. Ее можно скачать с сайте National Instruments.

Спасибо! Хорошая статья для начала.
я уже больше года не могу приступить к изучению, из-за нехватки времени, хоть и тянет периодически. А тут раз прочитал, и уже чтото да стало ясно.
Чувство что как будто 30% сам уже сделал :) шучу.

Я года 3 назад тож взялся, накупил книг, потом как то забросил. Сейчас плотно занялся изучением.

Круче только !а_н_дронный! коллайдер.

А я уже 6 лет активно использую LabWindows от NI, вот только 8 и выше версии сильно не понравились, так и сижу на 7-ой. Очень удобная штука, и не очень сложная.

В принципе, если знать C, то почему бы и нет. А можно ужнать что не понравилось в версиях выше 7?

Да уже точно и не помню, давно дело было. Сначала сидел на 5 версии, потом 5.5, семёрка была лучшая, а как только восьмая вышла — поставил, попробовал работать, и через недельку снёс. Возможно не понравилась монструозность разросшейся программы, а может и сильная нагрузка на слабенький процессор.

LabWindows/CVI — Full Development System with 1 Year SSP
Цена: 110291.53 руб.
Lite верстя 50 000, почти даром )))

Спасибо за статью, если бы еще кто-то набрался храбрости и выдал подобное про Matlab, особенно в связке с DSP :).

Я считаю, что подобные пакеты нужны не разработчикам, а ученым, у которых есть какой-то прибор для измерения определённых параметров, подрубаемый к ПК, у которого нет определённого удобного способа вывода информации. Разработчик же всегда движется к уменьшению себестоимости и надёжности, в чем дорогие и нагруженные сторонние пакеты не помошники. Человеку, который способен быстро и качественно написать прошивку для сложного устройства не составляет большого труда разобраться в нужной теме и так же быстро и качественно написать легкую, стабильную и удобную программу выполняющую нужную задачу.
Это было имхо. не призываю этому свято следовать.
ЗЫ: Мне кажется, что я заболел программированием для любой архитектуры, с использованием наименьшего числа сторонних библиотек. У такого подхода есть большие плюсы в виде легковесности, скорости и простоте программ.

Вы совершенно правы. Я как раз и интересуюсь лабораторными измерениями, и во время учебы даже делал для кафедры некоторые простые приборы, которые весьма облегчали жизнь ввиду отсутствия финансирования. Я далек от программирования под PC на стандартных языках, поэтому пробую использовать LabView.

Кто-нибудь пытался поставить Labview на Ubuntu? Точнее Visa…собственно Labview отлично ставится и работает, а вот в конфигурационных файлах Visa я уже з….лся копаться….Или есть другой способ работы с портами?

Теперь, когда мы окончательно освоили работу с генератором тактового сигнала и регистрами на Verilog+ПЛИС, пришло время сделать что-то более понятное широкому кругу лиц и приближенное к реальной жизни, чем просто мигающая лампочка. Сделаем сфетофор, который поочереди мигает 3мя лампочками. Но основная полезность светофора в качестве задания в данной лабораторной работе заключается в том, что его реализация представляет из себя простой и наглядный конечный автомат и в дальнейшем именно она ляжет в основу реализаций таких еще более понятных и полезных вещей, как микроэлектронные биороботы и подмножество настоящего процессора MIPS.

Конечный автомат (или машина состояний или стейт-машина - finit state machine) представляет из себя всего-навсего способ описания поведения системы в виде конечного набора состояний и событий, которые переводят систему из одного состояния в другое. Но чтобы долго не мусолить формальные определения, сразу попробуем описать светофор в виде конечного автомата.

Для этого в первую очередь все посмотрим на сам светофор:

и увидим, что он судя по всему может находиться всего в 3х состояниях: красный (red), желтый (yellow) и зеленый (green). Событием для перехода от одного состояния к другому будет истечение времени нахождения в текущем состоянии (для простоты будем считать, что в каждом из состояний сфетофор находится секунду).

Цепочка перехода: красный>желтый>зеленый>желтый>красный>же лтый>зеленый>желтый>.

Нарисуем все состояния на диаграмме в виде именованых кружочков, а события перехода попробуем обозначить подписанными стрелочками:

Как видим, переход из желтого состояния по событию "истекла 1 секунда" в данном случае не однозначен, т.к. исходя из одной только нарисованной машины состояний не очень ясно, куда в этот момент переходить - в красное или зеленое. Чтобы сделать правильный выбор, нужно знать в каком состоянии машина находилась перед этим - если она была красная, значит переходить нужно в зеленый, а если была зеленая, то нужно переходить в красный.

Для решения этого вопроса разобьем состояние желтый на две части - желтый1 (yellow1) и желтый2 (yello2) и перерисуем машину новым образом:

итого получили всего четыре состояния с циклическим переходом: красный>желтый1>зеленый>желтый2>красный> .

Проблема решена, неоднозначности исправлены, конечный автомат получен, приступаем к реализации.

Для начала немного поправим модуль clock_divider из предыдущего упражнения так, чтобы он не генерировал подряд секундные импульсы бесконечно, а по команде отсчитывал секунду и останавливался до новой команды.

reg [ delay_bit : 0 ] counter ;

always @ ( posedge clock , posedge reset )
begin
if ( reset )
counter 0 ;
else if ( ! counter [ delay_bit ] )
counter counter + 1 ;
end

assign finish = counter [ delay_bit ] ;
endmodule

Переходим к реализации конечного автомата в точном соответствии с нарисованной диаграммой - модуль traffic_light.

Для начала определим внешний интерфейс модуля - на входе нам нужен тактовый сигнал clock, который будет гонять светофор из одного состояния в другое, а на выход будем оптавлять значение текущего состояния out_state - т.к. у нас возможных состояний всего 4, для их кодирования как раз хватит ровно 2 бита:


Перечисляем константы с именами состояний (2 бита каждая - одно из этих значений всегда будет принимать выход out_state):

// enumerate state constants
parameter state_green = 2'b00 ;
parameter state_yellow1 = 2'b01 ;
parameter state_red = 2'b10 ;
parameter state_yellow2 = 2'b11 ;


И заводим для хранения значения текущего состояния автомата и следующего состояния автомата (так реализована логика перехода - см ниже) два внутренних регистра (тоже по два бита - они будут принимать значения описанных выше констант):

// one second timer controls
wire timer_one_second ;
reg timer_one_second_reset ;
timer one_second ( .clock ( clk ) , .reset ( timer_one_second_reset ) , .finish ( timer_one_second ) ) ;

И описываем логику перехода между состояниям машины - главная цель - получить значение для следующего состояния светофора и записать его в регистр next_state:

// detect next state depending on current state
// and current clock - change state one time per second:
// green>yellow1>red>yello2>green>.
always @ ( * )
begin
// start timer if it was reset
timer_one_second_reset = 0 ;
// next state would not change by default
next_state = state ;

case ( state )
state_green :
begin
if ( timer_one_second )
begin
// arm timer to count one second
// before moving to the next state
timer_one_second_reset = 1 ;
// move to the next state
next_state = state_yellow1 ;
end
end
state_yellow1 :
begin
if ( timer_one_second )
begin
// arm timer to count one second
// before moving to the next state
timer_one_second_reset = 1 ;
// move to the next state
next_state = state_red ;
end
end
state_red :
begin
if ( timer_one_second )
begin
// arm timer to count one second
// before moving to the next state
timer_one_second_reset = 1 ;
// move to the next state
next_state = state_yellow2 ;
end
end
state_yellow2 :
begin
if ( timer_one_second )
begin
// arm timer to count one second
// before moving to the next state
timer_one_second_reset = 1 ;
// move to the next state
next_state = state_green ;
end
end
endcase
end

Получился довольно увесистый блок кода, хотя большую часть там занимают копипаста и комментарии, но все равно разберем по частям:

Звездочка в списке чувствительности предлагает компилятору вставить в него все сигналы, которые могут каким-то образом повлиять на значения, вычисляемые внутри текущего блока always - это могут быть конечно сигналы, которые стоят в правой части операторов присвоения always @ ( state , timer_one_second )


Запускаем взведенный таймер, если он не был запущен (если на этот такт он был уже запущен или не взведен, то эта команда ничего не изменит):


По умолчанию next_state не меняется (по сути эта инструкция нужна здесь потому, что без нее компилятор без нее чувствует во всей конструкции always неопределенность и при компиляции показывает предупреждения - он хочет, чтобы все участвующие в ней переменные получали значения; на платах альтера с этой инструкцией автомат не переходит из состояния в состояние, следует разобраться ):


Далее конструкция case - фактически полный аналог такой же конструкции в С/С++ - внутри скобок проверяемое значение сигнала state, ниже варианты действий в зависимости от текущего значения сигнала state - возможнные значения приведены в формате 'значение:' (двоеточие) - в нашем случае для значений перечислены все константы состояний. После двоеточия и до следующего значения - блок действия.

case ( state )
state_green :
begin
if ( timer_one_second )
begin
// arm timer to count one second
// before moving to the next state
timer_one_second_reset = 1 ;

// move to the next state
next_state = state_yellow1 ;
end
end
// .
endcase

В блоке действия у нас опять стоит еще одна проверка значения сигнала timer_one_second - если он равен 0 (т.е. условие не выполнено), значит таймер не закончил отсчет или не запущен, ничего не делаем. Если timer_one_second равен 1 (условие выполнено), отдаем две команды:

Взводим таймер для нового отсчета секунды (сам отсчет в этот момент еще не пошел - для этого потребуется еще выполнить timer_one_second_reset = 0 ; )


Вычисляем следующее состояние, в которое должна перейти система - т.к. текущее состоянии системы в данном случае - зеленое (state_green - см значение case), следующим состоянием у нас будет желтый1 (state_yellow1 - небольшое несоответствие с картинкой - yellow1 и yellow2 в коде поменяли местами, но ничего страшного):

Остальные блоки внутри case полностью аналогичны, отличия только в значениях текущего и следующего состояний.

И финальный штрих - установить новое текущее состояние светофора (попытка будет происходить на каждый clock, те. 25 млн раз в секунду, но реально значение регистра state изменится только тогда, когда изменится значение next_state):

Теперь попробуем понять, что здесь вообще происходит. Система стартует в зеленом состоянии (state и next_state по нулям = state_green = 2'b00 ) с запущенным таймером (внутренний счетчик обнулен, внешний reset тоже 0). Таймер отсчитывает одну секунду, сигнал timer_one_second получает значение 1 и вызывает этим срабатывание 1го блока always @(*), т.к. '*' автоматически поместила timer_one_second в его список чувствительности. Далее внутри 1го блока always 'timer_one_second_reset = 0' не приводит ни к чему, т.к. reset пока что и так 0, 'next_state = state' аналогично - оба регистра до сих пор равны 0, т.е. указывают на зеленое состояние. Внутри case отрабатывает блок для условия 'state_green : ', внутри него также отрабатывает ' if ( timer_one_second ) ' (ради него сюда и пришли) - соответственно далее выполняются две команды - взводим (но пока не запускаем) новый таймер 'timer_one_second_reset = 1 ' и устанавливаем новое значение желтый1 в регистр next_state 'next_state = state_yellow1'. На этом текущая итерация 1го блока always завершается - в итоге next_state получил значение state_yellow1. Почти сразу после этого момента (на очередной такт clock - примерно через одну 25тимиллионную долю секунды) в очередной раз срабатывает второй блок always @(posedge clk), но на этот раз инструкция 'state next_state' не отрабатывает вхолостую, а записывает в регистр state новое значение state_yellow1 (оно же отправляется на выход модуля out_state) из регистра next_state, которое не равно его предыдущему значению state_green. Т.о. регистр state в этот момент меняет значение, а это значит, что первый блок always опять начинает отрабатывать уже по новому поводу, т.к. сигнал state тоже находится в его списке чувствительности. Первая инструкция 'timer_one_second_reset = 0' на этот раз спускает взведенный в прошлый раз таймер, и он начинает отсчитывать одну секунду, вторая инструкция 'next_state = state' опять ничего не меняет, внутри case сначала отрабатывает блок 'state_yellow1 : ', однако внутрь ' if ( timer_one_second ) ' он уже не попадает, т.к. в этот момент секунда еще не прошла и timer_one_second=0 - работа 1го блока always опять завершается. Далее через секунду, когда запущенный таймер отработал и установил значение сигнала timer_on_second=1 вместо нуля, опять отрабатывает 1й always - получили ситуацию, почти полностью аналогичную началу этого абзаца, только теперь текущие значения state и next_state равны state_yellow1 - далее все по аналогии и по циклу.

Замечание: последний важный нюанс, который еще не был рассмотрен - нужно обратить внимание, что в 1м блоке always @(*) для записи в регистры значений используется оператор =, а во 2м блоке always @(posedge clk) используется оператор /**
* Top module to test traffic light.
*/
module traffic_light_top (
input clk ,
output [ 0 : 2 ] ld
) ;

// enumerate state constants
parameter state_green = 2'b00 ;
parameter state_yellow1 = 2'b01 ;
parameter state_red = 2'b10 ;
parameter state_yellow2 = 2'b11 ;

// current state value
wire [ 1 : 0 ] state ;

// connect "clk" and "state" wires to traffic light logic implementation
traffic_light lights ( .clk ( clk ) , .out_state ( state ) ) ;

// display current state on output devices (lamps)
// for state_green switch on green lamp and switch off red and yellow,
// for state_yellow1 and state_yellow2 switch on yellow lamp and switch off green and red,
// for state_red switch on red lamp and swithc off green and yellow.
//
// All actions are performed at on and the same moment - order does not make
// any sense.

// "green" lamp
assign ld [ 0 ] = state == state_green ? 1 : 0 ;
// "yellow" lamp
assign ld [ 1 ] = ( state == state_yellow1 ) | ( state == state_yellow2 ) ? 1 : 0 ;
// "red" lamp
assign ld [ 2 ] = state == state_red ? 1 : 0 ;

Упражнение 3: самостоятельная работа - сделать робота, управляемого простым конечным автоматом

Группа разбивается на 3 команды, каждая из которых самостоятельно делает Робота Таракана, Робота Скорпиона и Робота Черепаху. Для каждого робота определяется логика его поведения и под нее рисуется новая схема конечного автомата с состояниями и переходами. Далее схема переносится в Verilog по полной аналогии со светофором, в качестве основы проекта берется код светофора. Параллельно идет распиновка сигналов модуля верхнего уровня по внешним интерфейсам (датчики/моторчики), а также сборка корпуса робота и подключение его проводами к выбранным портам ввода-вывода на плате.

Позже будут дополнительные подробности по устройству каждого из роботов отдельно, однако ничего нового в плане языковых конструкций или технологичных концептов по сравнению с сегодняшней лабой там уже не будет - только закрепление полученного опыта на практике с интересной задачей. Код Verilog роботов можно посмотреть уже сейчас - предварительный вариант Робота Скорпиона от меня, Робот Скорпион, Робот Черепаха и Робот Таракан от студентов, про запчасти для корпусов и результаты работы уже были подробности здесь. А пока на очереди процессор MIPS.

Я использую LabView для захвата некоторых долговременных данных, а затем обрабатываю их в MATLAB. Итак, я вручную экспортировал данные из Labview в excel. Но я обнаружил, что Labview не экспортирует более 1048575 данных, чтобы преуспеть, что в моем случае соответствует примерно 47 секундам. Для моей задачи мне нужно собрать данные не менее двух минут. В результате я не могу обработать сигнал ожидаемо.

Я предполагаю, что в моем Labview не хранится более 1048575 данных за раз. Я попытался увеличить разрешение ввода, но я не думаю, что это решение. Есть ли способ, я могу экспортировать все свои данные, чтобы преуспеть сразу? Спасибо.

Для больших наборов данных моя рекомендация состоит в том, чтобы сохранять образцы на диск по мере их приобретения, а LabVIEW устанавливает несколько примеров, чтобы продемонстрировать, как это сделать.

LabVIEW block diagram of example VI for writing data to a spreadsheet

Write Tab-Delimited File.vi Местоположение: [labview root]\examples\File IO\Spreadsheet\Tab-Delimited Data\Write Tab-Delimited File.vi

Ключевыми моментами для этого подхода являются:

Используйте VI файлы ввода-вывода для создания, открытия, записи и закрытия файла данных. Используйте Array To Spreadsheet String.vi для преобразования ваших данных выборки в десятичные строки

Вы также можете просто создать несколько файлов excel, увеличивая имя файла при достижении ограничения размера. Это позволяет сохранить другой контент excel (например, формулы, графики, макросы), но просто ограничьте набор данных, который вы передаете, чтобы преуспеть.

Другой вариант - запустить алгоритм сглаживания или усреднения данных в LabVIEW и передать меньше данных, чтобы преуспеть для отчетности. Например, если вы использовали 10-точечный фильтр усреднения, у вас будет 1/10 строк в Excel, если эти данные по-прежнему представляют собой результаты, достаточно близкие к вашим потребностям.

Excel не поддерживает более 1048576 строк в электронной таблице, поэтому вы не можете сохранить больше, чем это количество данных в файле электронной таблицы Excel ( .xls или .xlsx ).

Ответ Джо Фридрихсена - хорошее предложение: используя этот подход, вы должны иметь возможность загружать данные в MATLAB с помощью dlmread и указывать '\t' как разделитель.

В качестве альтернативы вы можете использовать LabVIEW Write To Measurement File express VI, но настройте его для записи в формате Text (LVM) . Затем вы должны иметь возможность загружать данные в MATLAB, используя этот код импорта файла LVM из MATLAB File Exchange.

Не так давно решил попробовать построить нечто подобное осцилоскопу на stm32, когда написание программы под контроллер подошло к концу, настало время выбрать на чем писать приложение для компьютера. Ведь необходимо какимто образом визуализировать полученные с контроллера данные. Выбор мой сразу пал в сторону LabView, этот мощный инструмент создания графических проложений при помощи графических элементов. Выбор я сделал т.к. уже давно хотел попробовать реализовать что либо на данном "языке", но подходящая задача все никак не подворачивалась.

При открытии LabView вам предложат создать новую программу (New Blank VI). Сделайте это.
Вы увидите два окна:


Первая из них Front Panel - лицевая (передняя) панель, на которой возможно создавать произвольный виртуальный прибор путем выбора разнообразных деталей из меню Control (появляется при нажатии правой клавиши манипулятора), среди которых большое разнообразие ручек настроек, переключателей, индикаторов, панелей
отображения графиков, а также элементов дизайна для улучшения внешнего вида виртуального прибора.

Вместе с лицевой панелью появляется функциональная панель Block Diagram – панель диаграммы, имеющая то же имя что и передняя панель. На этой панели
одновременно с элементами, располагаемыми на передней панели, появляются соответствующие им значки (терминалы). Это небольшие пиктограммы, представляющие собой разъемы для подсоединения к этим приборам других приборов или функций. Соединяя терминалы между собой в разрешенных комбинациях напрямую, либо через функциональные узлы, разработчик получает схему программы. Если соединения сделаны без ошибок, то программа готова к запуску на выполнение.

Запуск программы и работа с ней осуществляется обычно с передней панели, поскольку на ней обычно имеются средства имитации прибора с элементами управления и индикации.

В оба окна (панели) добавляються элементы при помощи окон, которые появляються по правому клику в свободной области:



Теперь давайте создадим простейшую программу.
Добавим в прибор регулятор, светодиод, и поле для отображения регулируемой величины.
Для этого в меню кликаем правой клавишей и элемент Knob:


Затем разместим "лампочку" led:



Обратите внимание, что при помещении каждого объекта во втором окне (окне блок-схемы), появляются соответствующие блоки.
Расположите их любым удобным для вас образом, я сделал вот так:


Теперь я предлагаю сформировать блок-схему нашего устройства.
Давайте сделаем так, чтобы при достижении определенного значения, загорался светодиод.
Для этого нам понадобиться блок сравнения:


Сформируйте вот такую схему:


Думаю любые пояснения здесь излишни. Понять и простить, как говориться.

Теперь смело жмите кнопку Run Continuously. При вращении ручки (Knob) вы видите текущее значение в поле Numeric. Также при достижении значения 5, загорается светодиод.

Читайте также: