مهندس موفق الکترونیک

راه اندازی I2C در STM32

در جلسات قبلی، چگونگی استفاده از پروتکل‌های ارتباطی Inter Integrated Circuits) I2C) و SPI را در ارتباط میان دو بورد آردوینو یاد گرفته‌ایم. در این جلسه می‌خواهیم یکی از بوردهای آردوینو را با بورد blue pill که بورد توسعه‌ی میکروکنترلر STM32F103C8 است جایگزین کنیم و ببینیم که چطور می‌توان با استفاده از پروتکل I2C، میان این میکرو و بورد آردوینو ارتباط برقرار کرد.

آموزش استفاده از پروتکل I2C در میکروکنترلر STM32

در باب اهمیت این موضوع هم باید بگوییم که میکروی STM32 قابلیت‌های زیادی دارد، حتی بیشتر از بوردهای آردوینو. بنابراین مهم است که بدانیم چگونه می‌توان به شیوه‌های مختلف آن را با بوردهای دیگر ارتباط داد. در این آموزش ارتباط I2C را بررسی می‌کنیم و در آموزش‌های آینده ساز و کار ارتباط SPI این میکرو را نیز توضیح خواهیم داد. پیش از ورود به این آموزش‌ها، اگر از قبل اطلاعات کافی درباره‌ی STM32 ندارید، پیشنهاد می‌کنیم آموزش‌های دیگری که قبلا درباره‌ی این میکرو ارائه داده‌ایم را ببینید.

نگاهی به قابلیت I2C در میکروی STM32

اگر بخواهیم قابلیت I2C در بورد blue pill را با بورد Arduino Uno مقایسه کنیم، اولین نکته‌ای که وجود دارد این است که بورد آردوینو از میکروکنترلر ATMEGA328 استفاده می‌کند و بورد STM32 یک هسته‌ی ARM Cortex-M3 در خود دارد. دومین تفاوت آنها این است که STM32 دارای دو عدد باس I2C است در حالی که بورد Arduino Uno فقط یک باس I2C دارد. به این دو دلیل ارتباط I2C در STM32 سریع‌تر از بورد Arduino است.

پین‌های مربوط به I2C در میکروی STM32

PB7 :SDA یا PB9 ،PB11

PB6 :SCL یا PB8 ،PB10

آموزش استفاده از پروتکل I2C در میکروکنترلر STM32

پین‌های مربوط به I2C در بورد آردوینو

 SDA: پین A4

SCL : پین A5

آموزش استفاده از پروتکل I2C در میکروکنترلر STM32

تجهیزات مورد نیاز برای انجام پروژه

  • STM32F103C8
  • بورد Arduino Uno
  • LED (۲ عدد)
  • کلید فشاری (۲ عدد)
  • مقاومت (۲ عدد 10K و ۲ عدد 2K)
  • برد بورد
  • سیم برد بوردی

نقشه‌ی مدار و بستن اتصالات

آموزش استفاده از پروتکل I2C در میکروکنترلر STM32

جدول زیر نحوه‌ی اتصالات بین بورد آردوینو و بورد میکروکنترلر STM32 را برای ارتباط I2C نشان می‌دهد. همان طور که می‌بینید این ارتباط تنها به دو سیم نیاز دارد و بسیار ساده است.

آموزش استفاده از پروتکل I2C در میکروکنترلر STM32

دو نکته‌ی مهم:

  • فراموش نکنید که GND هر دو بورد را به یکدیگر و به زمین مدار متصل کنید.
  • مقاومت‌های 10K را به عنوان مقاومت پول دان در هر بورد به صورت جداگانه به کلید فشاری متصل کنید.

در این ارتباط STM32 را به عنوان Master و Arduino Uno را به عنوان Slave در نظر می‌گیریم. ضمنا به هر دو بورد، یک LED و یک کلید فشاری نیز متصل می‌کنیم که در ادامه کاربرد آنها را توضیح می‌دهیم.

مطلب پیشنهادی:  راه اندازی واحد DAC میکروکنترلر stm32f4xx  و تولید سیگنال سینوسی

می‌خواهیم با استفاده از یک ارتباط LED ،I2C متصل به بورد STM32 را از طریق کلید فشاری متصل به بورد آردوینو و LED متصل به آردوینو را از طریق کلید فشاری متصل به STM32 کنترل کنیم. در حقیقت مقادیر دیتاهای کنترلی از طریق پروتکل I2C به دو طرف ارسال می‌شوند.

پروگرم کردن STM32 برای ارتباط I2C

پروگرم کردن STM32 برای ارتباط I2C، درست مشابه همان برنامه‌ای است که برای بوردهای آردوینو در ارتباط I2C داشتیم. یعنی در اینجا نیز از همان کتابخانه‌ی wire.h استفاده می‌کنیم و نیازی هم نیست که از پروگرمر FTDI استفاده کنیم. بلکه می‌توانیم به راحتی این بورد را با استفاده از پورت USB و Arduino IDE پروگرم کنیم. آموزش این روش را در جلسات قبلی برای شما ارائه داده‌ایم و می‌توانید به آن مراجعه کنید.

کدی که برای این پروژه باید بنویسیم هم از دو بخش کد لازم برای بورد Master و کد لازم برای بورد Slave تشکیل می‌شود که هر دو را به طور کامل در انتهای جلسه برایتان قرار داده‌ایم. یک ویدئو هم از روند انجام پروژه در انتها موجود است که می‌توانید آن را نیز ببینید.

توضیحات کد در بخش مربوط به بورد STM32) Master)

خب؛ ببینیم که در این بخش از کد چه اتفاقاتی می‌افتد.

  1. در ابتدا برای استفاده از توابع مربوط به پروتکل I2C در میکروی STM32، باید کتابخانه‌های لازم یعنی wire و softwire را اضافه کنیم.
#include<Wire.h> 
#include<SoftWire.h>
  1. در بخش ()void setup:
  • یک ارتباط سریال را با بادریت ۹۶۰۰ آغاز می‌کنیم.
Serial.begin(9600);
  • ارتباط I2C را روی پین‌های B6 و B7 تنظیم می‌کنیم.
Wire.begin();
  1. در بخش ()void loop:
  • داده‌ی مورد نیاز را با استفاده از تابع ()requestFrom از بورد Slave دریافت می‌کنیم. ۸ آدرس Slave و ۱ نشان دهنده‌ی درخواست ۱ بایت داده است.
Wire.requestFrom(8,1);
  • داده‌ی دریافت شده با کمک تابع ()read خوانده می‌شود.
byte a = Wire.read();
  • با توجه به داده‌ی دریافت شده از Slave، و با استفاده از تابع digitalwrite در پین LED ،PA1 موجود در Master روشن یا خاموش می‌شود. از serial print هم استفاده می‌کنیم تا مقدار دریافت شده همزمان بر روی مانیتور سریال هم نمایش داده شود.
if (a==1) 
      { 
      digitalWrite(LED,HIGH);
      Serial.println("Master LED ON");
      }
    else
      {
      digitalWrite(LED,LOW);
      Serial.println("Master LED OFF");
      }
  • در مرحله‌ی بعد باید وضعیت پین PA0 که کلید فشاری بورد Master به آن متصل است را بخوانیم.
int pinvalue = digitalRead(buttonpin);
  • و سپس باید مقدار خوانده شده را به صورت یک مقدار دیجیتال به بورد Slave که در آدرس ۸ قرار دارد ارسال کنیم.
if(pinvalue==HIGH) 
    {
     x=1;

    } 
  else
  {
     x=0;

    }

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

توضیحات کد در بخش مربوط به بورد Arduino) Slave)

  1. ابتدا کتابخانه‌ی wire را اضافه می‌کنیم تا بتوانیم از ارتباط I2C استفاده کنیم.
#include<Wire.h>
  1. در بخش ()void setup:
  • یک ارتباط سریال را با بادریت ۹۶۰۰ آغاز می‌کنیم.
Serial.begin(9600);
  • سپس ارتباط I2C را آغاز می‌کنیم (پین‌های A4 و A5) و ۸ به عنوان Slave address.
 Wire.begin(8);
  • در این بخش تابع onReceive را فراخوانی می‌کنیم تا داده‌ی ارسال شده توسط Master را دریافت کنیم. از تابع Wire.onRequest هم برای زمانی استفاده می‌کنیم که Master منتظر دریافت داده از سوی Slave است.
Wire.onReceive(receiveEvent);       Wire.onRequest(requestEvent);
  1. در ادامه دو تابع داریم؛ یکی برای request event و دیگری برای receive event.
مطلب پیشنهادی:  معرفی CMSIS

برای request Event:

این تابع زمانی اجرا می‌شود که STM32 که Master است، از Slave درخواست داده کند. ورودی آن داده‌ی کلید فشاری بورد Slave است که براساس وضعیت آن، یک بایت (۱ یا ۰) را با استفاده از تابع ()Wire.write خوانده و برای آن ارسال می‌کند.

void requestEvent() 
  {
  int value = digitalRead(buttonpin);

  if (value == HIGH) 
  {
    x=1;
  }
  else
  {
   x=0;
  }
  Wire.write(x); 
}

برای Receive Event:

این تابع زمانی اجرا می‌شود که Master داده‌ای برای Slave که در آدرس ۸ قرار دارد ارسال کند. این تابع داده‌ی دریافت شده را در یک متغیر از نوع int ذخیره کرده و با استفاده از یک if logic، تصمیم‌گیری می‌کند که بر اساس مقدار این متغیر، LED را خاموش یا روشن کند. به این ترتیب که اگر ۱ باشد آن را روشن می‌کند و اگر ۰ باشد آن را خاموش می‌کند.

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);
}

خروجی پروژه

  1. اگر کلید فشاری متصل به بورد STM32) Master) را فشار دهیم، LED متصل به بورد Arduino) Slave) روشن می‌شود (led سفید رنگ).

آموزش استفاده از پروتکل I2C در میکروکنترلر STM32

  1. و برعکس؛ زمانی که کلید فشاری بورد Slave را بزنیم، LED متصل به بورد Master روشن خواهد شد (led قرمز رنگ) و اگر کلید را رها کنیم خاموش می‌شود.

آموزش استفاده از پروتکل I2C در میکروکنترلر STM32

  1. حتی می‌توانیم همزمان هر دو کلید را با هم فشار دهیم و خواهیم دید که تا زمانی که آنها را رها نکنیم، هر دو LED روشن می‌مانند.

آموزش استفاده از پروتکل I2C در میکروکنترلر STM32

بسیار خب، این تمام کاری بود که باید برای استفاده از پروتکل ارتباطی I2C در میکروی STM32 انجام بدهید. از این به بعد می‌توانید هر سنسور (یا هر قطعه‌ی دیگری) که از این پروتکل ارتباطی استفاده می‌کند را به راحتی به STM32 متصل کنید.

مطلب پیشنهادی:  مدولاسیون عرض پالس یا PWM در STM32 - کنترل سرعت فن DC

کد کامل پروژه و ویدئوی اجرای آن را در ادامه می‌بینید.

کد

Master STM32 Code
//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);
 }
} 


Slave Arduino Code
//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
}

}

ویدئو

امیدواریم آموزش «راه اندازی I2C در STM32» برایتان مفید واقع شده باشد. در ادامه پیشنهاد می‌کنیم دیگر آموزش‌های STM32 را نیز مطالعه کنید.

اگر این نوشته‌ برایتان مفید بود لطفا کامنت بنویسید.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *