Передача данных
Для тех, кто вообще не в курсе - сегодня мы будем заниматься передачей данных. Если говорить сугубо об информационных технологиях то тут существует бесчисленное множество способов передачи данных (Ethernet, Wi-fi, blue-tuth IPv4/IPv6 , FTP, http, https, ssl, usb перечислять можно долго). Каждый из таких способов называется протоколом. Говоря своими словами, протокол передачи данных - это, некоторое соглашение о том каким способом будут передаваться данные. Некоторые из них реализованы на высоком уровне некоторые на более низком, а некоторые вообще существуют как абстрактные понятия (Существует даже специальная модели стеков протоколов, в которых на определённых уровнях решаться конкретные задачи). Так вот UART это один из таких протоколов. На UART'те базируется ещё одни знаменитый протокол RS-232, интерфейсы RS-232 это COM порты. Обычно, передаваемой единицей информации, для определённого протокола, является пакет, пакет данных (или кадр, или batch). Который в свою очередь тоже жестко протоколирован. Вспомните что, когда мы говорим о передачи данных по сети (кстати это протокол IPv4 (Internet Protocol версии 4)), мы оперируем такими выражениями как " отправленные пакет”, ”потерянные пакетов". Пакет данных обычно состоит из головы, тела (той части, в которой и находятся передаваемые данные), и хвоста.
То есть, сначала по каналу передачи к получателю поступают служебные данные, информирующие его о сущности поступаемых данных, потом сами данные, потом хвост, уведомляющий получателя о благополучном завершении передачи пакета. К счастью к той модели UART'та которую мы будем реализовывать, применима политика минимализма. Голова составляет всего 1бит, данные 8бит (один байт), и хвост 1 или 2 байта.
UART Технические данные
Данные через UART передаются по двум линиям связи. Это TX (Transmitted) передающая линия и RX (Received) принимающая линия. Каждая из линий принимает по одному биту в равные промежутки времени. Существует ряд общепринятых скоростей передачи данных 300; 600; 1200; 2400; 4800; 9600; 19200; 38400; 57600; 115200; 230400; 460800; 921600. Эти величины имеют размерность bps (bit per second) количество передаваемых бит в секунду. Стоит заметить, что в число передаваемых бит в секунду входят также служебные биты. Допустим один байт, на скорости 9600, будет передаваться не 8/9600 секунд как хотелось бы, а 11/9600 учитывая биты начала пакета и конца. Исходя из того что некоторые модели UART не предусматривают способов синхронизации частот, то частоты передачи данных обменивающихся сторон должны быть изначально оговорены. Одной из наших задач будет синхронизация COM порт компа, и UART микроконтроллера на одной из вышеприведенных скоростей (хотя, принципе можно перенастроить UART на любую желаемую частоту). Модули UART обычно имею буферы памяти, нужные в том случае когда принимающие устройство не успевает обрабатывать поступающие данные.
Некоторое аспекты Desiner'а которое ещё небыли освещены
Маркировка
Иногда может показаться, что выбор расположения цифрового или аналогового блока дизайнер проводит случайным образом. Что бы понять, что происходит, стоит рассмотреть маркировку блоков в дизайнере более подробно. Каждый блок имеет имя состоящие из 3-х букв и 2-х цифр. Например - ASC12.
- Первая буква - обозначат принадлежность к аналоговой или цифровой подсистеме контроллера. A - для аналоговых, D - цифровых.
- Вторая буква – обозначает деление аналоговых или цифровых блоков на подгруппы. Для аналоговых блоков происходит деление на C (continious time block) и S (switch capacitor block). Постоянные и переменные блоки. В постоянных блоках реализуются такие вещи как компараторы, программируемые операционные усилители и.т.д. В переменных, такие как АЦП, ЦАП'ы. Для цифровых блоком, на B (basic block) и C (communication block). В бейсиках могут находиться Таймеры, широтно-импульсные модуляторы. В блоках передачи информации такие модули как UART, который мы будем рассматривать в дальнейшем.
- Третья буква - означает вид архитектуры реализации блока. Бывают буквы A,B,C,D. Но обсуждение этого выходит за рамки статьи.
- Две последние цифры - означают строку и столбец, в котором находиться блок.
То есть при выборе того или иного модуля микроконтроллера дизайнер подбирает за нас, подходящие для него расположение.
Если случилось, так что вам не понравилось расположение модуля по умолчанию. Вы всегда можете перенести блок кнопками:
Мультиплексоры
Мультиплексор, представляет из себя устройство задачей которого является перенаправление сигнала одного из входов (мультиплексоры имеют несколько входов и один выход) на выход. Исходя из установленного состояния прибора. На схемах он обычно обозначается трапецией. Наш случай не исключение.
Левым кликом по мультиплексору можно задать одно из возможных состояний.
Встретить мультиплексор (Multiplexer или Mux) можно и в даташитах, и пугается при этом не стоит. Он выполняет абсолютно такую же функцию.
Пример 3. Transmitted Data. (Часть 1. inception)
Предыстория: Напомню что, в предыдущем занятии мы добились того, что научили наш девайс получать входящий сигнал, переводить его в человеческий вид и выводить значение на экран. В этом занятии мы не будем создавать пример с нуля. А воспользуемся уже готовым примером из предыдущей главы.
Задачи: Послать и принять данные на ПК.
Дополнительное АО и ПО: Нам понадобиться кабель RS-232.
Ход работы.
Долго не думая, заходим в папу Digital Comm и выкидываем на схему UART. Модуль занимает два цифровых блока, один для RX принимающая линия, второй для TX, передающая линию. Выходы этих блоков были соединены с определёнными портами, специально отведенными для транспортировки данных. Port_2_7 для выхода, Port_1_6 для входа. Теперь для синхронизации СОМ порта ПК и нашего модуля UART надо определиться с частотой передачи данных. Допустим, мы выбрали частоту в 19200 bit per second. В даташитах было сказано, что модуль должен работать на частоте в 8-мь раз большей, чем скорость передачи данных. Вроде всё просто. У нас есть SysClk это та частота, которую генерирует наш IMO (internal main ocilator) и есть VC (variable clock) - благодаря которым мы можем делить число SysClk на некоторые степени двойки. Теперь решаем небольшую задачку по математике.
BitRate - 19 200
SysClk - 24 000 000
VC - ?
Необходимая нам частота должна быть в 8-мь раз больше, значит, прибор должен работать на 19 200 * 8
Составляем неравенство 24 000 000 / VC = 19 200 * 8. Выражаем VC = 24 000 000 / (19 200 * 8) = 156.25.
Остаток 0.25 не так важен, и на передачу данных не повлияет. Выставляем в глобальных ресурсах VC3 Divider - 156 и VC3 Source - SysClk/1. Подключаем наш UART на эту рабочую частоту.
Всего 3 строчки кода понадобиться нам для отправки данных, это UART_Start(UART_PARITY_NONE); для запуска модуля, UART_PutString(buf); для отправки и UART_PutChar('\n'); для вставки разделяющего символа. Для большего понимания приведу код прошивки.
#include // part specific constants and macros #include "PSoCAPI.h" // PSoC API definitions for all User Modules #include "stdlib.h" int iResult; double dResult; const double scaleFactor = 0.0012315996074583; char* buf; void main(void) { LCD_Start(); LCD_Position(0,0); LCD_PrCString("Measured Voltage"); UART_Start(UART_PARITY_NONE); PGA_Start(PGA_HIGHPOWER); //запуск PGA ADCINC12_Start(ADCINC12_HIGHPOWER); //запуск АЦП ADCINC12_GetSamples(0); //установка АЦП на бесперерывную работу M8C_EnableGInt ; // Uncomment this line to enable Global Interrupts while(1) // главный цикл прошивки { if (ADCINC12_fIsDataAvailable() != 0) //проверка на данных в ADC { iResult = ADCINC12_iGetData() +2048; ADCINC12_ClearFlag(); dResult = iResult * scaleFactor; LCD_Position(1,0); //установка позиции для вывода buf = ftoa(dResult,0); LCD_PrString(buf); UART_PutString(buf); UART_PutChar('\n'); } } }
Теперь надо проверить включён и работает ли на вашем компьютере com-порт. Для windows 7 -> правой кнопкой Мой Компьютер -> диспетчер устройств -> и мы должны видеть следующую картину.
Если этого не случилось com порт скорее всего отключен, и включить его следует в BIOS.
Выставляем настройки СОМ порта как показано на скриншоте.
Теперь надо прослушать ком порт и понять получаем мы какие-нибудь данные с микроконтроллера или нет. Для этого есть программы, называемые снифферами и терминалами. Мне, например, понравились Hyper Terminal и COM Port Toolkit. В статье я буду использовать 2е и приведу ниже архив для скачки. Next -> Next -> Next программа установлена. Запускаем прогу. Подключаем микроконтроллер к компу. Подаем питание. И если всё было сделано правильно, получим примерно следующий результат.
Не стоит беспокоиться о том, что данные, которые мы получаем, нам не понятны. Сейчас мы всего лишь убеждаемся в их наличии.
*Transmitted Data. (Часть 2. C#)
* - звёздочка перед началом заголовка означает что нижеприведенная информация отходит от темы микроконтроллеров, но несомненно является важной и интересной. Возможно, будут необходимы некоторые знания их других областей IT и если при чтении этих строк у вас возникают сложности, то можно просто скачать исходники в конце статьи
Теперь, когда мы убедились в том, что данные благополучно поступают на наш компьютер. Настало время в них разобраться и написать небольшой клиент для обработки поступающих данные. Клиент будет состоять из двух частей. Части обработки информации и графического интерфейса. Писать клиент будем на C#.
я работаю Visual Studio 2012 Express, у в других студиях интерфейс может отличаться, но принцип останется прежним
Запускаем любой Visual Studio с поддержкой C#. File -> New Project -> Visual C# -> Windows Forms Application. Сразу даём ему имя нашему проекту (у меня Client) и путь для создания. Сразу перед нами должен появится дизайнер окна и панель инструментов Toolbox (Если Toolbox'а не видно, то его нужно добавить через меню View). Из него вытягиваем на форму два Label'а и одни TextBox. Форматируем их так, что бы получилось примерно следующие окно.
Теперь понадобиться создать класс для коммуникации. В закладке Project меню Add Class. Затем даёте имя файлу (у меня Com) и студия автоматически создаст за вас каркас класса.
Выглядит это примерно так:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Client { class Com { } }
теперь в класс нужно добавить, поля данных.
private string buffer; //буфер private string value; //форматированные данные для отображения private TextBox textBox;//элемент для вывода на экран private SerialPort port = new SerialPort("COM1", 19200, Parity.None, 8, StopBits.One); //ну и естественно сам порт
на некоторые из полей студия начнёт ругаться, а именно на TextBox и SerialPort. А произойдёт это по тому, что к файлу не подключены нужные пространства имён. Для этого в самом верху файла нам надо подключить два пространства имён:
using System.IO.Ports; using System.Windows.Forms;
Конструктор с параметром, в который будет выводиться информация.
public Com(TextBox textBox) { this.textBox = textBox; }
Создаём функцию для обработки полученных данных, она будет вызываться каждый раз кода, поступают какие либо данные на ком порт.
private void received(object sender, SerialDataReceivedEventArgs e) { buffer += port.ReadExisting(); if (buffer.Contains('\n')) { value = buffer.Split('\n')[0]; buffer = buffer.Remove(0, value.Length + 1); if (textBox.InvokeRequired) textBox.Invoke((MethodInvoker) delegate { textBox.Text = value; }); else textBox.Text = value; } }
Некоторые строчки этой функции могут казаться не понятными, и досконально рассматривать мы их не будем. Скажу только что прототип функции заранее оговорен и должен принимать следующий вид private void received(object sender, SerialDataReceivedEventArgs e) (за исключением названий переменных и функции разумеется). А строка textBox.Invoke((MethodInvoker) delegate { textBox.Text = value; }); просто записывает данные в наш текст бокс в потокобезопастной манере.
Осталась пара мелочей. Функция, которая запускает поток на просушку порта.
public void Strart() { port.DataReceived += new SerialDataReceivedEventHandler(received); port.Open(); }
Строчка port.DataReceived += new SerialDataReceivedEventHandler(received); подписывает, описанную нами ранние функцию, на событие поступления данных.
Полный вид файла для взаимодействия с ком портом имеет следующий вид.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.IO.Ports; using System.Windows.Forms; namespace Client { class Com { private string buffer; //буфер private string value; //форматированные данные для отображения private TextBox textBox;//элемент для вывода на экран private SerialPort port = new SerialPort("COM1", 19200, Parity.None, 8, StopBits.One); //ну и естественно сам порт public Com(TextBox textBox) { this.textBox = textBox; } private void received(object sender, SerialDataReceivedEventArgs e) { buffer += port.ReadExisting(); if (buffer.Contains('\n')) { value = buffer.Split('\n')[0]; buffer = buffer.Remove(0, value.Length + 1); if (textBox.InvokeRequired) textBox.Invoke((MethodInvoker) delegate { textBox.Text = value; }); else textBox.Text = value; } } public void Strart() { port.DataReceived += new SerialDataReceivedEventHandler(received); port.Open(); } public void Stop() { port.Close(); } } }
Последний штрих это в конструкторе класса нашей формы создать объект класса Com и передать ему указатель на TextBox.
private Com com; public Form1() { InitializeComponent(); com = new Com(textBox1); com.Strart(); }
Теперь подключаем микроконтроллер к компу, запускаем клиент, запускаем контроллер и надеемся, что бы всё заработало. ВНИМАНИЕ если вы не собирали программу самостоятельно (client.exe) то для её нормального функционирования вам понадобиться установленной на ПК netframework 4.5.
Результат работы на видео
PSoC. Глава 0. Введение. Первый пример
Прикрепленные файлы:
- COM Port Toolkit.zip (1443 Кб)
- UART.ZIP (409 Кб)
- Client.zip (177 Кб)
Комментарии (0) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация