Что то зацепил меня UART, да и давненько у нас не было си шарпа, поэтому решил сделать еще один примерчик. Суть — микроконтроллер измеряет и передает данные по юарту, а компьютер рисует графики, такой себе псевдоосциллограф.
Итак, если вы следили за предыдущими статьями, то с легкостью сможете создать форму в Visual C#, прицепить к ней кнопочки, вывести текст. В идеале вы в состоянии поймать байтик из юарта и вывести полученный текст на форму.
Если вы не знакомы с предыдущими статьями, то основные моменты: если вы хотите сделать что то, то это действие должно быть привязано некому другому действию. Например, хотим чтобы изменился текст надписи, значит изменение текста нужно привязать к щелчку по кнопке, поэтому именно в обработке щелчка по кнопке следует писать свой код. Хотите вывести полученный по UART байт на форму — поместите компонент serialPort на форму, ведь именно он отвечает за ком порт и при событии DataReceived (получение данных) изменяйте надпись.
Не забываем! Чтобы вывести текст — принимаете байты в массив, выводите в надпись. Передать переменную состоящую из нескольких байт за один раз нельзя — передаете по байтно, собираете в массив — выводите. Чтобы узнать что начали передаваться данные — используйте спецсимволы, означающие начало и конец передачи — не путать со старт и стоп битами!
Все это круто, кнопки на форме рисовать умеем, текст писать и выводить переменные умеем, теперь неплохо бы еще научиться рисовать. Для этого заюзаем GDI+, он вполне сгодится. Чтобы его использовать в WindowsForm существует класс Graphics из пространства имен System.Drawing. Он позволяет рисовать изображения, многоугольники, дуги, линии, заливки областей, в общем то что нужно.
Главным образом нас интересует как рисовать прямые линии, с остальным, при желании, можно разобраться самостоятельно. Создаем проект WindowsForm. Придадим более культурный вид, например залить форму цветом WhiteSmoke, поместить кнопку и соответственно создать обработчик ее нажатия. В обработчике создадим переменную graphics, выберем цвет карандаша и нарисуем линию. Для наглядности, я привел полный исходник который должен
у вас получиться.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace plot { public partial class Form1 : Form { public Form1(){InitializeComponent();} private void button1_Click(object sender, EventArgs e) { Graphics gr = CreateGraphics(); //создаем переменную класса graphics Pen penc = new Pen(Color.Black); //выбираем цвет карандаша,которым будем рисовать gr.DrawLine(penc, 0, 0, 100, 200); //рисуем линию начальная точка x1=0 y1=0 } //конечная точка x2=100 y2=200 } } |
Теперь при нажатии кнопки на экране будет рисоваться линия. Небольшая особенность — начало координат это верхний левый угол. Думаю принцип понятен, подобным же образом рисуются остальные примитивы.
Вернемся к изначальной задаче. Допустим микроконтроллер измеряет с некой периодичностью и шлет нам байты по последовательному порту. Кидаем на форму компонент serialPort1, задаем скорость и номер порта(!), с которого будем считывать информацию. Для теста я взял два виртуальных порта 4 и 5, т.е. через com4 терминалом передаются байты, а com5 читается программой. В событиях serialPort1 ищем обработчик DataReceived — туда пишем код, который рисует линии. С каждым приходящим байтом наш график будет дорисовывать линию к предыдущей, со смещением 5(переменная х2).
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { Graphics gr = CreateGraphics(); //создаем переменную Pen penc = new Pen(Color.Black); //задаем цвет карандаша y2 = serialPort1.ReadChar(); //читаем полученный байт x2+=5; //следующая точка по координате х будет на 5 больше if (x2 > 300) //если мы достигли края формы, то очищаем форму и { //обнуляем переменные gr.Clear(Color.WhiteSmoke); x2 = 0; y2 = 0; x1 = 0; y1 = 0; } gr.DrawLine(penc, x1, y1, x2, y2); //рисуем линию по координатам x1 = x2; //запоминаем конец линии y1 = y2; } |
Не забываем, что перед использованием порт нужно открыть, а перед закрытием программы — закрыть. Теперь мы можем послать пару байтов, например при помощи терминала. Вроде работает.
Ну и на закуску — измеряем АЦП микроконтроллера, кидаем в юарт, смотрим на ПК. Только я внесем небольшое изменение в программу, чтобы график рисовался не от верхнего левого угла, а относительно центра. Для этого, нужно из половины высоты формы вычитать наш результат. И кнопку можно в принципе убрать с формы. В качестве схемы крутилка потенциометра. Прошивка микроконтроллера в комментариях думаю не нуждается — все есть в 8 и 10 уроках.
Протестировано — работает, такая вот приставка-осциллограф к компьютеру, всего на одном микроконтроллере и преобразователе usb-uart.
Проект Visual C#
Проект Atmel studio
Вопросы по прошивкам на форум, по статье в комменты.
подскажите, а какую макс частоту сигнала можно измерять таким осциллографом?
я не тестировал, но тут частота будет ограничена скоростью передачи юарта.
т.е. если скорость UARТ 9600 бит/с, а АЦП в МК стоит 8-битный, то UART должен успевать передавать эти 8 бит, соответствующие амплитуде измеряемого сигнала в данный момент времени, т.е. 9600/8=1200 Гц, а на практике только 600 Гц успеет реально отослаться по UART. правильно ли я размышляю?
Там ограничение еще будет и за счет частоты выборок самого АЦП. Она у мег, кажись, не выше 15 тыс. выборок в сек.
в идеале — внешний ацп и передача по usb
В правильных осциллографах конкретно выборки делает очень быстрый АЦП, а логика(обычно на ПЛИС) принимает значения и записывает их во внешнюю быструю оперативную память в обход МК… После чего МК может медленно эту память прочитать, обработать, и медленно отослать на компьютер.
Осциллографу важно быстро кусочек сигнала записать, которого будет достаточно для отрисовки картинки, обновлять которую очень часто вовсе не нужно, ибо сигнал все равно обычно повторяется и к нему по срабатыванию триггера можно будет вернутся в любой момент. 😉
Проект в статье скорее концептуальный, примерный, и если кому нужна скорость- думаю он вполне сумеет напрячь моск и улучшить алгоритм. Кстати иногда напрягать моск очень полезно, говорят. 😀
Артур, спасибо за статью. Давно замышлял замутить нечто подобное для смартфона. Начну с компа.
добрый день! интересная статья но может вы знаете как прикрепить контроллер атмега к юсб без фт232 чтобы из него считать аналоговый сигнал, с цифровыми разобрался а аналоговый не могу понять, или как байт с контроллера передать тоже не могу понять !!! может у вас есть какие примеры на С ++!
СПАСИБО!!!!
гуглите V-USB, статьи еще пока нет, хотя она в ближайших планах
гуглил,просто невсьо понятно!!! спасибо!!!будем ждать!
За статью спасибо
У меня такой вопрос … Есть контроллер Atmega 8 в нём мы скажем измеряем температуру по уровню АЦП .. илиже просто меряем АЦП на двух портах .. как можно реализовать вывод этих данных в С#, кажем на label1 и label2. Я примерно разобрался как зажигать светодиоды как запрашивать данные с МК .. но проблема в том что оно всё какбы в одной переменной. И как можно реализовать опрос .. зажжен ли светодиод или нет.
http://avr-start.ru/?p=2230
Доброго дня! А есть возможность по окончании каждого сеанса построения графика сохранять его в jpg или в другом формате?
Конечно, если допишите Если серьезно, то это пример-заготовка, а не готовое решение.
Проверил. Работает. Спасибо.
Посоветуйте хорошую информацию по написанию портативного осциллографа на СИ, может книги какие или журналы, с основ желательно
По аналоговой части лучше почитать хоровиц хила. Информацию о том как работает ацп, лучше гуглить. Си тут собственно не причем.
Это круто, только как подключать к компьютеру все это дело?
через переходник usb/uart
Спасибо за статью! Подскажите, а как по оси х задать время?
В идеале вы в состоянии поймать байтик из юарта и вывести полученный текст на форму.
Вот с этим могут быть у новичков проблемы, не было же такого урока.
Хотите вывести полученный по UART байт на форму — поместите компонент serialPort на форму, ведь именно он отвечает за ком порт и при событии DataReceived (получение данных) изменяйте надпись.
Не все так просто, ведь событие DataReceived генерируется в дополнительном потоке. Хотелось бы урок и на эту тему)
я не планировал развивать идею C#, ибо уроков на эту тему в интернете дофига и очень хорошо объяснено. тут просто показан пример того, как это могло бы быть
Добрый день! Будет ли такое работать с ATSAM4E16C? От чего он у вас питается и что значит «В качестве схемы крутилка потенциометра» ?
вы можете использовать потенциометр, для проверки работы ацп. один конец на vcc, другой на gnd, со средней точки снимаете напряжение. при повороте потенциометра, значения должны меняться