Беспроводные технологии играют важную роль в жизни современного общества. К подобным технологиям можно отнести Bluetooth, WiFi, радиочастотные модули 433 МГц (433 MHz RF) и т.д. Каждая из этих технологий имеет свои преимущества и недостатки по скорости, дальности, стоимости и т.п.
В данной статье мы рассмотрим подключение радиочастотного модуля 433 МГц (RF Module 433Mhz) к плате STM32F103C8, также известной под названием STM32 Blue Pill («синяя таблетка»). В передающей части нашего проекта передатчик будет подключен к плате STM32F103C8 (Blue Pill), а в приемной части проекта приемный радиочастотный модуль будет подключен к плате Arduino Uno.
В данном проекте мы с помощью радиочастотных модулей будем передавать два значения: измеренное с помощью ультразвукового датчика расстояние и значение, считанное с потенциометра (изначально оно в диапазоне 0-4096, но мы его будем преобразовывать в диапазон от 0 до 100). Приемная часть проекта на основе платы Arduino будет принимать эти значения и выводить их на экран ЖК дисплея 16×2.
Также на нашем сайте вы можете посмотреть другие проекты с использованием радиочастотных модулей:
- лодка с дистанционным управлением на Arduino и радиочастотных модулях 433 МГц;
- умная трость для слабовидящих людей на основе Arduino;
- связь микроконтроллеров AVR ATmega8 через радиочастотные модули.
Необходимые компоненты
- Отладочная плата STM32F103C8 (STM32 Blue Pill) (купить на AliExpress).
- Плата Arduino Uno (купить на AliExpress).
- Радиочастотные модули 433 МГц (передатчик и приемник) (купить на AliExpress).
- Ультразвуковой датчик HC-SR04 (купить на AliExpress).
- ЖК дисплей 16×2 (купить на AliExpress).
- Потенциометр 10 кОм (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Приемный и передающий радиочастотные модули 433 МГц
В данном проекте мы будем использовать гибридные передатчики и приемники с амплитудной манипуляцией (ASK Hybrid Transmitter and receiver), работающие на частоте 433 МГц. В своем составе они содержат кварцевый генератор для поддержания хорошей стабильности частоты. В нашем проекте нам понадобится всего одна внешняя антенна для этого модуля. Внешний вид данных модулей представлен на следующем рисунке.
Также широко распространены варианты не с 8 контактами у приемника (как на рисунке), а с 4.
Данные модули достаточно дешево стоят, что обусловило их широкое применение в разнообразных устройствах.
При максимально возможном напряжении питания дальность связи этих радиочастотных модулей составляет примерно 100 метров, при использовании напряжения питания 5 В и простой штыревой антенны длиной 17 см дальность связи с помощью данных модулей составит примерно 50-60 метров.
Технические характеристики радиочастотного передатчика:
- рабочая частота: 433 МГц;
- выходная мощность: 4-16 дБм;
- дальность связи: 3 метра (без антенны), 100 метров (с антенной);
- метод модуляции (манипуляции): амплитудная (Amplitude shift keying, ASK);
- скорость передачи: 10 кбит/с
- напряжение питания: 3-5 В постоянного тока.
Назначение контактов (распиновка) модуля передатчика:
1. GND – общий провод (земля).
2. Data In – по этому контакту модуль принимает последовательные данные от кодера (encoder).
3. Vcc – на этот контакт подается питающее напряжение +5 В.
4. Antenna – к этому контакту подключается внешняя антенна.
Технические характеристики радиочастотного приемника:
- чувствительность: -105 дБм;
- промежуточная частота: 1 МГц;
- низкое потребление энергии;
- потребляемый ток: 3,5 мА;
- напряжение питания: 3-5 В.
Назначение контактов (распиновка) модуля приемника:
1. GND – общий провод (земля).
2. Data In – по этому контакту передаются последовательные данные декодеру.
3. Data In – по этому контакту передаются последовательные данные декодеру.
4. Vcc – на этот контакт подается питающее напряжение +5 В.
5. Vcc – на этот контакт подается питающее напряжение +5 В.
6. GND – общий провод (земля).
7. GND – общий провод (земля).
8. Antenna – к этому контакту подключается внешняя антенна.
Схема проекта
Передающая часть
Схема подключения передающего радиочастотного модуля 433 МГц к STM32F103C8 (Blue Pill) представлена на следующем рисунке.
Плата STM32F103C8 | Радиочастотный модуль |
5V | VDD |
GND | GND |
PA10 | DATA |
NC | ANT |
Схема соединений между ультразвуковым датчиком и платой STM32F103C8 приведена в следующей таблице.
Плата STM32F103C8 | Ультразвуковой датчик |
5V | VCC |
PB1 | Trig |
PB0 | Echo |
GND | GND |
Внешний вид собранной конструкции передающей части проекта представлен на следующем рисунке.
Приемная часть
Схема подключения приемного радиочастотного модуля 433 МГц к плате Arduino Uno представлена на следующем рисунке.
Схема соединений между радиочастотным модулем и платой Arduino Uno приведена в следующей таблице.
Arduino Uno | Приемный радиочастотный модуль |
5V | VDD |
GND | GND |
11 | DATA |
NC | ANT |
Схема соединений между ЖК дисплеем 16х2 и платой Arduino Uno приведена в следующей таблице.
ЖК дисплей 16х2 | Плата Arduino Uno |
Ground (Gnd) | Ground (G) |
VCC | 5V |
VEE | к среднему контакту потенциометра для регулировки контрастности |
Register Select (RS) | 2 |
Read/Write (RW) | Ground (G) |
Enable (EN) | 3 |
Data Bit 4 (DB4) | 4 |
Data Bit 5 (DB5) | 5 |
Data Bit 6 (DB6) | 6 |
Data Bit 7 (DB7) | 7 |
LED Positive | 5V |
LED Negative | Ground (G) |
Внешний вид собранной конструкции приемной части проекта представлен на следующем рисунке.
Объяснение программы для платы STM32 (передающая часть)
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
В передающей части нашего проекта расстояние до препятствия в сантиметрах, измеренное с помощью ультразвукового датчика, и значение с потенциометра, преобразованное в диапазон 0-100, мы будем передавать с помощью радиочастотного модуля, подключенного к плате STM32F103C8.
Первым делом скачайте библиотеку Radiohead по следующей ссылке. Данная библиотека использует амплитудную манипуляцию (Amplitude Shift Keying Technique, ASK) для передачи и приема сигналов. С помощью этой библиотеки программирование работы с радиочастотными модулями становится достаточно простым занятием. Скачанную библиотеку вы можете подключить в Arduino IDE используя пункт меню Sketch->include library->Add .zip library.
Затем подключим использование этой библиотеки в программе.
1 |
#include <RH_ASK.h> |
Укажем контакты платы STM32F103C8, к которым подключены контакты trigger и echo ультразвукового датчика.
1 2 |
#define trigPin PB1 #define echoPin PB0 |
Создадим объект rf_driver для работы с радиочастотным модулем. В качестве параметров для него укажем скорость (2000), контакт RX (PA9) и контакт TX (PA10).
1 |
RH_ASK rf_driver(2000, PA9, PA10); |
Объявим ряд строковых переменных.
1 2 3 |
String transmit_number; String transmit_distance; String transmit; |
Далее, в функции void setup(), инициализируем объект rf_driver.
1 |
rf_driver.init(); |
Затем инициализируем последовательную связь со скоростью 9600 бод и установим режимы работы используемых контактов (на ввод или вывод данных).
1 2 3 4 |
Serial.begin(9600); pinMode(PA0,INPUT); pinMode(echoPin,INPUT); pinMode(trigPin,OUTPUT); |
Далее в функции void loop() мы будем считывать значение с выхода АЦП контакта PA0, к которому подключен потенциометр. Оно в будет в диапазоне от 0 до 4095 поскольку АЦП платы STM32 имеют разрешение 12 бит. После этого мы будем конвертировать считанное значение в диапазон от 0 до 100 с помощью функции map и записывать его в переменную pwmvalue.
1 2 |
int analoginput = analogRead(PA0); int pwmvalue = map(analoginput,0,4095,0,100); |
Затем с помощью ультразвукового датчика мы будем измерять расстояние до препятствия, подавая на его контакты соответствующие уровни напряжения с необходимыми длительностями.
1 2 3 4 5 |
digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); |
После отражения излученной ультразвуковой волны от препятствия на контакте echo ультразвукового датчика формируется импульс, длительность которого равна времени распространения волны до препятствия и обратно. Зная это время и скорость звука в воздухе можно рассчитать расстояние до препятствия.
1 2 |
long duration = pulseIn(echoPin, HIGH); float distance= duration*0.034/2; |
Затем определенное значение расстояние и переменную pwmvalue (значение с потенциометра) мы будем преобразовывать в строки и записывать их в строковые переменные.
1 2 |
transmit_number= String(pwmvalue); transmit_distance = String(distance); |
Далее полученные две строки мы объединяем в одну строку, разделив их значения запятой (“,”).
1 |
transmit = transmit_pwm + "," + transmit_distance; |
Затем мы эту строку преобразуем в символьный массив.
1 |
const char *msg = transmit.c_str(); |
Далее мы передаем эти данные и ждем пока передача не будет закончена.
1 2 |
rf_driver.send((uint8_t *)msg, strlen(msg)); rf_driver.waitPacketSent(); |
Также передаваемую строку мы будем выводить в окно монитора последовательной связи (Serial Monitor).
1 |
Serial.println(msg); |
Объяснение программы для платы Arduino Uno (приемная часть)
В приемной части нашего проекта мы будем принимать от передающей части строку, содержащую сведения об измеренном расстоянии и значении с потенциометра, и отображать их на экране дисплея 16×2.
Первым делом в программе подключим использование библиотеки RadiohHead.
1 |
#include <RH_ASK.h> |
Также подключим библиотеку для работы с ЖК дисплеем.
1 |
#include <LiquidCrystal.h> |
Затем укажем контакты платы Arduino Uno, к которым подключен ЖК дисплей.
1 |
LiquidCrystal lcd(2,3,4,5,6,7); |
Далее объявим необходимые строковые переменные.
1 2 3 |
String str_receive; String str_number; String str_distance; |
Затем создадим объект для работы с радиочастотным модулем.
1 |
RH_ASK rf; |
После этого в функции void setup() установим для ЖК дисплея режим 16×2 и покажем на его экране приветственное сообщение.
1 2 3 4 5 6 |
lcd.begin(16,2); lcd.print("CIRCUIT DIGEST"); lcd.setCursor(0,1); lcd.print("RF with STM32"); delay(5000); lcd.clear(); |
Далее инициализируем объект для работы с радиочастотным модулем.
1 |
rf.init(); |
Затем объявим массив buf[] с размерностью 7 байт – это длина передаваемой нами с помощью радиочастотного модуля строки (с учетом символа “,”).
1 2 |
uint8_t buf[7]; uint8_t buflen = sizeof(buf); |
Если передаваемая строка доступна в приемном радиочастотном модуле мы проверяем ее размер и выполняем функцию rf.recv(), которая используется для приема данных.
1 |
if (rf.recv(buf, &buflen)) |
Переданную строку мы приняли в массив buf, теперь этот массив символов мы преобразуем в строку и сохраним ее в переменной str_receive.
1 |
str_receive = String((char*)buf); |
Затем в цикле for мы разделим эту строку на две строки при помощи нахождения в ней разделительного символа ‘,’.
1 2 3 4 5 6 7 8 |
for (int i = 0; i < str_receive.length(); i++) { if (str_receive.substring(i, i+1) == ",") { str_number = str_receive.substring(0, i); str_distance = str_receive.substring(i+1); break; } |
Далее эти две строки мы преобразуем в символьные массивы.
1 2 3 4 |
char numberstring[4]; char distancestring[3]; str_distance.toCharArray(distancestring,3); str_number.toCharArray(numberstring,3); |
После этого конвертируем их в числа целого типа (integer) с помощью функции atoi().
1 2 |
int distance = atoi(distancestring); int number = atoi(numberstring); |
Затем мы отобразим эти числа на экране ЖК дисплея 16х2.
1 2 3 4 5 6 7 |
lcd.setCursor(0,0); lcd.print("Number:"); lcd.print(number); lcd.setCursor(0,1); lcd.print("Distance :"); lcd.print(distance); lcd.print(" cm"); |
Тестирование работы проекта
После загрузки кодов программ в платы STM32 и Arduino передаваемые передающей частью проекта данные будут отображаться на экране ЖК дисплея в приемной части.
На следующем рисунке показан пример работы нашего проекта при значении с потенциометра, равного 0, и расстояния до препятствия, равного 6 см.
Аналогичный пример при значении 47 с потенциометра и расстоянии 3 см.
Исходный код программы (скетча)
Передающая часть (плата 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 |
//433MHZ RF Trasmitter with STM32F103C8 //Transmitter Code //Circuit Digest #include <RH_ASK.h> //библиотека RadioHead #define trigPin PB1 //Sets the Trigpin of Ultrasonic sensor as PB1 #define echoPin PB0 //Sets the echoPin of Ultrasonic sensor as PB0 RH_ASK rf_driver(2000, PA9, PA10); //Sets Pin PA9 as receiver and PA10 as transmitterand 2000 as Speed String transmit_pwm; //Strings to store string value String transmit_distance; String transmit; void setup() { // Initialize ASK Object rf_driver.init(); Serial.begin(9600); pinMode(PA0,INPUT); pinMode(echoPin,INPUT); pinMode(trigPin,OUTPUT); } void loop() { int analoginput = analogRead(PA0); // значение с выхода АЦП контакта PA0, к которому подключен потенциометр int pwmvalue = map(analoginput,0,4096,0,100); // конвертируем диапазон 0-4096 в диапазон от 0 до 100 digitalWrite(trigPin, LOW); //подаем на TrigPin датчика уровень LOW delayMicroseconds(2); digitalWrite(trigPin, HIGH); // подаем на TrigPin датчика уровень HIGH delayMicroseconds(10); digitalWrite(trigPin, LOW); // подаем на TrigPin датчика уровень LOW long duration = pulseIn(echoPin, HIGH); //измеряем длительность импульса на контакте Echo float distance= duration*0.034/2; //рассчитываем расстояние до объекта в см transmit_pwm = String(pwmvalue); //преобразуем значение в строку transmit_distance = String(distance); // преобразуем значение в строку transmit = transmit_pwm + "," + transmit_distance; //объединяем две строки в одну const char *msg = transmit.c_str(); // rf_driver.send((uint8_t *)msg, strlen(msg)); //передаем строку rf_driver.waitPacketSent(); Serial.println(msg); //для целей отладки delay(1000); } |
Приемная часть (плата 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 42 43 44 45 46 47 48 49 50 51 52 53 |
//Receiver Arduino Code //433MHZ RF with STM32F103C8 as Transmitter //Circuit Digest #include <RH_ASK.h> //подключаем библиотеку RadioHead #include <LiquidCrystal.h> //библиотека для работы с ЖК дисплеем LiquidCrystal lcd(2,3,4,5,6,7); // создаем объект для работы с ЖК дисплеем с указанием контактов платы, к которым он подключен String str_receive; //Strings to Store Value String str_number; String str_distance; RH_ASK rf; //rf as object for RG_ASK void setup() { lcd.begin(16,2); //режим работы ЖК дисплея 16x2 lcd.print("CIRCUIT DIGEST"); //показываем приветственное сообщение lcd.setCursor(0,1); lcd.print("RF with STM32"); delay(5000); lcd.clear(); rf.init(); //инициализируем объект для работы с радиочастотным модулем } void loop() { uint8_t buf[7]; uint8_t buflen = sizeof(buf); if (rf.recv(buf, &buflen)) { str_receive = String((char*)buf); // принимаем строку от передатчика for (int i = 0; i < str_receive.length(); i++) // разделяем принятую строку на две строки { if (str_receive.substring(i, i+1) == ",") { str_number = str_receive.substring(0, i); str_distance = str_receive.substring(i+1); break; } } char numberstring[4]; char distancestring[3]; str_distance.toCharArray(distancestring,3); //конвертируем строку в массив символов str_number.toCharArray(numberstring,3); int distance = atoi(distancestring); //конвертируем символьный массив в число целого типа int number = atoi(numberstring); lcd.setCursor(0,0); lcd.print("Number:"); lcd.print(number); //Display number value at LCD display lcd.setCursor(0,1); lcd.print("Distance :"); lcd.print(distance); //Display distance value at LCD display lcd.print(" cm"); delay(1500); lcd.clear(); } } |