در آموزشهای گذشته، در مورد پروتکلهای ارتباطی SPI و I2C و نحوهی استفاده از آنها برای برقرار کردن ارتباط بین دو بورد آردوینو صحبت کردهایم. در این جلسه میخواهیم یکی از بوردهای آردوینو را با بورد Blue Pill که بورد مخصوص میکروکنترلر STM32 است جایگزین کنیم و با استفاده از SPI Bus بین این میکروکنترلر و بورد آردوینو ارتباط برقرار کنیم.
در این پروژه، بورد Arduino Uno را به عنوان Slave و بورد Blue Pill را به عنوان Maser ارتباط سریال قرار میدهیم. به هر کدام از این دو بورد هم یک نمایشگر LCD 16×2 متصل میکنیم. دو عدد پتانسیومتر را نیز به ترتیب به پینهای PA0 و A0 میکروکنترلر STM32 و بورد Arduino متصل میکنیم. با استفاده از این دو پتانسیومتر، میتوانیم مقادیری بین صفر تا ۲۵۵ را از Master به Slave و یا برعکس ارسال کنیم.
پروتکل SPI در میکروکنترلر STM32
اگر بخواهیم SPI Bus این میکروکنترلر را با SPI Bus بورد آردوینو مقایسه کنیم، این میکروکنترلر دارای دو عدد SPI Bus است حال آنکه به عنوان مثال بوردی مانند Arduino Uno دارای یک SPI Bus است. در بورد Arduino Uno از میکروکنترلر ATMEGA328 استفاده میشود؛ در حالیکه STM32 از ARM Cortex- M3 استفاده میکند. بنابراین STM32 سرعت به مراتب بالاتری دارد.
پینهای مربوط به SPI در میکرکنترلر STM32
پینهای مربوط به SPI در بورد آردوینو
تجهیزات مورد نیاز برای انجام پروژه
- میکروکنترلر STM32F103C8
- بورد Arduino UNO
- دو عدد LCD 16×2
- چهار عدد پتانسیومتر 10K
- برد بورد
- سیم برد بوردی
نمودار مدار و اتصالات
در جدول زیر اتصالات بین STM32 و Arduino UNO را به منظور ارتباط SPI میبینیم.
و این جدول اتصال بین LCDها را به هر کدام از دو بورد میکروکنترلر و آردوینو نشان میدهد.
نکتهی مهم: فراموش نکنید که باید زمین (GND) میکرو و آردوینو را به یکدیگر و به زمین مدار متصل کنید.
پروگرم کردن STM32 برای ارتباط SPI
پروگرم کردن STM32 به منظور این ارتباط، تقریبا مشابه پروگرم کردن بوردهای آردوینو به همین منظور است. بنابراین اگر قبلا آن را در آموزشهای قبلی همراه با ما انجام داده باشید، در اینجا دیگر چالش چندانی نخواهید داشت.
در اینجا هم باید از کتابخانهی SPI.h استفاده کنیم و میتوانیم میکرو را بدون استفاده از پروگرمر FTDI و با استفاده از پورت USB پروگرم کنیم. آموزش این نحوهی پروگرم کردن STM32 را نیز در جلسات قبلی داشتهایم. در صورتی که با آن آشنایی ندارید؛ حتما به آموزش لینک زیر مراجعه کنید.
- مطلب مرتبط مفید: پروگرم کردن بورد STM32F103C8 با استفاده از USB port
همانطور که در ابتدا هم توضیح دادیم، در این پروژه قصد داریم بورد Arduino Uno را به عنوان Slave و بورد Blue Pill را به عنوان Maser ارتباط سریال انتخاب کنیم. هر کدام از این دو بورد را هم به یک نمایشگر LCD 16×2 متصل میکنیم. دو عدد پتانسیومتر را نیز به ترتیب به پینهای PA0 و A0 میکروکنترلر STM32 و بورد Arduino متصل میکنیم تا با استفاده از آنها، مقادیری بین صفر تا ۲۵۵ را از Master به Slave و یا برعکس ارسال کنیم.
پین PA0 میکروکنترلر STM32، مقادیر آنالوگ ولتاژ را از پتانسیومتر دریافت میکند (این مقادیر بین صفر تا ۳.۳ ولت هستند) این مقادیر با استفاده از مبدل آنالوگ به دیجیتال درون میکروکنترلر به مقادیر دیجیتال در بازهی صفر تا ۴۰۹۶ تبدیل میشوند و پس از آن نیز توسط نگاشت دیگری به بازهی صفر تا ۲۵۵ میروند. بنابراین ما در ارتباط SPI، در هر بار ارسال یا دریافت داده، حداکثر میتوانیم ۸ بیت (۱ بایت) را انتقال دهیم.
به طور مشابه در سمت Slave یعنی بورد آردوینو نیز، مقادیر آنالوگ از پتانسیومتر توسط پین A0 دریافت میشوند (بین صفر تا ۵ ولت) و توسط مبدل آنالوگ به دیجیتال این بورد، به مقادیر دیجیتال در بازهی صفر تا ۱۰۲۳ برده میشوند. سپس نگاشت دیگری این مقادیر را به بازهی صفر تا ۲۵۵ نظیر میکند.
در ادامه، کدهای هر کدام از دو بخش Master و Slave را جداگانه بررسی میکنیم. کد کامل پروژه که شامل کدهای هر دو بخش است و نیز ویدئوی نمونه از اجرای پروژه را در انتهای جلسه در دسترستان قرار دادهایم.
پروگرم کردن بخش (Master(STM32 برای ارتباط SPI
- برای استفاده از توابع مربوط به پروتکل SPI و توابع مربوط به اتصال LCD، ابتدا باید کتابخانههای h و LiquidCrystal.h را اضافه کنیم. پینهای مربوط به اتصال LCD را نیز تعریف میکنیم.
#include<SPI.h> #include<LiquidCrystal.h> const int rs = PB0, en = PB1, d4 = PB10 , d5 = PB11 , d6 = PC13, d7 = PC14; LiquidCrystal lcd(rs,en,d4,d5,d6,d7);
- در بخش ()void setup:
- یک ارتباط سریال را با بادریت ۹۶۰۰ شروع میکنیم.
Serial.begin(9600);
- سپس ارتباط SPI را آغاز میکنیم.
SPI.begin();
- سپس Clock divider را برای SPI تنظیم میکنیم. ما در اینجا آن را بر روی ۱۶ تنظیم کردهایم.
SPI.setClockDivider(SPI_CLOCK_DIV16);
- سپس پین SS را در وضعیت HIGH قرار میدهیم چرا که هنوز هیچ مبادلهای را با Slave نداشتهایم.
digitalWrite(SS,HIGH);
- در بخش ()void loop:
- قبل از ارسال هر دادهای به Slave، ابتدا باید select value آن را در وضعیت LOW قرار دهیم. به این ترتیب میتوانیم مبادلهای را از سوی Master به سمت Slave آغاز کنیم.
digitalWrite(SS, LOW);
- سپس مقدار آنالوگ دریافت شده از پتانسیومتر را از پین PA0 میخوانیم.
int pot = analogRead(PA0);
مقدار دریافت شده را سپس به یک بایت در بازهی صفر تا ۲۵۵ تبدیل میکنیم.
byte MasterSend = map(pot,0,4096,0,255);
- این مرحله مهمترین قدم این ارتباط است. در این قسمت از کد، دادهی حاصل شده را که در متغیر Mastersend ذخیره کردهایم برای Slave ارسال میکنیم و دادهی دریافت شده از Slave را در متغیر mastereceive ذخیره میکنیم.
Mastereceive = SPI.transfer(Mastersend);
- مقادیر دریافت شده از Slave را با تاخیرهای ۵۰۰ نانوثانیه بر روی LCD متصل به میکرو نمایش میدهیم.
Serial.println("Slave Arduino to Master STM32"); Serial.println(MasterReceive lcd.setCursor(0,0); lcd.print("Master: STM32"); lcd.setCursor(0,1); lcd.print("SalveVal:"); lcd.print(MasterReceive delay(500); digitalWrite(SS, HIGH);
نکته: تابع ()serial.println به این علت استفاده میکنیم که مقادیر دریافتی را همزمان بر روی serial monitor در Arduino IDE هم نمایش دهیم.
پروگرم کردن بخش (Slave (Arduino UNO برای ارتباط SPI
- مشابه طرف Master، در این طرف هم ابتدا برای استفاده از توابع مربوط به پروتکل SPI و توابع مربوط به اتصال LCD، ابتدا باید کتابخانههای h و LiquidCrystal.h را اضافه کنیم. پینهای مربوط به اتصال LCD را نیز تعریف میکنیم.
#include<SPI.h> #include<LiquidCrystal.h> LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // Define LCD Module Pins (RS,EN,D4,D5,D6,D7)
- در بخش ()void setup:
- یک ارتباط سریال را با بادریت ۹۶۰۰ شروع میکنیم.
Serial.begin(9600);
- در این بخش MISO را به عنوان خروجی (OUTPUT) تعیین میکنیم. (برای ارسال داده به IN در سمت Master) بنابراین دادههای Arduino از MISO ارسال میشوند.
pinMode(MISO,OUTPUT);
- سپس با استفاده از SPI Control Register، ارتباط SPI را در مود Slave آغاز میکنیم.
SPCR |= _BV(SPE);
- وقفههای (interrupt) ارتباط SPI را فعال میکنیم. با این کار اگر دادهای از جانب Master ارسال شود، Interrupt Service Routine فراخوانی شده و دادهی مربوطه از SPDR (رجیستر دادهی مربوط به ارتباط SPI) دریافت میشود.
SPI.attachInterrupt();
- دادهی دریافت شده توسط SPDR، در متغیر Slavereceived ذخیره میشود. این ذخیرهسازی به وسیلهی این دستور در کد انجام میشود.
ISR (SPI_STC_vect) { Slavereceived = SPDR; received = true; }
- در بخش ()void loop:
- مقدار آنالوگ را از پین A0 بورد آردوینو میخوانیم.
int pot = analogRead(A0);
- داده را تبدیل به یک بایت (از صفر تا ۲۵۵) میکنیم.
Slavesend = map(pot,0,1023,0,255);
- مهمترین قدم این بخش است که باید داده را برای Master ارسال کنیم. برای این کار ابتدا باید آن را در رجیستر SPDR قرار دهیم. این رجیستر هم در ارسال و هم در دریافت دادهها مورد استفاده قرار میگیرد.
SPDR = Slavesend;
- در مرحلهی بعد مقادیر دریافت شده از Master را (که در رجیستر SlaveReceive قرار دارند) بر روی LCD نمایش میدهیم. در اینجا هم مقادیر را با تاخیر ۵۰۰ نانوثانیهای نمایش میدهیم.
lcd.setCursor(0,0); lcd.print("Slave: Arduino"); lcd.setCursor(0,1); lcd.print("MasterVal:"); Serial.println("Master STM32 to Slave Arduino"); Serial.println(SlaveReceived); lcd.print(SlaveReceived); delay(500);
حال اگر پتانسیومتر یکی از دو سمت را بچرخانید، میبینید که در سمت دیگر، مقادیر نشان داده شده بر روی LCD تغییر خواهند کرد.
بسیار خب! تمام شد. به همین سادگی! این پروژه تمام چیزی بود که در مورد نحوهی استفاده از پروتکل SPI در میکروی STM32 لازم بود یاد بگیرید. حالا میتوانید هر دیوایس دیگری را هم با این پروتکل به STM32 متصل کنید.
کد کامل پروژه شامل قسمتهای ارتباط Master و Slave را میتوانید در ادامه ببینید. همچنین یک ویدئو نیز از اجرای این پروژه قرار داده شده است که در صورت علاقهمندی میتوانید آن را نیز ببینید.
کد
Master STM32 SPI //SPI Master code for STM32F103C8 //SPI Communication between STM32 & Arduino //Circuit Digest
// Melec.ir
#include<SPI.h> // Including Library for using SPI Communication #define SS PA4 #include<LiquidCrystal.h> // Including LCD display library const int rs = PB0, en = PB1, d4 = PB10 , d5 = PB11 , d6 = PC13, d7 = PC14; // Declaring pin names and pin numbers of lcd LiquidCrystal lcd(rs,en,d4,d5,d6,d7); // Setting lcd and its paramaters void setup (void) { lcd.begin(16,2); // Setting lcd as 16x2 mode lcd.setCursor(0,0); // Setting cursor at first row and first column lcd.print("CIRCUIT DIGEST"); // Puts CIRCUIT DIGEST in LCD delay(3000); // Delays for 3 seconds lcd.clear(); // Clears lcd display Serial.begin(9600); // Starts Serial Communication at Baud Rate 9600 pinMode(SS,OUTPUT); // Puts SS as Output SPI.begin(); // Begins the SPI commnuication SPI.setClockDivider(SPI_CLOCK_DIV16); // Sets clock for SPI communication at 16 (72/16=4.5Mhz) digitalWrite(SS,HIGH); // Setting SlaveSelect as HIGH (So master doesnt connnect with slave) } void loop(void) { byte MasterSend,MasterReceive; int pot = analogRead(PA0); // Analog read the input pot value at pin PA0 MasterSend = map(pot,0,4096,0,255); // Used to convert pot value in terms of 0 to 255 from 0 to 4096 digitalWrite(SS, LOW); // Starts communication with Slave connected to master MasterReceive=SPI.transfer(MasterSend); // Send the mastersend value to slave also receives value from slave Serial.println("Slave Arduino to Master STM32"); // Used in Serial Monitor Serial.println(MasterReceive); // Puts value Received im Serail Monitor lcd.setCursor(0,0); lcd.print("Master: STM32"); lcd.setCursor(0,1); lcd.print("SalveVal:"); lcd.print(MasterReceive); // Puts the received value from slave arduino delay(500); digitalWrite(SS, HIGH); // Again make SS line HIGH so that it doesnt communicate with Slave lcd.clear(); } Slave Arduino SPI //SPI Slave Code for Arduino //SPI Communication between STM32F103C8 & Arduino //Circuit Digest #include<SPI.h> // Including Library for using SPI Communication #include<LiquidCrystal.h> // Including LCD display library LiquidCrystal lcd(2, 3, 4, 5, 6, 7); // Define LCD Module Pins (RS,EN,D4,D5,D6,D7) volatile boolean received; volatile byte SlaveReceived,Slavesend; void setup() { lcd.begin(16,2); // Initilize LCD display lcd.setCursor(0,0); // Sets Cursor at first line of Display lcd.print("CIRCUIT DIGEST"); // Prints CIRCUIT DIGEST in LCD delay(3000); // Delay for 3 seconds lcd.clear(); // Clears LCD display Serial.begin(9600); // Starts Serial Communication at Baud Rate 9600 pinMode(MISO,OUTPUT); // Sets MISO as OUTPUT (Have to Send data to Master IN (STM32F103C8) SPCR |= _BV(SPE); // Turn on SPI in Slave Mode received = false; SPI.attachInterrupt(); // Interuupt ON is set for SPI commnucation } ISR (SPI_STC_vect) // Inerrrput routine function { SlaveReceived = SPDR; // Value received from master STM32F103C8 is stored in variable slavereceived received = true; // Sets received as True } void loop() { int pot = analogRead(A0); // Analog read the input pot value from analog pin A0 Slavesend = map(pot,0,1023,0,255); // Converts the value pot (0-1023) to (0-255) for sending to master stm32 SPDR = Slavesend; // Sends the salvesend value to master STM32F103C8 via SPDR lcd.setCursor(0,0); lcd.print("Slave: Arduino"); lcd.setCursor(0,1); lcd.print("MasterVal:"); Serial.println("Master STM32 to Slave Arduino"); Serial.println(SlaveReceived); // Puts the received value from Master STM32F103C8 at Serial Monitor lcd.print(SlaveReceived); // Puts the received value from Master STM32F103C8 at LCD display delay(500); lcd.clear(); }
ویدئو
- منبع: ترجمه از سایت circuitdigest.com
امیدواریم این مطلب آموزشی براتون مفید واقع شده باشه. دیگر آموزشهای STM32 را هم مطالعه کنید.
اگر این نوشته برایتان مفید بود لطفا کامنت بنویسید.
فقط بلدین چرت و پرت کپی کنید، این پروژه رو سایت ایرنکس هم گذاشته، فقط بدرد خودتون میخوره