Что то зацепил меня 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
    }
}

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

draw_line1

Вернемся к изначальной задаче. Допустим микроконтроллер измеряет с некой периодичностью и шлет нам байты по последовательному порту. Кидаем на форму компонент 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;
}

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

draw_line2

Ну и на закуску — измеряем АЦП микроконтроллера, кидаем в юарт, смотрим на ПК. Только я внесем небольшое изменение в программу, чтобы график рисовался не от верхнего левого угла, а относительно центра. Для этого, нужно из половины высоты формы вычитать наш результат. И кнопку можно в принципе убрать с формы. В качестве схемы крутилка потенциометра. Прошивка микроконтроллера в комментариях думаю не нуждается — все есть в 8 и 10 уроках.

draw_sch

Протестировано — работает, такая вот приставка-осциллограф к компьютеру, всего на одном микроконтроллере и преобразователе usb-uart.

draw_real

Проект Visual C#

Проект Atmel studio

Вопросы по прошивкам на форум, по статье в комменты.

24 комментария: Простой UART Осциллограф.

  • подскажите, а какую макс частоту сигнала можно измерять таким осциллографом?

  • я не тестировал, но тут частота будет ограничена скоростью передачи юарта.

  • т.е. если скорость UARТ 9600 бит/с, а АЦП в МК стоит 8-битный, то UART должен успевать передавать эти 8 бит, соответствующие амплитуде измеряемого сигнала в данный момент времени, т.е. 9600/8=1200 Гц, а на практике только 600 Гц успеет реально отослаться по UART. правильно ли я размышляю?

  • Там ограничение еще будет и за счет частоты выборок самого АЦП. Она у мег, кажись, не выше 15 тыс. выборок в сек.

  • в идеале — внешний ацп и передача по usb

  • В правильных осциллографах конкретно выборки делает очень быстрый АЦП, а логика(обычно на ПЛИС) принимает значения и записывает их во внешнюю быструю оперативную память в обход МК… После чего МК может медленно эту память прочитать, обработать, и медленно отослать на компьютер.
    Осциллографу важно быстро кусочек сигнала записать, которого будет достаточно для отрисовки картинки, обновлять которую очень часто вовсе не нужно, ибо сигнал все равно обычно повторяется и к нему по срабатыванию триггера можно будет вернутся в любой момент. 😉

    Проект в статье скорее концептуальный, примерный, и если кому нужна скорость- думаю он вполне сумеет напрячь моск и улучшить алгоритм. Кстати иногда напрягать моск очень полезно, говорят. 😀

  • Артур, спасибо за статью. Давно замышлял замутить нечто подобное для смартфона. Начну с компа.

  • добрый день! интересная статья но может вы знаете как прикрепить контроллер атмега к юсб без фт232 чтобы из него считать аналоговый сигнал, с цифровыми разобрался а аналоговый не могу понять, или как байт с контроллера передать тоже не могу понять !!! может у вас есть какие примеры на С ++!

    СПАСИБО!!!!

  • гуглите V-USB, статьи еще пока нет, хотя она в ближайших планах

  • гуглил,просто невсьо понятно!!! спасибо!!!будем ждать!

  • За статью спасибо
    У меня такой вопрос … Есть контроллер Atmega 8 в нём мы скажем измеряем температуру по уровню АЦП .. илиже просто меряем АЦП на двух портах .. как можно реализовать вывод этих данных в С#, кажем на label1 и label2. Я примерно разобрался как зажигать светодиоды как запрашивать данные с МК .. но проблема в том что оно всё какбы в одной переменной. И как можно реализовать опрос .. зажжен ли светодиод или нет.

  • Доброго дня! А есть возможность по окончании каждого сеанса построения графика сохранять его в jpg или в другом формате?

  • Конечно, если допишите :mrgreen: Если серьезно, то это пример-заготовка, а не готовое решение.

  • Проверил. Работает. Спасибо.

  • Посоветуйте хорошую информацию по написанию портативного осциллографа на СИ, может книги какие или журналы, с основ желательно

  • По аналоговой части лучше почитать хоровиц хила. Информацию о том как работает ацп, лучше гуглить. Си тут собственно не причем.

  • Это круто, только как подключать к компьютеру все это дело?

  • через переходник usb/uart

  • Спасибо за статью! Подскажите, а как по оси х задать время?

  • В идеале вы в состоянии поймать байтик из юарта и вывести полученный текст на форму.
    Вот с этим могут быть у новичков проблемы, не было же такого урока.
    Хотите вывести полученный по UART байт на форму — поместите компонент serialPort на форму, ведь именно он отвечает за ком порт и при событии DataReceived (получение данных) изменяйте надпись.
    Не все так просто, ведь событие DataReceived генерируется в дополнительном потоке. Хотелось бы урок и на эту тему)

  • я не планировал развивать идею C#, ибо уроков на эту тему в интернете дофига и очень хорошо объяснено. тут просто показан пример того, как это могло бы быть

  • Добрый день! Будет ли такое работать с ATSAM4E16C? От чего он у вас питается и что значит «В качестве схемы крутилка потенциометра» ?

  • вы можете использовать потенциометр, для проверки работы ацп. один конец на vcc, другой на gnd, со средней точки снимаете напряжение. при повороте потенциометра, значения должны меняться

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика