Связь микроконтроллера с компьютером через usb

ARCAdaptor

Многие профессионалы-разработчики электроники часто «воротят нос» от семейства микроконтроллеров производства Atmel — фи, мол, эта ваша Атмега — только лампочками поморгать. Однако, это спорное утверждение.

Дешевизна, легкость программирования (как физической «заливки» прошивки, так и создания самих программ) превращают микроконтроллеры семейства AVR в универсальный инструмент, доступный начинающему радиолюбителю, а богатейшая линейка устройств — от самых простых ATTiny до устройств Mega256 с огромным количеством периферии «на борту» позволят реализовать самый смелый и амбициозный проект.

В этот раз мы рассмотрим конкретные примеры реализации одноплатных (и не очень) конструкторов на базе микроконтроллеров семейства ATMega. Все они вполне реализуемы в домашних условиях, а некоторые можно приобрести на сайте авторов. Для начала — небольшое отступление про «одноплатники» вообще.

Название говорит само за себя — все компоненты компьютера, необходимые для его базового функционирования размещены на одной плате. Совсем юные читатели сразу подумают о новинках вроде Raspberry Pi, а те, кто уже имеют понятие о мироустройстве — вспомнят РК-86, ZX-Spectrum и БК-0010, например.

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

И вот 21 век сдвинул «окно ностальгии» в нужную позицию и радиолюбители по всему миру не сговариваясь выпустили несколько проектов, которые по характеристиками ну очень напоминают те самые «эр-кашки» и «спектрумы» конца восьмидесятых годов прошлого века. А некоторые — в точности повторяют, но обо всём по порядку.

Схема программатора

Теперь о схеме программатора.
Первоначальная схема программатора не предусматривала поддержки USB и содержала 2 разъёма COM9.

Один разъём служит для подключения JDM программатора и подключив к нему компьютер можно программировать микроконтроллеры с помощью программ IS-Prog , PonyProg или других программ, в которых реализована поддержка JDM программатора.

Второй разъём предназначен для работы со специально разработанным протоколом обмена. С его помощью можно программировать микроконтроллеры Microchip или микросхемы памяти типа 24Cxxx.

Для подключения USB переходника добавлен третий разъём COM9 ( на плате расположен посередине ). От этого разъёма использовано всего 3 контакта. RXD, TXD и общий(масса). Выводы от разъёма подключены напрямую к соответствующим выводам микроконтроллера программатора.

Схема программатора

Первоначально плата программатора не содержала разъёма под переходник USB — на фотографии видно, что этот разъём стоит посередине.

Плата программатора

Рис. 6 Плата программатора

Программное обеспечение программатора пока не доработано полностью. Испытан программатор только с микроконтроллерами PIC16F628A и PIC16F84.

Прошивка и программирование Blue Pill

Подключаем плату к ST-Link и запускаем «STM32 ST-LINK Utility»:

Жмем «Connect to the target» и если в графе Device чип определился правильно, значит все Оk, чип живой и готов к работе. Хотя, это конечно следовало проверить ДО того как браться за паяльник 😉

Попробуем прошить Blink через ST-Link из Arduino. Для этого запустим Arduino с установленным паком Arduino_STM32. В меню выбора платы щелкнем по Generic-STM32F103C series

Из примеров загрузим вариант Blink’а для STM32:

В тексте скетча исправим номер пина PB1 на PC13, т.е. на пин с зеленым светодиодом.

В меню выбора программатора выберем ST-Link:

После чего пробуем прошить:

В итоге имеем вес прошивки в 13 КБайт, и успешный лог выполнения. К конце прошивка немного подвисает, на этапе «waiting for tty device», т.е. в ожидании последовательного порта, как будто бы прошивка происходила через USB-загрузчик, но в целом, все ОК.

USB — COM переходник на микроконтроллере Attiny2313

Питание микроконтроллера Attiny2313 осуществляется непосредственно от шины питания USB. Вся схема собрана на односторонней плате (SMD и ТН варианты). Устройство поддерживает только сигналы Rx и Tx.

Прошивку к переходнику, рисунок печатной платы (SMD и TH), а также программу терминал для проверки адаптера можно скачать по ниже приведенной ссылке:

При программировании Attiny2313, фьюзы необходимо выставить следующим образом:

Для работы устройства необходимо установить драйвер виртуального COM порта. Для этого скачиваем его:

Скачать драйвер (1,1 MiB, скачано: 3 558)

Теперь вставляем в USB порт компьютера наш адаптер, компьютер должен выдать сообщение «Найдено новое устройство», а затем предложит установить для него драйвер. Выбираем пункт «Установить с указанного места» и нажимаем на кнопку «Далее». Затем в новом окне выбираем путь к папке скаченного и распакованного драйвера и опять жмем кнопку «Далее». Спустя несколько секунд драйвер будет установлен и устройство будет готово к работе.

Для проверки работоспособности устройства, временно замыкаем Rx и Tx выводы и с программы терминала, так же находящегося в архиве, выставляем номер COM порта и отправляем любое сообщение. Для этого пишем например «Привет» и нажимаем кнопку «Send». Если переходник рабочий, то написанное сообщение появится в верхнем окне программы.

Программное обеспечение и заметки

Подключив COM или LPT программатор к микроконтроллеру нужно не забыть подать питание на сам микрочип. В качестве источника питания микроконтроллера можно использовать батарейки или блок питания со стабилизатором, это будет наиболее безопасно как для порта компьютера, так и для чипа. О том как использовать источники питания для AVR микроконтроллера мы уже рассматривали.

Под Linux есть очень мощная программа которая умеет работать с USB ASP, COM и LPT программаторами — это программа AVRDUDE, о ней будет идти речь в следующих разделах.

Для прошивки AVR чипов под Windows с использованием данных COM и LPT программаторов нужна программа UniРrof от Николаева, которая представляет собою универсальный программатор для AVR (avr.nikolaew.org).

ВНИМАНИЕ! Будьте предельно внимательны и осторожны при сборке и использовании программаторов с использованием COM или LPT порта компьютера, простой ошибкой можно запросто подпалить эти порты. Для нормальной работы таких программаторов нужно стараться использовать по возможности максимально короткие проводники от разъема к схеме программатора и микроконтроллеру. Микропроцессор компьютера желательно чтобы имел частоту не более 1-2 ГГц, а в качестве ОС для программирования чипов желательно использовать Win2000 или WinXP.

Также важно знать что переходники USB-RS232 (USB-COM Port) скорее всего не будут работать с программатором Громова, заработают возможно только те у которых стоят более новые микросхемы, так что лучше искать машину с родным COM-портом.

Общие сведения

Программатор USBAsp распространяется и открытым исходным кодом, так что при желании можно изготовить самому, скачав печатную плату и прошивку с сайта Thomas, из-за этого в различных интернет магазинах существует различные варианты программатора с одинаковым функционалом. В моем случае буду рассказывать о USBAsp V2.0 китайского производителя LC Technelogy.

Обзор программатора USBAsp v.2.0

Программатор собран на синий печатной плате, слева расположен USB-разъем необходимый для подключения к компьютеру. В центре располагается контроллер ATmega8A, рядом установлен кварцевый резонатор на 12 МГц и электрическая обвязка (резисторы, конденсаторы). Справа расположен 10-контактный разъем (два ряда, по пять выводов, шагом 2.54 мм), обеспечивающий обмен данными с прошиваемым микроконтроллером (интерфейс ISP). В комплекте поставляется кабель, с каждой стороны которого, установлен разъем IDC (10 выводов), для простоты прошивки некоторых плат (например Arduino), советую приобрести адаптер-переходник с 10-pin на 6-pin. Назначение выводов программатора USBAsp можно посмотреть на рисунке ниже, вид на стороне программатора.

Обзор программатора USBAsp v.2.0

Назначение выводов:
► 1 – MOSI
► 2 – VCC
► 3, 8, 10 – GND
► 4 – TXD
► 5 – RESET
► 6 – RXD
► 7 – SCK
► 9 – MISO

Световая индикация
► Красный светодиод G — Включен
► Красный светодиод R — Обмен данными

Перемычки
► JP1 — POWER, управляет напряжением на разъеме ISP VCC (вывод 2), можно установить на + 3.3В, + 5В или вовсе убрать перемычку, если программируемое устройство, имеет собственный источник питания.
► JP2 — SERVICE, обновления прошивки USBasp.
► JP3 — SLOW, программирования на низких скоростях, если программируемое устройство, работает на частоте ниже 1.5 МГц, SCK (вывод 7) уменьшит частоту с 375 кГц до 8 кГц.

Принципиальная схема программатора USBAsp V2.0 можно посмотреть на рисунке ниже.

Принципиальная схема программатора USBAsp v.2.0

Список поддерживаемых AVR микроконтроллеров:
► Mega Series:
ATmega8, ATmega8A, ATmega48, ATmega48A, ATmega48P, ATmega48PA, ATmega88, ATmega88A, ATmega88P, ATmega88PA, ATmega168, ATmega168A, ATmega168P, ATmega168PA, ATmega328, ATmega328P, ATmega103, ATmega128, ATmega128P, ATmega1280, ATmega1281, ATmega16, ATmega16A, ATmega161, ATmega162, ATmega163, ATmega164, ATmega164A, ATmega164P, ATmega164PA, ATmega169, ATmega169A, ATmega169P, ATmega169PA, ATmega2560, ATmega2561, ATmega32, ATmega32A, ATmega324, ATmega324A, ATmega324P, ATmega324PA, ATmega329, ATmega329A, ATmega329P, ATmega329PA, ATmega3290, ATmega3290A, ATmega3290P, ATmega64, ATmega64A, ATmega640, ATmega644, ATmega644A, ATmega644P, ATmega644PA, ATmega649, ATmega649A, ATmega649P, ATmega6490, ATmega6490A, ATmega6490P, ATmega8515, ATmega8535,
Tiny Series: ATtiny12, ATtiny13, ATtiny13A, ATtiny15, ATtiny25, ATtiny26, ATtiny45, ATtiny85, ATtiny2313, ATtiny2313A
Classic Series: AT90S1200, AT90S2313, AT90S2333, AT90S2343, AT90S4414, AT90S4433, AT90S4434, AT90S8515, AT90S8535
► Can Series: AT90CAN128
PWN Series: AT90PWM2, AT90PWM3

Avrdudeprog

Avrdudeprog – утилита от русского программиста, являющаяся удобной оболочкой для avrdudue. Скачать AVRDUDE_PROG можно с официального сайта (прямая ссылка на загрузку, на всякий случай зеркало на моём ЯД и FTP этого сайта). В рамках этого урока, программа умеет следующее:

  • Чтение/запись/очистка flash памяти
  • Чтение/запись/очистка eeprom памяти
  • Полная очистка чипа
  • Калькулятор фьюзов и локбитов (чтение/запись)

Более подробный обзор на avrdudeprog можно посмотреть здесь . Давайте посмотрим на калькулятор фьюзов. Выбираем свой микроконтроллер и программатор (можно добавить другие модели микроконтроллеров и программаторов, читай тут). Переходим во вкладку Fuses, нажимаем прочитать. При успешном чтении увидим текущий набор настроек своего чипа. Можно их поменять и загрузить. Важно! Галку инверсные биты не трогаем! Лок-биты и отключение RST заблокирует микроконтроллер, не трогайте их, если такой цели нет! Можно загружать прошивку или загрузчик из .hex файла, указав путь к ней на первой вкладке в окне Flash. Очень удобная утилита для низкоуровневой работы с МК.

Автор публикации

Здорово, понравилось. Очень ценю ваш фундаментальный подход!

Спасибо за добрые слова.

Спасибо за уроки, просто и понято.

а если Arduino с ком портом по uart «общаться» — какой переходник нужен? RS485 => RS232?

Если на компьютере стандартный COM порт с уровнями +10/-10 , то нужен преобразователь уровней RS232. Например микросхема MAX232, SP232, ADM232. Через один урок я напишу об этом. RS485 здесь непричем.

Эдуард, возможно ли сделать в будущем пару уроков по программе верхнего уровня? Хотя бы самый минимальный уровень.

Здравствуйте!
Это сложная, объемная, совершенно другая тема. Может быть когда-нибудь инфопродукт сделаю. Подумаю, но в ближайшее время вряд ли.

Здравствуйте, большое спасибо за уроки. Очень интересная тема по программам для компа верхнего уровня. Не могли бы Вы для начала выложить исходник программы UART_Arduino_PC.exe? Кому интересно, тот сам разберется что там к чему. Спасибо.

Здравствуйте!
У меня есть планы сделать инфопродукт по разработке программ верхнего уровня. Но когда до этого дойдут руки — не знаю. Сейчас очень занят.

А пока исходник выложите

Эдуард. а насколько сложно подключить к СКАДА системе Trace Mode ?

Наверное, все возможно. Я с системой СКАДА не работал. Разбираться надо.

Обратите внимание на проект «Мажордомо», если интересует система «Умный дом» своими руками. Активное сообщество, целая куча наработок и т.д. и т.п.

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

Здравствуйте!
Тайм-аут это нечто другое. В примере урока команда от компьютера состоит из 3 байтов. Представьте, что от компьютера на контроллер было передано 2 байта команды, а третий не пришел. Контроллер будет бесконечно ожидать 3го байта команды. Система приема данных зависнет.
Чтобы такого не произошло, контроллер отсчитывает время между приходом байтов команды. Если оно превысило время тайм-аута, то команда считается ошибочной и прерывается.

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

Здравствуйте!
Спасибо за добрые слова.
Программы верхнего уровня я пишу в среде Borland C++ Builder.
Сложно ли это, не знаю. Все на свете и сложно и просто. Информации, конечно, надо знать много.

Антон, погугли среду разработки Small Basic, с её помощью очень несложно, даже проще ардуины, мне кажется.

Что лучше использовать
MsTimer2::start(),MsTimer2::stop() или interrupts,noInterrupts?

Здравствуйте!
Только первый вариант. noInterrupts запрещает все прерывания, в том числе и системные.

Добрый день. Эдуард подскажите. А если есть необходимость подключить два модуля к NANO. Можно ли как-то использовать другие пины в качестве Rx Tx?

Здравствуйте!
В принципе можно, но UART будет программный и параллельной задачей обмен не реализовать. Для локальной сети лучше использовать аппаратный UART.

Что означает в коде:
* ((byte *)(& sum))
?

Здравствуйте!
* ((byte *)(& sum))
Об этом написано в уроке 15.
С помощью указателей формируется младший байт от переменой sum типа int.
& sum — получается адрес переменной sum
(byte *)(& sum) — адрес преобразуется в адрес переменной типа byte
* ((byte *)(& sum)) считывается значение по этому адресу.

Добрый день, Эдуард!
Можете ли Вы поделиться исходным кодом программы для компьютера к этому уроку, exe-файл которой Вы выложили?
Заранее спасибо!
Виктор.

Здравствуйте!
Это совершенно другая, сложная тема. Я подумываю написать инфопродукт об этом, но сейчас не хватает времени.

Доброго времени суток!
Спасибо за скорый ответ.
Уроки к Ардуино отличные!
Буду с нетерпением ждать продолжения, желательно к delphi!
С уважением ,
Виктор

День добрый. Урок прекрасный, но возникла сложность. Внутри обработчика прерывания по таймеру «не работает» чтение данных c UART. Т.е. данных в буфере нет (Serial.available не возвращает положительного результата). В сети пишут, что это из-за того, что получение данных Serial само реализуется через прерывания «и вообще не нужно ничего по UART в обработчике слать». Но у вас, судя по всему, всё работает. Подскажите, пожалуйста, что может быть не так?

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

Тогда я, видимо, не совсем поняла урок. «Естественно модуль управления обменом по сети расположен в обработчике прерывания по таймеру. Вот его скетч». И в полном варианте программы по ссылке вроде бы тоже весь обмен по UART реализован именно в обработчике прерывания timerInterrupt()

Здравствуйте!
Может я неправильно выразился. Я имел ввиду, что в обработчике прерывания нельзя ждать завершения каких-либо процессов класса Serial. Можно только проанализировать состояние и выйти из обработчика.

Эдуард, здравствуйте. У Вас потрясающие уроки!
Дабы получше усвоить материал, пытаюсь написать свою модификацию протокола и программу верхнего уровня (параллельно учу Python). Но возникла проблема: ардуино Мега 2560 возвращает всегда нулевое значение светодиода, независимо, горит он или нет. Чтобы исключить возможные ошибки логики убрал из скетча все лишнее, оставил только кнопку и один светодиод. Ситуация не изменилась, в логе одно и тоже нулевое значение, при этом светодиод отрабатывает идеально.
Ссылка на файлы проекта: https://www.dropbox.com/sh/xoxraiatujf1xfv/AAA3nHeTgRpGe-cpUDlg6ISda?dl=0

В процессе написания комментария родилась мысль писать в буфер не состояние кнопки, как в Вашем уроке, а состояние светодиода. И все заработало. Но очевидны недостатки. Хочется читать сенсор/датчик, а не промежуточную переменную.

Здравствуйте!
Спасибо за оценку уроков.
Вопроса я не понял. С одной стороны вы пишите «ардуино Мега 2560 возвращает всегда нулевое значение светодиода, независимо, горит он или нет». С другой — «писать в буфер не состояние кнопки, как в Вашем уроке, а состояние светодиода. И все заработало».
Если сомневаетесь, то проверьте работу светодиода в цикле loop. Занесите в него 0, считайте и передайте через последовательный порт. Затем тоже самое с 1.

Да, наверно действительно несколько непонятно написал. Проблема в том, что по какой то причине, конструкция
////////////////////////
noInterrupts();
if (button1.flagPress == true) dataSerialBuf[0] = 1;
else dataSerialBuf[0] = 0;
interrupts();
////////////////////////
не пишет в буфер состояние кнопки, простейшая программа верхнего уровня показывает в порту нули, независимо, жму я на кнопку или нет.
При замене проверки состояния кнопки на проверку состояния светодиода, которым рулит кнопка, программа верхнего уровня начинает показывать и единицы. Но первоначальной задачей было все же отслеживать состояние кнопки

Не понятно. Все должно работать. А простая программа в цикле loop() работает?
Зачем вы прерывания запрещаете? Прерывания надо запрещать если проверяете тип данных длиной более одного байта. Часть данных может измениться в прерывании. Получится половина данных новая, половина старая.

Хотелось бы посмотреть исходник программы для компьютера

Здравствуйте…..у меня почему_то пояснение в виде каких то иероглифов , как их сделать читаемыми? подскажите пожалуйста…….

Здравствуйте! Это ваш браузер так выводит.

Нажмите на ссылку. Откроется окно с иероглифами. Правой кнопкой мыши, выбрать сохранить как. Будет сохранено в исходном виде.

Вы делаете в основном цикле «погрузку» данных в массив с предварительной отменой прерываний и последующим их возобновлением.
А если операцию погрузки в массив делать в самом прерывании, непосредственно перед отправкой, на что это повлияет?

Здравствуйте!
Смысл в том, чтобы развязать операции формирования данных массива и отправки. Вы просто кладете данные в массив, а параллельный процесс эти данные по запросу отсылает на компьютер. Основная программа не знает, что существует параллельный процесс. Он может отослать данные в любой момент. Для того, чтобы не было отослано половина старых, а половина новых данных и запрещается прерывания.

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

Еще такая проблема — я похожую связку сделал между Attiny45 и ESP8266 NodeMCU, и ESP у меня при обрыве связи начинает бесконечно перезагружаться в том случае, если я очистку буфера вашим способом делаю. Без очистки всё идеально, можно обрывать и восстанавливать связь, ничего не зависнет. С чем может быть такое связано? C особенностями ESP?

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

Всё, нашел причину)

Дело всё-таки в ESP. Ваш способ очистки буфера /* while (true) < if (mySerial.read() == 0xffff) break;>*/ на ней работать не хочет, зато сработал вот такой:

Хотя на других платах Ваша очистка отлично отрабатывает

здраствуйте! у меня такая проблема==>
‘timerInterrupt’ was not declared in this scope

почему такая ошибка не понял

Здравствуйте!
Прежде всего проверьте, что у вас в пути к файлам Ардуино нет папок с именами на кириллице.

добрый день! решил эту проблемуб но у меня вопрос есть.я хочу передавать инвормайию с ардуино на другой микроконтролер по uart ,как сообщение должно быть длиной 10 символов(10 байт) если оно отправляется с ардуино платы на другой и 13 символов если оно принимается ардуино платой с другой.
Первый символ всегда 0x1. Он означает начало сообщения.
Второй символ указывает на тип сообщения, 0x20 для сообщения отправляемого ардуино на другой плату, и 0x21 для сообщения отправляемого 2.платой на ардуино.
Следующие 8 символов содержат в себе любые данные которые нужно передать. в моцй задаче это измерения двух датчиков.вот я не очень знаю как протокол написать по этому поводу.я иностранный студент в Москве и это задача часть моей дипломной работы и мне надо ваш помощь.есть другой человек он пишет коды для 2. микроконтролер, моя задача коду ардуино.ни понятие веши вот протокол как писат и понимат,ваш урок похож видимо решить мою задачу.вы можете помогать?

А вы не хотите использовать библиотеку протокола ModBus из последующих уроков? Ей очень удобно работать, обмен делается очень просто.

если бы я использоыал датчик DHT11 ,то я должен использовать команды (0xBE),(0x44, 1),(0xСС, 1)
.
или все это команды для DS18B20?

Здравствуйте!
Конечно. В схеме установлен датчик DS18B20, значит и протокол для него.

значить все это команды использовать ,но только библиотеку менять на?

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

ок спасибо болшое!

Урок 58. Обмен данными между платами Ардуино через UART по протоколу ModBus. Библиотека Tiny_ModBusRTU_Master.
Урок 61. Аппаратная реализация интерфейса RS-485. Объединение плат Ардуино в локальную сеть RS-485.

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

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

* (float *)(dataSerialBuf+4) = voltage;

Что в ней означает каждый символ, по такому примеру:
temperature= (float)((int)bufSensTmp[0] | (((int)bufSensTmp[1])

переменной «temperature» типа float (занимает в памяти микроконтроллера 4 байта) присвоить значение типа float, полученное путём побитового «ИЛИ» двух байтов типа int, с предварительным побитовым сдвигом второго байта влево на 8 бит, взятых из «0» и «1» ячеек буфера bufSensTmp[] соответственно. И затем умноженное на число 0.0625 для того-то, и просуммировано с числом 0.03125 для того-то.

dataSerialBuf — это имя массива, а значит указатель на него.
+ 4 — смещение указателя на нужные нам данные.
(float *) — явное преобразование указателя на указатель данных типа float.
* — запись данного по указателю типа float, т.е. запись данного типа float.
Урок 15 посвящен указателям.

Спасибо за столь скорый ответ.
Поправьте пожалуйста, если я допустил неточность. Очень-очень надо. Скопировать кусок чужого кода в свой проект легко, но мне непременно надо разобраться, как самому написать этот кусок кода. Поэтому такая дотошность.
В программе объявлена глобальная переменная типа «массив» с именем dataSerialBuf[], которая имеет 10 ячеек по 1 байту и расположена в памяти контроллера по адресу, назначенному (компилятором?). Пусть это будут ячейки с адресом от 15600 (для первого байта) и до 15600+9 для последнего (всего 10). Верно? Когда из программы есть обращение к имени массива — это равносильно что напрямую называть адрес первой ячейки, т.е. 15600, в которой лежит первый байт массива, а именно dataSerialBuf[0]. Использование указателей позволяет не заморачиваться с ТОЧНЫМ расположением в памяти микроконтроллера переменных, достаточно назвать её имя. И указатель, как стрелочник, добросовестно направит к адресу с первым байтом. Если это переменная типа int, то она имеет два байта и для неё компилятором зарезервировано два байта в памяти. Если float, то четыре. Здесь я лично для себя прибег к методу ассоциаций и представил переменную типа float, как четыре вагона поезда. В каждый вагон мы можем положить 8 бит(записать), и в каждом вагоне можем посмотреть что там лежит (прочитать). Таким образом, переменную dataSerialBuf[] можно представить в виде 10-ти вагонов. Нумерация вагонов начинается с нуля. С «0» по «3» (четыре вагона-байта) это для переменной temperature типа float, с «4» по «7» (ещё четыре вагона-байта) для переменной voltage типа float, один вагон (№8) для того, чтоб передать состояние светодиода всего одним битом из восьми, один вагон (№9) зарезервирован и полезного груза пока не несет.
Тогда запись вида: * (float *)(dataSerialBuf+4) = voltage; можно интерпретировать как, в вагон №4 состава dataSerialBuf[] положить переменную voltage, которая имеет тип float, а потому займет 4 вагона с №№ 4-7.
Сильно не пинайте за очевидные для Вас вещи. Я, как и многие, учусь по урокам на сайте. За сайт и возможность поучиться у более сильного программиста, выражаю Вам отдельную благодарность.

Да, все правильно. Добавить нечего.
Если вы реализовываете практическую задачу, то будет проще сделать это с помощью библиотек, поддерживающих протокол ModBus. Этому посвящены несколько последующих уроков, и в разделе Умный дом практически реализовывается обмен по ModBus.

Спасибо.
Да собственно MODBUS это и есть моя цель. Точнее MODBUS RTU на RS-485. Так что здесь для меня просто кладезь информации. Потом мне надо ещё построить мост MODBUS_RTU — Mosquitto.

Или может здесь применена какая-то разрешенная в С форма записи вроде такой: sum ^= 0xa1e3; тоже самое что и sum = sum ^ 0xa1e3;

Здравствуйте
Подскажите пожалуйста, что означает конструкция
while (true) < if (Serial.read() == 0xffff) break;>?
и что вообще означает понятие «сброс порта»?

Здравствуйте!
В буфере порта могли остаться несчитанные данные. Эта конструкция очищает буфер. Считывает данные, пока не встретится код 0xffff, что означает, что буфер пуст.

Здравствуйте, еще можно вопрос?
Формула для контрольной суммы (сумма байтов 0 … 9 ^ 0xa1e3) как-то зависит от количества байт? Другими словами, если будет 5 байт или 15 байт — формула изменится (ну кроме количества слагаемых)?

При данном способе не зависит. Это просто сумма с переполнением.

Эдуард, подскажите, пожалуйста такой момент. Контрольная сумма объявлена как unsigned int sum. А если слагаемые могут быть отрицательными (по логике передаваемых данных) — нужно ли объявить контрольную сумму как знаковую (int)? Или логика передаваемых данных не влияет на подсчет контрольной суммы?

Здравствуйте!
Объявляйте сумму, как беззнаковую переменную. Хотя при суммировании не важно, как объявлены слагаемые и переменная суммирования. Результат будет одним и тем же. Используются знаковые или беззнаковые переменные повлияет только при интерпретации результата — сравнение больше меньше и т.п.
Правильнее слагаемые явно преобразовать в беззнаковые byte.

Эдуард, всю голову сломал. Подскажите пожалуйста — при каком значении n программа попадет вот сюда:
else // не все байты приняты, проверка тайм-аута
if (timeOutCount > TIME_OUT) Вообще — при каких обстоятельствах она туда может попасть?

Обычно такие конструкции отрабатывают тайм-ауты, т.е. зависание обмена по непредсказуемым причинам. Например, программа ждет 5 байтов, а пришло только 3. Провод оборвался не вовремя или помеха на линию связи. Без отработки такой ситуации программа зависнет навечно.

Большое спасибо за ответы

Эдуард, подскажите пожалуйста — что за беда. Если программа уже загружена в МК и там благополучно работает, то при подключении к порту любым терминалом, в том числе стандартным монитором порта Arduino IDE, МК перегружается! Т.е. картина выглядит так: программа работает, чего-то там делает, открываем монитор порта — МК перегружается! Плата Arduino UNO. Это так надо или у меня лыжи не едут?!

Здравствуйте!
Да, при запуске монитора последовательного порта микроконтроллер перезапускется. Вырабатывается аппаратный сброс с помощью сигнала DTR (можете почитать об этом в уроке 46).
Мне кажется это очень удобно. Программа перезапускается и данные порта монитор не пропускает.

Т.е это штатный режим?! Вот это засада… Т.е. работает себе программа, работает, тут внешняя программ решила подключиться чтобы считать данные. Подключилась… а тут Reset. Я прочитал что можно это обойти путем соединения пинов reset и 5 В через резистор 120 Ом или конденсатора (не помню на какие пины). Но как-то страшно, не сгорит ли…
А у нано — такая-же засада?

Почему внешняя программа. Сброс формируется только монитором последовательного порта. Если программа не трогает DTR, то сброса не будет.
Используйте другой монитор. Мне нравится CoolTerm. В уроке 3 уроках STM32 есть ссылка.

Не только монитором порта. Подключаюсь например программкой Terminal v 1.9 — тоже самое: как только жму кнопочку «Соединиться с портом» — МК перезагружается. Подозреваю что так же будет со всеми терминалами.
А у нано такая же засада, не знаете?

Здравствуйте!
В Nano будет тоже самое. В PRO Mini если сигнал DTR не подключать такого эффекта не будет.
Нужен терминал, который не использует DTR сигнал. Попробуйте CoolTerm. Я не помню, если там есть такая возможность, то установите DTR в неактивное состояние.

Эдуард, здравствуйте
Такая ситуация. Пакет данных, который я пытаюсь передать от МК на ПК достаточно большой. Если я не ошибаюсь буфер ограничен 64 байтами? Ну даже не в этом дело, если пакет большой, как его «искусственно» разделить на несколько пакетов? По другому сформулирую — если бы в вашем примере dataSerialBuf был размером 200 байт — то нужно было бы как-то разделять его передачу?

Здравствуйте!
Решайте сами. Никто вам не мешает передавать пакеты любой длины. Все ограничено ресурсами микроконтроллера.
При больших объемах пакетов ошибка передачи «выбивает» сразу много данных. Так что, длина пакетов еще зависит от помехозащищенности сети. Если вероятность ошибки велика, то лучше разбивать пакеты на небольшие порции.

Подскажите пожалуйста — а как разбить пакеты? Вот есть у меня 100 байт которые нужно передать. Я решаю что логично было бы их разбить на 60 и 40 (по логике передаваемых данных). Предположим это массивы buf1 и buf2
for (i=0; i Serial.write(buf1[i]);
for (i=0; i Serial.write(buf2[i]);
Что нужно сделать между этими двумя циклами чтобы данные ушли двумя разными пакетами и принимающая сторона приняла их как 2 разных пакета?

Здравствуйте!
Добавьте в начале посылки признак пакета. Я уже не помню, как там сделано. Если есть код операции, то можно в него бит добавить.

Добрый день. Как всё таки вычисляется 0xa1e3? И нужно ли его менять если увеличить количество передаваемых байт с ваших 10 до, скажем 20?
Если можно, дайте пожалуйста, подробный и развернутый ответ, с примерами, для совсем чайников вроде меня.
Из всего урока, только этот момент не понятен (

Здравствуйте!
Нужно пакет данных сопроводить контрольным кодом, чтобы определить на приемной стороне, что данные не исказились.
Как его вычислить. ? Лучший вариант использовать циклические коды, но они сложно вычисляются. Поэтому я просто суммировал байты и сумму передал в качестве контрольного кода.
Если все передаваемые байты будут равны 0 (а это ситуация возможная при аппаратных ошибках), то их сумма тоже будет равна 0, и данные восприняты, как правильные. Поэтому я добавил операцию исключающего или. Я выбрал код a1e3, но ничего не мешает использовать другой.

#define TIME_OUT 6 // время таймаута приема команды (мс)

Если прием байтов растянулся на время более 6 мс, то определяется ошибка приема команды.» — а почему именно 6мс? Если мне потребуется передавать 4 байта данных (температура, влажность, ток нагрузки, «авария/норма»)?

Здравствуйте!
Это время не длительности пакета, а отсутствия данных. Ошибка формируется, если прием пакета начался, а очередного данного нет более 6 мс, т.е. нарушена целостность пакета.

Помогите. Очень нужна помощь спецов. Есть игра-авиасимулятор, есть контроллер ARCC к которому подключены кнопки, и программа, в которой можно назначить на эти кнопки разные функции авиасимулятора. И дальше в процессе игры эта программа связывает контроллер с симулятором. Но эта программа заточена только под контроллер ARCC. А надо подружить программу с ардуинкой — написать что то типа модуля, поддерживающего интерфейс программы. Исходники программы есть. Там же есть примеры, как это сделано для контроллера ARCC.

Меня интересовал исходник программы верхнего уровня, работа с СОМ портом, разбор посылки с контроллера, а не exe-файл!

Здравствуйте!
Но это уроки программирования микроконтроллера, а не компьютера. Планы были написать уроки по программам верхнего уровня, но времени не хватает.

Может исходник на почту бросите, я хоть и мало но заплатил, а тут облом.

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

Объястните пожалуйста следущие строки:
Вопрос 1
//————————-перегрузка результатов измерений в буфер———

* (float *)dataSerialBuf = temperature;
* (float *)(dataSerialBuf+4) = voltage;

температура использует первые 4 байта массива (0,1,2,3). Вы написали строку
* (float *)dataSerialBuf = temperature; будет ли она эквивалентна, если запишем так
* (float *)dataSerialBuf[0,1,2,3] = temperature;?

Ну и следующая строка:
* (float *)(dataSerialBuf+4) = voltage; == * (float *)(dataSerialBuf[0,1,2,3]+[4,5,6,7]) = voltage;?

Вопрос 2
Строка if ( (buf[0] == 0x10) && ((buf[0] ^ buf[1] ^ 0xe5) == buf[2]) )
Вы пишите «Контрольный код представляет собой сумму 10 байтов с последующим ”исключающим или”.
Реализуется расчет такого контрольного кода достаточно просто.»
А где здесь сумма 10ти байтов? Если мы приняли только три байта с центрального контроллера

» else if (n == 3) //принята команда, 3 байта
//чтение команды в буфер
byte buf[3];
buf[0]= Serial.read();
buf[1]= Serial.read();
buf[2]= Serial.read(); »

Вопрос 3
Числа(?) 0xe5 и 0xa1e3 в человеческом виде чему равны? Может имеется какая -то таблица с их переводом?

Вопрос 4
Строка sum += buf[i]; переменые в buf[i] прибавляются к sum c каждым циклом и пока
не получится сумма 0xa1e3 в строке sum ^= 0xa1e3; «контрольная сумма ответа»?
Что означаеют символы ^= ?

Здравствуйте!
Посмотрите урок 15 о работе с указателями.
У нас есть переменные, которые надо передать через последовательный интерфейс. Переменные разного типа, например первая temperature типа float. Через последовательный порт мы можем передавать только байтами. Поэтому надо все переменные преобразовать в байты и положить последовательно в буфер. А потом из него передать байтами. На приемной стороне сделать обратную операцию.
* (float *)dataSerialBuf = temperature;
Указатель на массив типа byte (указатель на массив равен его имени) dataSerialBuf преобразовали в указатель на тип float.
По этому указателю положили число типа float, которое занимает 4 байта.
* (float *)(dataSerialBuf+4) = voltage;
Тоже самое с переменной voltage, только сместили на 4 байта. и т.д.
Что касается второго вопроса. Я не помню формат протокола. Значит принимается 2 байта и 3й байт это контрольный код.
3 вопрос. Откройте калькулятор на компьютере. Выберите режим программиста. Набираете в одной системе исчисления, переключаете на другую и получаете результат. 0xe5 это в шестнадцатеричном виде.
4 вопрос. ^ Это операция ИСКЛЮЧАЮЩЕЕ ИЛИ. Побитное сложение, при котором если биты равны, то результат 0, если не равны, то результат бита 1. В данном случае применяется, чтобы при всех нулевых байтах контрольный код не был равен нулю. Такая ситуация возникает после сброса микроконтроллера.
Не обижайтесь. Почти все вопросы у вас начального уровня. Я периодически задумываюсь открыть на форуме раздел для таких вопросов и отвечать на них там более развернуто.

Здравствуйте Эдуард.
Спасибо за ответ.
Какая тут обида.
Где же ещё узнать и у кого как не на Вашем сайте.
А в учебниках типа Блума, Петина, Белова и таких же авторов об этом не пишут и не разясняют, что почём, от куда и куда.
Спасибо.

Оцените статью
Fobosworld.ru
Добавить комментарий

Adblock
detector