Интерфейс I2C в настоящее время является одним из самых популярных интерфейсов для связи между внутренними компонентами электронной аппаратуры. Ранее на нашем сайте мы рассматривали статью про использование интерфейса I2C в плате Arduino, в которой демонстрировали возможность связи между двумя платами Arduino по протоколу I2C. В этой же статье мы заменим одну из плат Arduino в отмеченном проекте на плату STM32F103C8, которая также известна под названием STM32 Blue Pill («синяя таблетка»). Таким образом, мы рассмотрим использование интерфейса I2C в плате STM32F103C8 (Blue Pill) и ее связь по данному интерфейсу с платой Arduino.
Если сравнивать интерфейс I2C (Inter Integrated Circuits) в платах STM32F103C8 Blue Pill и Arduino Uno мы увидим, что в плате Arduino он реализуется с помощью микроконтроллера ATMEGA328, а в плате STM32F103C8 – с помощью микроконтроллера ARM Cortex M3. Плата Arduino Uno имеет только одну шину I2C, а плате STM32 их две. К тому же по вычислительным возможностям плата STM32F103C8 значительно превосходит плату Arduino Uno.
В следующей статье на нашем сайте мы рассмотрим использование интерфейса SPI в плате STM32F103C8.
Контакты I2C в плате STM32F103C8
Распиновка платы STM32F103C8 представлена на следующем рисунке.
- SDA: PB7 или PB9, PB11;
- SCL: PB6 или PB8, PB10.
Контактами I2C в плате Arduino Uno являются:
- SDA: контакт A4;
- SCL: контакт A5.
Необходимые компоненты
- Плата разработки STM32F103C8 (STM32 Blue Pill) (купить на AliExpress).
- Плата Arduino Uno (купить на AliExpress).
- Светодиод – 2 шт. (купить на AliExpress).
- Кнопка – 2 шт.
- Резисторы 10 кОм (2 шт.) и 2,2 кОм (2 шт.) (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Схема проекта
Схема для связи между платами STM32F103C8T6 и Arduino Uno по интерфейсу I2C представлена на следующем рисунке.
Плата STM32 Blue Pill | Плата Arduino Uno | Описание контакта |
B7 | A4 | SDA |
B6 | A5 | SCL |
GND | GND | Ground |
Примечания:
- не забудьте соединить контакты GND (общий провод) плат Arduino и STM32F103C8;
- подключите подтягивающие резисторы 10 кОм к каждой из двух кнопок в схеме.
В нашем проекте плата STM32 Blue Pill будет выступать в роли ведущего устройства (Master) для связи по интерфейсу I2C, а плата Arduino – в роли ведомого (Slave). К каждой из плат подключены светодиод и кнопка.
Для демонстрации возможностей использования интерфейса I2C в плате STM32 мы будем управлять светодиодом, подключенным к ней (к ведущему), с помощью кнопки, подключенной к плате Arduino (ведомой). Аналогично мы будем управлять светодиодом, подключенным к плате Arduino (ведомой), с помощью кнопки, подключенной к плате STM32 (ведущей). Данные будут передаваться по шине I2C.
Объяснение программ для работы с интерфейсом I2C
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты.
Программа для платы STM32 в данном случае будет очень похожа на программу для платы Arduino – будет использоваться та же самая библиотека <wire.h>. Программировать плату STM32F103C8 мы будем с помощью Arduino IDE через USB порт, без использования внешнего FTDI программатора.
В нашем проекте у нас будет две программы: одна для платы STM32, которая будет выступать ведущим устройством, и одна для платы Arduino, которая будет выступать ведомым устройством.
Объяснение программы для платы STM32 (ведущей)
В программе для платы STM32 (ведущей) нам первым делом необходимо подключить библиотеки Wire.h и SoftWire.h.
1 2 |
#include <Wire.h> #include <SoftWire.h> |
Затем в функции void setup() мы инициализируем последовательную связь со скоростью 9600 бод.
1 |
Serial.begin(9600); |
После этого мы начнем связь по протоколу I2C на контактах (B6, B7).
1 |
Wire.begin(); |
Далее в функции void loop() мы будем получать данные от ведомой Arduino с помощью функции Wire.requestFrom(8,1), где 8 – это адрес ведомого (slave address), а 1 – количество запрашиваемых байт (то есть в данном случае мы будем запрашивать один байт).
1 |
Wire.requestFrom(8,1); |
Принимаемое значение мы будем считывать с помощью функции Wire.read().
1 |
byte a = Wire.read(); |
В зависимости от принятого от ведомого значения мы будем включать или выключать светодиод, подключенный к нашей плате STM32 (ведущей), с помощью функции digitalWrite(). Также мы будем выводить в окно монитора последовательной связи сообщение, свидетельствующее о включении/выключении светодиода.
1 2 3 4 5 6 7 8 9 10 |
if (a==1) { digitalWrite(LED,HIGH); Serial.println("Master LED ON"); } else { digitalWrite(LED,LOW); Serial.println("Master LED OFF"); } |
Затем мы будем считывать состояние контакта PA0 платы STM32, к которому подключена кнопка.
1 |
int pinvalue = digitalRead(buttonpin); |
Далее в зависимости от состояния контакта PA0 мы будем передавать соответствующее значение (0 или 1) ведомой плате Аrduino с адресом 8.
1 2 3 4 5 6 7 8 9 10 11 |
if(pinvalue==HIGH) { x=1; } else { x=0; } Wire.beginTransmission(8); Wire.write(x); Wire.endTransmission(); |
Объяснение программы для платы Arduino (ведомой)
Первым делом в программе подключим библиотеку Wire для использования возможностей протокола I2C.
1 |
#include <Wire.h> |
Затем в функции void setup() мы инициализируем последовательную связь со скоростью 9600 бод.
1 |
Serial.begin(9600); |
Далее начнем связь по протоколу I2C на контактах (A4, A5) с адресом ведомого (slave address) 8. Здесь важно указать адрес ведомого.
1 |
Wire.begin(8); |
После этого мы должны вызвать функцию Wire.onReceive когда ведомый получает значение от ведущего и функцию Wire.onRequest когда ведущий (Master) запрашивает значение от ведомого (Slave).
1 |
Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent); |
Затем нам необходимо запрограммировать две функции – для события запроса и для события приема.
Для события запроса
Данная функция будет выполняться когда плата STM32 (ведущая) будет запрашивать значение от ведомого (slave). Эта функция будет считывать значение (0 или 1) с кнопки, подключенной к ведомой Arduino, и передавать его ведущей STM32 с помощью функции Wire.write().
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void requestEvent() { int value = digitalRead(buttonpin); if (value == HIGH) { x=1; } else { x=0; } Wire.write(x); } |
Для события приема
Данная функция будет выполняться когда ведущий (Master) будет передавать данные ведомому (slave) с адресом равным 8. Функция будет считывать принятое от ведущего значение и сохранять его в переменной типа byte. Далее в зависимости от принятого значения она будет включать или выключать светодиод.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void receiveEvent (int howMany) { byte a = Wire.read(); if (a == 1) { digitalWrite(LED,HIGH); Serial.println("Slave LED ON"); } else { digitalWrite(LED,LOW); Serial.println("Slave LED OFF"); } delay(500); } |
Тестирование работы проекта
Когда мы будем нажимать кнопку, подключенную к ведущей STM32, светодиод, подключенный к ведомой Arduino, будет загораться.
Если же мы нажмем кнопку на ведомой стороне, то загорится светодиод на ведущей стороне.
Когда обе кнопки будут нажаты одновременно, то оба светодиода загорятся в одно и то же время и будут оставаться во включенном состоянии до тех пор, пока мы не отпустим кнопки.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы (скетча)
Код для ведущей STM32
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 54 55 56 57 |
//I2C Master Code (STM32F103C8) //I2C Communication between STM32 and Arduino //Circuit Digest #include<Wire.h> #include<SoftWire.h> //Library for I2C Communication functions #define LED PA1 #define buttonpin PA0 int x = 0; void setup() { Serial.begin(9600); //Begins Serial Communication at 9600 baud rate pinMode(buttonpin,INPUT); //Sets pin PA0 as input pinMode(LED,OUTPUT); //Sets PA1 as Output Wire.begin(); //Begins I2C communication at pin (B6,B7) } void loop() { Wire.requestFrom(8,1); // request bytes from slave arduino(8) byte a = Wire.read(); // receive a byte from the slave arduino and store in variable a if (a==1) //Logic to turn Master LED ON (if received value is 1) or OFF (if received value is 0) { digitalWrite(LED,HIGH); Serial.println("Master LED ON"); } else { digitalWrite(LED,LOW); Serial.println("Master LED OFF"); } { int pinvalue = digitalRead(buttonpin); //Reads the status of the pin PA0 if(pinvalue==HIGH) //Logic for Setting x value (To be sent to slave Arduino) depending upon inuput from pin PA0 { x=1; } else { x=0; } Wire.beginTransmission(8); // starts transmit to device (8-Slave Arduino Address) Wire.write(x); // sends the value x to Slave Wire.endTransmission(); // stop transmitting delay(500); } } |
Код для ведомой Arduino
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 54 55 56 57 58 59 |
//I2C Slave Code (Arduino) //I2C Communication between STM32 and Arduino //Circuit Digest #include<Wire.h> //Library for I2C Communication functions #define LED 7 #define buttonpin 2 byte x =0; void setup() { Serial.begin(9600); //Begins Serial Communication at 9600 baud rate pinMode(LED,OUTPUT); //Sets pin 7 as output Wire.begin(8); // join i2c bus with its slave Address as 8 at pin (A4,A5) Wire.onReceive(receiveEvent); //Function call when Slave Arduino receives value from master STM32 Wire.onRequest(requestEvent); //Function call when Master STM32 request value from Slave Arduino } void loop() { delay(100); } void receiveEvent (int howMany) //This Function is called when Slave Arduino receives value from master STM32 { byte a = Wire.read(); //Used to read value received from master STM32 and store in variable a if (a == 1) //Logic to turn Slave LED ON (if received value is 1) or OFF (if received value is 0) { digitalWrite(LED,HIGH); Serial.println("Slave LED ON"); } else { digitalWrite(LED,LOW); Serial.println("Slave LED OFF"); } delay(500); } void requestEvent() //This Function is called when Master STM32 wants value from slave Arduino { int value = digitalRead(buttonpin); //Reads the status of the pin 2 if (value == HIGH) //Logic to set the value of x to send to master depending upon input at pin 2 { x=1; } else { x=0; } Wire.write(x); // sends one byte of x value to master STM32 } } |