Протоколы связи являются составной частью многих современных электронных проектов. Везде, где требуется подключение различных периферийных устройств или соединение между собой нескольких микроконтроллеров, для передачи данных применяются протоколы связи. К настоящему времени разработано достаточно много протоколов связи и среди них достаточно популярным является протокол RS-485, который находит широкое применение в промышленных проектах.
Ранее на нашем сайте мы рассматривали последовательную связь между Arduino Uno и Arduino Nano по протоколу RS-485, также мы рассматривали применение данного протокола совместно с протоколом Modbus в плате Arduino Uno. В этой же статье мы рассмотрим последовательную связь между платами STM32F103C8 (также известной под названием STM32 Blue Pill – "синяя таблетка") и Arduino Uno по протоколу RS-485.
В этом проекте мы будем использовать три кнопки, подключенных к плате STM32F103C8 и выполняющей роль ведущего устройства (Master), для управления тремя светодиодами, подключенных к плате Arduino Uno и выполняющей роль ведомого устройства (Slave).
Протокол последовательной связи RS-485
RS-485 представляет собой асинхронный интерфейс последовательной связи, не требующий для своей работы импульсов синхронизации. Для передачи двоичных данных от одного устройства к другому интерфейс использует дифференциальный сигнал.
Если следовать определению из википедии, дифференциальный сигнал представляет собой способ электрической передачи информации с помощью двух противофазных сигналов. В данном методе один электрический сигнал передаётся в виде дифференциальной пары сигналов, каждый по своему проводнику, но один представляет инвертированный сигнал другого, противоположный по знаку. Пара проводников может представлять собой витую пару, твинаксиальный кабель или разводиться по печатной плате. Приёмник дифференциального сигнала реагирует на разницу между двумя сигналами, а не на различие между одним проводом и потенциалом земли.
В нашем случае дифференциальный сигнал образуется при помощи использования положительного и отрицательного напряжения 5V. Интерфейс RS-485 обеспечивает полудуплексную связь (Half-Duplex) при использовании 2-х линий (проводов) и полноценную дуплексную связь (Full-Duplex) при использовании 4-х линий (проводов).
Основные особенности данного интерфейса:
- Максимальная скорость передачи данных в интерфейсе RS-485 – 30 Мбит/с.
- Максимальная дистанция связи – 1200 метров, что значительно больше чем в интерфейсе RS-232.
- Основным достоинством интерфейса RS-485 по сравнению с RS-232 является использование нескольких ведомых (multiple slave) при одном ведущем (single master) в то время как RS-232 поддерживает только одного ведомого.
- Максимальное число устройств, которое можно подключить по интерфейсу RS-485 – 32.
- Также к достоинствам интерфейса RS-485 относится хорошая помехоустойчивость вследствие использования дифференциального сигнала.
- RS-485 обеспечивает более высокую скорость передачи по сравнению с интерфейсом I2C.
Для последовательной связиь между платами STM32F103C8 и Arduino Uno по протоколу RS-485 мы будем использовать модуль 5V MAX485 TTL to RS485, в основе которого лежит микросхема Maxim MAX485. Модуль является двунаправленным и обеспечивает последовательную связь на расстояние до 1200 метров. В полудуплексном режиме он обеспечивает скорость передачи данных 2,5 Мбит/с.
Модуль 5V MAX485 TTL to RS485 использует питающее напряжение 5V и логический уровень напряжения также 5V, что позволяет без проблем подключать его к платам Arduino.
Данный модуль имеет следующие особенности:
- работает с напряжениями 5V;
- имеет в своем составе чип MAX485;
- отличается низким энергопотреблением;
- всеми его контактами можно управлять с помощью микроконтроллера;
- размеры платы модуля: 44 x 14mm.
Внешний вид модуля RS-485 показан на следующем рисунке.
Назначение контактов (распиновка) модуля RS-485 приведена в следующей таблице.
Название контакта | Назначение контакта |
VCC | 5V |
A | вход/выход линии RS-485 |
B | вход/выход линии RS-485 |
GND | GND (0V) |
R0 | выход приемника (RX pin) |
RE | разрешение работы приемника |
DE | разрешение работы передатчика |
DI | вход передатчика (TX pin) |
Как видите, контакты на модуле RS-485 расположены очень логично - с одной стороны к модулю подключается устройство, а с другой - линия.
Подключить модуль MAX485 TTL to RS485 к платам STM32F103C8 и Arduino Uno достаточно просто – для этого используются последовательные порты данных плат, которые расположены на следующих контактах:
- в плате STM32F103C8: контакты PA9 (TX) и PA10 (RX);
- в плате Arduino Uno: контакты 0 (RX) и 1 (TX).
Запрограммировать работу данного модуля при его подключении к платам STM32F103C8 и Arduino Uno тоже несложно: необходимо использовать функцию Serial.print() для передачи данных по RS-485 и функцию Serial.Read() для чтения данных из RS-485. При этом на контакты DE & RE модуля MAX485 TTL to RS485 необходимо подать уровень LOW для приема данных и уровень HIGH для передачи данных.
Необходимые компоненты
- Отладочная плата STM32F103C8 (STM32 Blue Pill) (купить на AliExpress).
- Плата Arduino Uno (купить на AliExpress).
- Модуль преобразования MAX485 TTL в RS485 – 2 шт. (купить на AliExpress).
- Кнопка – 3 шт.
- Светодиод – 3 шт. (купить на AliExpress).
- Резисторы (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Схема проекта
Схема для последовательной связи между платами STM32F103C8 и Arduino Uno по протоколу RS-485 представлена на следующем рисунке.
В нашем проекте плата STM32F103C8 (Blue Pill) будет использоваться в качестве ведущей (Master), а плата Arduino Uno – в качестве ведомой (Slave).
Схема соединений между модулем MAX485 TTL в RS485 и платой STM32F103C8 (ведущей) приведена в следующей таблице.
MAX485 TTL в RS485 | STM32F103C8 |
DI | PA9 (TX1) |
DE RE | PA3 |
R0 | PA10 (RX1) |
VCC | 5V |
GND | GND |
A | To A of Slave RS-485 |
B | To B of Slave RS-485 |
Три кнопки с помощью подтягивающих резисторов 10 кОм подключены к контактам PA0, PA1, PA2 платы STM32F103C8.
Схема соединений между модулем MAX485 TTL в RS485 и платой Arduino Uno (ведомой) приведена в следующей таблице.
MAX485 TTL в RS485 | Arduino Uno |
DI | 1 (TX) |
DE RE | 2 |
R0 | 0 (RX) |
VCC | 5V |
GND | GND |
A | To A of Master RS-485 |
B | To B of Master RS-485 |
Три светодиода с помощью подтягивающих резисторов 330 Ом подключены к контактам 4, 7, 8 платы Arduino Uno.
Объяснение программ проекта
Полный код программ приведен в конце статьи, здесь же мы кратко рассмотрим их основные фрагменты.
Для программирования плат STM32F103C8 и Arduino Uno мы будем использовать Arduino IDE. Только убедитесь в том, что в Arduino IDE вы выбрали правильный порт в пункте меню Tools->Port и правильную плату в пункте меню Tools->Board.
В нашем проекте у нас будет две программы – для платы STM32F103C8 (ведущей) и платы Arduino Uno (ведомой). Рассмотрим каждую из этих программ по отдельности.
Программа для платы STM32F103C8 (ведущей)
На стороне ведущего (Master) мы будем считывать состояние кнопок и передавать их по протоколу RS-485 через последовательный порт Serial 1 (контакты PA9, PA10) платы STM32F103C8. Для этого нам не понадобится никаких дополнительных библиотек – Arduino IDE содержит все необходимые для последовательной связи библиотеки.
В начале программы инициализируем последовательную связь на контактах PA9, PA10 со скоростью 9600 бод.
1 |
Serial1.begin(9600); |
Считаем состояние кнопок, подключенных к контактам PA0, PA1, PA2 платы STM32F103C8, и сохраним их в переменных button1val, button2val, button3val. Их значение будет равно HIGH если кнопка нажата и LOW если кнопка не нажата.
1 2 3 |
int button1val = digitalRead(button1); int button2val = digitalRead(button2); int button3val = digitalRead(button3); |
Перед тем как передавать значения кнопок через последовательный порт, на контакты DE & RE модуля RS-485 (которые подключены к контакту PA3 платы STM32F103C8), необходимо подать уровень HIGH.
1 |
digitalWrite(enablePin, HIGH); |
Далее в зависимости от состояния кнопок мы будем передавать в последовательный порт соответствующие значения. Если нажата первая кнопка, то мы будем передавать значение ‘1’.
1 2 3 4 5 |
if (button1val == HIGH) { int num1 = 1; Serial1.println(num1); } |
Аналогичным образом, если нажата кнопка 2, мы будем передавать значение 2, а если нажата кнопка 3 – то значение 3.
1 2 3 4 5 6 7 8 9 10 |
else if (button2val == HIGH) { int num2 =2; Serial1.println(num2); } else if (button3val == HIGH) { int num3 =3; Serial1.println(num3); } |
Когда ни одна из кнопок не нажата, мы будем передавать значение 0.
1 2 3 4 5 |
else { int num = 0; Serial1.println(num); } |
Программа для платы Arduino Uno (ведомой)
Ведомая плата Arduino Uno будет принимать значение целого типа (integer), которое было передано ей ведущей STM32F103C8. Мы будем считывать это значение и сохранять его в переменной. Далее в зависимости от значения этой переменной мы будем включать/выключать соответствующий светодиод.
Для того, чтобы осуществить прием данных по протоколу RS-485 нам необходимо подать на контакты DE & RE модуля RS-485 уровень LOW – для этого нам необходимо подать на контакт 2 платы Arduino Uno уровень LOW.
1 |
digitalWrite(enablePin, LOW); |
После этого считаем число целого типа из последовательного порта и сохраним его в соответствующей переменной.
1 |
int receive = Serial.parseInt(); |
Далее в зависимости от принятого значения (0, 1, 2 или 3) мы будем зажигать соответствующий светодиод.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
if (receive == 1) //Depending Upon Recieved value the corresponding LED is turned ON or OFF { digitalWrite(ledpin1,HIGH); } else if (receive == 2) { digitalWrite(ledpin2,HIGH); } else if (receive == 3) { digitalWrite(ledpin3,HIGH); } else { digitalWrite(ledpin1,LOW); digitalWrite(ledpin2,LOW); digitalWrite(ledpin3,LOW); } |
Тестирование работы проекта
При нажатии первой кнопки, подключенной к ведущей STM32, будет загораться первый светодиод, подключенный к ведомой Arduino.
При нажатии второй кнопки, подключенной к ведущей STM32, будет загораться второй светодиод, подключенный к ведомой Arduino.
Аналогичным образом, при нажатии третьей кнопки, подключенной к ведущей STM32, будет загораться третий светодиод, подключенный к ведомой Arduino.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы (скетча)
Программа для STM32F103C8 (ведущей)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
//RS-485 Serial Communication Between STM32F103C8 & Arduino Uno #define button1 PA0 #define button2 PA1 #define button3 PA2 #define enablePin PA3 void setup() { Serial1.begin(9600); // Begins Serial communication at serial1 Port PA9,PA10 at baudrate 9600 pinMode(enablePin, OUTPUT); pinMode(button1,INPUT); pinMode(button2,INPUT); pinMode(button3,INPUT); delay(10); digitalWrite(enablePin, HIGH); // (always high as Master Writes data to Slave) } void loop() { int button1val = digitalRead(button1); //считываем состояние кнопки int button2val = digitalRead(button2); int button3val = digitalRead(button3); if (button1val == HIGH) { int num1 = 1; Serial1.println(num1); // передаем 1 если нажата первая кнопка } else if (button2val == HIGH) { int num2 =2; Serial1.println(num2); // передаем 2 если нажата вторая кнопка } else if (button3val == HIGH) { int num3 =3; Serial1.println(num3); // передаем 3 если нажата третья кнопка } else { int num = 0; Serial1.println(num); // передаем 0 если не нажата ни одна из кнопок } delay(50); } |
Программа для Arduino Uno (ведомой)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
//RS-485 Serial Communication Between STM32F103C8 & Arduino Uno #define enablePin 2 #define ledpin1 4 #define ledpin2 7 #define ledpin3 8 void setup() { Serial.begin(9600); // инициализируем последовательную связь со скоростью 9600 бод pinMode(ledpin1,OUTPUT); pinMode(ledpin2,OUTPUT); pinMode(ledpin3,OUTPUT); pinMode(enablePin, OUTPUT); delay(10); digitalWrite(enablePin, LOW); // (Pin 8 always LOW to receive value from Master) } void loop() { while (Serial.available()) //пока в последовательном порту есть данные выполняем цикл { int receive = Serial.parseInt(); // считываем значение целого типа, переданное платой STM32 if (receive == 1) // в зависимости от принятого значения включаем соответствующий светодиод { digitalWrite(ledpin1,HIGH); } else if (receive == 2) { digitalWrite(ledpin2,HIGH); } else if (receive == 3) { digitalWrite(ledpin3,HIGH); } else { digitalWrite(ledpin1,LOW); digitalWrite(ledpin2,LOW); digitalWrite(ledpin3,LOW); } } } |
Оставлю свой запоздалый комментарий.
Ни RS-485, ни RS-232, ни что-то еще подобное не являются протоколами.
Это физические интерфейсы. А протокол придумывает разработчик программы либо сообщество программистов.
Ну он не запоздалый, мы все рады прислушаться к конструктивным комментариям. ))
Многие источники трактуют понятия протокол и интерфейс немного по разному, из-за этого многим энтузиастам часто трудно определить разницу между этими понятиями и они просто отождествляют их, то есть считают их фактическими одинаковыми понятиями
Начало статьи показало, что автор не в теме:
Использование питания +5 и - 5в обсуждалось в 80х, когда протокол RS485 обсуждался. Появление специализированных микросхем зафиксировало только однополярние питание и уровни сигнала в одной полярности.
Следует различать логический и физический протоколы. RS485 это только физический протокол связи, использующий (чаще всего) логический протокол RS232, который имеет и физическую и логическую версию.
Полный дуплекс по 4м проводам называется RS422
Начало статьи скопировано из Википедии. Насколько она правдива, да, не проверял. Но главное проект то рабочий. Но вам все равно спасибо за полезный комментарий
RS-485, like RS-422, can be made full-duplex by using four wires. Похоже, комментатор выше, сам не в теме. )
Ну, может быть с помощью комментариев, мы все таки установим истину в этом вопросе ))