Четверг, 25.04.2024, 03:43
RC - Мастерская
Главная | Каталог статей | Регистрация | Вход
Меню
Статистика
Главная » Статьи » Обмен опытом » Arduino для школьников

6. Цифровые сигналы в теории и на практике. Последовательный порт.
Цифровые сигналы в теории и на практике. Последовательный порт.

 

В общем случае словосочетание "цифровой сигнал" сейчас не слышал только глухой. А вот понимание сути этого названия есть далеко не у каждого. Я попробую объяснить, что же все это значит...
Как говорилось ранее, цифровая техника называется "цифровой" потому, что оперирует только двумя состояниями: напряжение есть и напряжения нет. Их еще обозначают цифрами 1 и 0. Отсюда и название.

Давайте теперь рассмотрим нашу схему с кнопкой и светодиодом. Кнопку нажали - светодиод загорелся, отпустили - погас. При нажатой кнопке на выход МК подается "1", в отпущенном состоянии "0". Построив график зависимости изменения напряжения на светодиоде от времени получим приблизительно такую картину:

 

 

Здесь время t– это ни что иное, как удержание кнопки в нажатом состоянии. А график изображает «прямоугольный импульс». Не трудно догадаться, что называется он так из-за своей характерной формы.
Электрический импульс - это всплеск напряжения или тока в определённом и конечном промежутке времени.

Импульс всегда имеет начало (передний фронт) и конец (спад). В нашем случае они соответствуют моментам нажатия и отпускания кнопки. На самом деле, цифровой импульс имеет трапециевидную форму из-за того, что напряжение не может нарастать и спадать мгновенно. Но в ряде случаев время изменения уровня на столько мало по сравнению с временем t, что им пренебрегают. Так пока поступим и мы.
Если нажать на кнопку несколько раз, то на графике будет несколько таких импульсов. Допустим, эти импульсы будут иметь одинаковое время t и будут следовать через равные интервалы времени.


 

Для описания такой последовательности нам понадобится ввести еще одну характеристику Т – период импульсов.
Период импульсов - это промежуток времени, между двумя характерными точками двух соседних импульсов.
Обычно период измеряют между фронтами соседних импульсов. Так же часто вместо периода используют другую характеристику – частоту (F).
Частота следования импульсов - это количество полных импульсов в единицу времени. За единицу времени принято брать одну секунду. Единицей измерения частоты является герц, по имени немецкого физика Генриха Герца. Один герц - это регистрация одного полного импульса за одну секунду.
Частота и период неразрывно связаны между собой. И связь эта описывается простой формулой:
F = 1 / T

Есть еще несколько полезных и часто употребляемых определений:

  • Если длина импульса t точно равна половине периода T, то такой сигнал часто называют "меандр".
  • Скважностью импульсов называется отношение периода следования импульсов к их длительности и обозначается буквой S:
S=T/t

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

  • Коэффициент заполнения D является величиной, обратной скважности. Коэффициент заполнения обычно выражается в процентах и вычисляется по формуле:
D=1/S
Практически сразу после открытия электричества люди задумались над вопросом передачи информации при помощи него на расстояния. Одним из первых изобретений в этом направлении стал телеграф. Суть его в том, что буквы алфавита кодируются при помощи азбуки Морзе в последовательности коротких и длинных импульсов и передаются по проводам. Формирование импульсов осуществлялось вручную – оператор нажимал на ключ(кнопку). На другой стороне так же вручную происходило декодирование – другой оператор, глядя на вспышки лампочки, записывал последовательности и преобразовывал их в символы. Собственно, наше устройство как раз и представляет собой простейший макет первого телеграфа. А сам телеграф – аналог современного последовательного порта передачи данных.
Современный последовательный асинхронный порт передачи данных (UART) работает приблизительно следующим образом:
Связь осуществляется по двум проводам – по одному для каждого направления передачи. На каждой стороне есть приемник (Rx) и передатчик (Tx). Провода соединяют соответственно Tx стороны А с Rx стороны B и Rxстороны А с Txстороны B. Каждый передатчик связывается со своим приемником. Рассмотрим передачу данных со стороны А на сторону В. Обратное направление будет работать идентично этому.
Для начала надо вспомнить, что порт асинхронный. Это значит, что обе стороны не синхронизированы друг с другом. Принимающая сторона ничего не знает о частоте, с которой будут передаваться данные, и в какой момент эта передача начата. Не зная отправной точки (начало отсчета) невозможно правильно разделить данные на биты и составить из них правильные байты. Значит надо синхронизировать обе стороны. Для этого вначале передатчик выдает на линию несколько байт синхронизации вида 01010101 или 10101010. Принимая их, приемник настраивается на частоту импульсов передатчика. После такой синхронизации частоты передатчик начинает последовательно загонять в линию биты из буфера. А приемник в свою очередь с ранее полученной частотой считывает с линии значения.
Это простейший алгоритм асинхронной последовательной передачи данных. На практике все несколько сложнее, но сейчас нам это не особо важно. Все дело в том, что в нашейArduinoпредусмотрен аппаратный последовательный порт. Если быть точным, то это часть микроконтроллера. В ArduinoUno/Mini/Nanoон один, а в ArduinoMegaтаких портов аж 4.
Рассматривая Arduino Uno (Nano/Mini) соответствующие выводы мы найдем под номерами D0(Rx) и D1(Tx). Но при их использовании надо учитывать, что для загрузки программы в микроконтроллер наша плата Arduinoкак раз и использует последовательный порт. Поэтому при прошивке микроконтроллера требуется отключать все периферийные устройства от этих выводов.
Использовать последовательный порт на Arduinoочень просто. Для этого в языке предусмотрен специальный класс Serial. Этот класс обладает следующими методами:
  • begin(speed) – открываетпоследовательный порт и устанавливает скорость передачи данных. Обычно используются стандартизированные скорости (9600, 14400, 19200, 28800, 38400, 57600 или 115200), но можно указать и любую другую. Важно, чтобы порт на обоих сторонах был открыт с одинаковой скоростью.
  • available() – функция возвращает количество байт, принятых микроконтроллером в специальный буфер и доступных для считывания в программу. Буфер может хранить до 64 байт.
  • read() – считывает один байт из буфера последовательного соединения. При этом считанный байт из буфера уходит. Байты из буфера считываются в той последовательности, в которой они поступили в порт.
  • write(val) – записывает один (или несколько) байт в последовательный порт.
  • print(val) – записывает в порт последовательность байтов в виде строки. Так же есть функция println(val). Она отличается от данной тем, что в конце строки передает байт указания перехода на новую строку.

Вернемся к тому, что наш микроконтроллер фактически подключается к компьютеру через последовательный порт. Это соединение мы пока использовали только для загрузки прошивки. Однако, такой подход достаточно расточителен. Мы можем это соединение использовать для любого обмена данными между компьютером и микроконтроллером. В ArduinoIDEв меню сервис есть пункт «Монитор порта». При его вызове откроется такое окошко:

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


int led = 13;
int button = 2;

void setup() {             
  Serial.begin(9600); 
  pinMode(led, OUTPUT);    
  pinMode(button, INPUT);
}

intval;

void loop() {
  val = digitalRead(button);
  digitalWrite(led, !val);
  Serial.print(val);
}
Загрузим этот скетч в микроконтроллер и откроем монитор порта. Там мы увидим убегающую вправо строку из нулей и единиц. Как не сложно догадаться, каждый символ этой строки показывает состояние кнопки в момент считывания микроконтроллером. Данные есть – это хорошо, но микроконтроллер работает достаточно быстро и следить за этими данными тяжело. Давайте еще немного модифицируем нашу программу:
. . . .
intval;
intold_val=0;

void loop() {
  val = digitalRead(button);
  if (old_val!=val){
    digitalWrite(led, !val);
    Serial.print(val);
    old_val = val;
  }

}
А значит это следующее… Оператор ifиспользуется для проверки каких-либо условий. Если условие верно (истина), то выполняется следующий оператор. Если условие ложно, то следующий оператор пропускается. На этот случай есть так же дополнительное ключевое слово else. Когда условие ложно, будет выполнен оператор следующий за этим словом. Таким образом мы имеем возможность выполнять один из двух операторов в зависимости от условия. Так же стоит посмотреть тут и тут.
В нашей программе я добавил переменную old_val для хранения предыдущего состояния кнопки. В операторе ifя сравниваю только что полученное значение с предыдущим. И если они не равны, то выполняется следующий оператор. А если быть точным, блок операторов, заключенный в операторные скобки. Там я устанавливаю новое состояние светодиода. Потом записываю это же состояние кнопки в порт. В конце я присваиваю переменной old_val новое состояние кнопки. Теперь данные в окошке будут появляться только при каком-либо действии с кнопкой.
Как говорилось выше, для передачи в порт информации из нашей платы Arduino есть три функции – write, print и println. Разберем разницу между ними. Функцию print мы только что использовали. Она вывела нам значения valв одну строку. Давайте теперь заменим ее на println. В результате при каждом вызове к передаче будет добавляться байт перехода на новую строку и нули с единицами в окошке будут отображаться уже в столбик.
А вот если вместо функции print поставить функцию write результат окажется на первый взгляд странным – окошко останется пустым. На самом деле все закономерно. Если функция print передает 0 и 1 как символы, то функция write передает их как байты в «сыром» виде. А все дело в кодовой таблице… Дело в том, что каждый символ, который мы видим на экране, кодируется определенным числовым значением. Все эти значения собраны в этой самой кодовой таблице ASCII:

Как легко можно убедиться, нулю соответствует значение 48, а единице – 49. Значения байтов 0 и 1 соответствуют не отображаемым символам. Поэтому и экран остался пустым.
Если в своей программе Вы напишете Serial.print(86), то в мониторе Вы и увидите 86. Если же написать Serial.write(86), то в мониторе появится буква «V».
 

Категория: Arduino для школьников | Добавил: Mactep (10.01.2014)
Просмотров: 3791 | Рейтинг: 0.0/0
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск