Перевод статьи How to use I2C Communication in STM32 Microcontroller (STM32F103C8)Pramoth Thangavel, Circuit Digest.

В прошлых материалах мы разбирали связь по SPI и I2C между двумя платами Arduino. В этом руководстве мы заменим одну из Arduino платой Blue Pill (STM32F103C8) и наладим обмен с Arduino по шине I2C.

Обзор I2C в STM32F103C8#

Если сравнить I2C (Inter-Integrated Circuits) у STM32F103C8 Blue Pill и Arduino Uno: в Arduino стоит ATMEGA328, а в STM32F103C8 — ARM Cortex-M3. У STM32 две шины I2C, у Arduino Uno — одна, и STM32 быстрее.

Пины I2C у STM32F103C8#

  • SDA: PB7, PB9 или PB11;
  • SCL: PB6, PB8 или PB10.
Распиновка STM32F103C8 с пинами I2C

Пины STM32F103C8.

Пины I2C у Arduino#

  • SDA: пин A4;
  • SCL: пин A5.
Пины I2C на Arduino

Пины I2C на Arduino: SDA (A4), SCL (A5).

Компоненты#

  • STM32F103C8;
  • Arduino Uno;
  • светодиод — 2 шт.;
  • кнопка — 2 шт.;
  • резисторы — 4 шт. (10 кОм — 2, 2,2 кОм — 2);
  • макетная плата;
  • соединительные провода.

Схема и подключения#

В таблице ниже — соединения STM32 Blue Pill и Arduino Uno для шины I2C. Нужно всего два провода.

STM32F103C8ArduinoНазначение
B7A4SDA
B6A5SCL
GNDGNDЗемля

Важно:

  • обязательно соедините GND у Arduino и STM32F103C8;
  • к пинам кнопок обеих плат подключите подтягивающие к земле резисторы 10 кОм.

В этом руководстве STM32F103C8 — мастер, Arduino — ведомый. К каждой плате отдельно подключены светодиод и кнопка. Мы управляем светодиодом мастера (STM32) кнопкой ведомого (Arduino) и наоборот — значения передаются по шине I2C.

Схема I2C-связи между STM32 и Arduino

Схема I2C-связи STM32 ↔ Arduino.

Программирование I2C на STM32#

Программирование похоже на код Arduino — используется та же библиотека <Wire.h>. STM32F103C8 можно прошивать через USB без FTDI-программатора.

Разбор кода мастера (STM32)#

  1. Подключаем библиотеки Wire и SoftWire.
#include<Wire.h>
#include<SoftWire.h>
  1. В setup(): запускаем Serial на 9600 и начинаем I2C на пинах (B6, B7).
Serial.begin(9600);
Wire.begin();
  1. В loop(): сначала запрашиваем данные у ведомого Arduino (адрес 8, один байт) и читаем полученное значение.
Wire.requestFrom(8,1);
byte a = Wire.read();

В зависимости от полученного значения зажигаем или гасим светодиод мастера (пин PA1). Затем читаем состояние кнопки мастера (PA0) и отправляем соответствующее значение ведомому.

Wire.beginTransmission(8);
Wire.write(x);
Wire.endTransmission();

Разбор кода ведомого (Arduino)#

  1. Подключаем библиотеку Wire.

  2. В setup(): запускаем Serial, начинаем I2C с адресом ведомого 8 на пинах (A4, A5) и регистрируем обработчики событий приёма и запроса.

Wire.begin(8);
Wire.onReceive(receiveEvent); Wire.onRequest(requestEvent);
  1. Обработчик запроса requestEvent() вызывается, когда мастер запрашивает данные: читает кнопку ведомого и отправляет байт (1 или 0). Обработчик приёма receiveEvent() вызывается, когда мастер прислал данные: читает значение и зажигает/гасит светодиод ведомого.

Результат#

  1. При нажатии кнопки на мастере (STM32) загорается светодиод, подключённый к ведомому Arduino (белый).
  2. При нажатии кнопки на стороне ведомого загорается светодиод мастера (красный), а при отпускании — гаснет.
  3. При одновременном нажатии обеих кнопок оба светодиода горят вместе, пока кнопки удерживаются.

Так и работает I2C-связь на STM32 — теперь к плате можно подключить любой I2C-датчик.

Нажата кнопка мастера — горит светодиод ведомого

Нажата кнопка мастера — загорается светодиод ведомого.

Нажата кнопка ведомого — горит светодиод мастера

Нажата кнопка ведомого — загорается светодиод мастера.

Проверка I2C-связи: обе кнопки нажаты, оба светодиода горят

Обе кнопки нажаты — оба светодиода горят.

Полный код#

Мастер (STM32)#

//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)#

//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
}