برد STM

راه اندازی پروتکل I2C در میکروکنترلر STM32 با برد STM32F103C8T6

نوشته شده توسط علی زاهدی

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

 


معرفی پروتکل I2C


پروتکل Inter-Integrated Circuit یا به اختصار I2C یکی از محبوب ترین و قدرتمند ترین رابط های سریال  است. که برای ارتباط بین دو یا چند مدار مجتمع (Chip) طراحی شده است. این پروتکل در سال ۱۹۸۲ توسط شرکت Philips معرفی شد. این پروتکل همانند USART دارای ۲ سیم است. اما با استفاده از همین دو سیم میتوان ارتباط میان تعداد زیادی دستگاه را با استفاده از این پروتکل برقرار نمود. ارتباط بین دستگاه ها در این پروتکل همانند SPI به صورت Master و Slave است. البته این پروتکل بر خلاف SPI از یک سیستم دارای چند Master نیز پشتیبانی می‌کند. اما Master ها نمی‌توانند با یک دیگر ارتباط داشته باشند. و همچنین برای ارتباط با Slave ها بایستی به صورت نوبتی از خطوط باس استفاده کنند. هر دستگاه در رابط I2C دارای آدرس دستگاه خاصی برای تمایز بین دستگاه های دیگر موجود در همان رابط I2C است.

معرفی پروتکل I2C - دیجی اسپارک

 


سخت افزار I2C


همانطور که گفته شد این پروتکل برای ارسال و دریافت داده بین دستگاه مختلف از ۲ پایه استفاده می‌کند. این پایه ها عبارتند از SDA (Serial Data Line) که داده بر روی این خط جابجا میشود و SCL (Serial Clock Line) این پایه برای کلاک است. کلاک I2C توسط Master تولید می‌شود. درایو های I2C عموما به صورت “Open-drain” هستند. اوپن درین به نوعی خروجی گفته میشود که میتواند سطح ولتاژ خط باس را پایین بکشد (در بیشتر موارد به سمت صفر ولت یا همان زمین).

شناخت سخت افزار I2C - دیجی اسپارک

 

و یا در حالت دیگر میتواند خط باس را آزاد کرده تا اجازه دهد مقاومت Pull-up متصل به خط سطح ولتاژ را بالا بکشد. برای درک بهتر این موضوع به تصویر زیر توجه کنید.

Releasing the Bus

 


انتقال داده در I2C


در طول یک پالس ساعت SCL یک بیت داده ارسال می‌شود. هر بایت از ۸ بیت داده بر روی خط SDA تشکیل شده است. یک بایت ممکن است آدرس یکی از Slave ها، آدرس یک ثبات و یا داده نوشته شده و یا خوانده شده از Slave باشد. بین یک وضعیت شروع و پایان میتوان هر تعداد بایت داده را از Master به Slave منتقل کرد. داده ها بر روی خط SDA زمانی که پالس ساعت در سطح بالا (یک منطقی) نباید تغییراتی داشته باشند. زیرا تغییر داده در این حالت به عنوان دستورات کنترلی (وضعیت شروع/پایان) شناخته می‌شود.

وضعیت شروع و پایان I2C

اگر منطق خطوط باس را صفر و یک در نظر بگیریم. زمانی که خط SCL در سطح ۱ باشد و خط SDA یک تغییر ۱ به صفر داشته باشد. این تغییر به عنوان وضعیت شروع شناخته می‌شود. همچنین زمانی که خط SCL در سطح ۱ باشد و خط SDA یک تغییر ۰ به ۱ داشته باشد. این تغییر به منظور وضعیت پایان شناخته می‌شود.

انتقال داده در I2C - دیجی اسپارک

 

وضعیت شروع مجدد I2C

در I2C حالتی با نام “وضعیت شروع مجدد” وجود دارد که کمتر به آن توجه می‌شود. این حالت مشابه وضعیت شروع است. با این تفاوت که قبل از وضعیت پایان اتفاق می افتد. این وضعیت شروع مجدد زمانی مفید است که Master میخواهد ارتباط جدیدی را ایجاد کند. بدون این که وضعیت پایان را ارسال کند (ممکن است پس از ارسال شرط پایان خطوط باس توسط Master های دیگر اشغال شود).

وضعیت شروع مجدد I2C - دیجی اسپارک

 

ACK و NACK در I2C

در پروتکل I2C پس از ارسال هر بایت داده (از جمله بایت آدرس) بیت نهم تحت عنوان تایید گیرنده ارسال می‌شود. این بین دارای دو حالت، تایید داده ارسال شده ACK (Acknowledge) و عدم تایید داده ارسال شده NACK (Not Acknowledge) ارسال می‌شود. بیت ACK به گیرنده اجازه می دهد تا با فرستنده ارتباط برقرار کند و اعلام کند که داده با موفقیت دریافت شد و امکان ارسال داده دیگر وجود دارد. قبل از اینکه گیرنده بتواند ACK ارسال کند ، فرستنده باید خط SDA را آزاد کند. درصورتی که پس از ارسال هشت بیت داده در صورتی که گیرنده بتواند سطح خط SDA را پایین بکشد. یک ACK اتفاق افتاده است. در غیر این صورت انتقال داده متوقف می‌شود.

ACK و NACK در I2C - دیجی اسپارک

 

انتقال داده فقط در صورت آزاد بودن گذرگاه ممکن است آغاز شود. اگر بعد از یک وضعیت پایان هر دو خط SDA و SCL سطح ولتاژ بالا باشند ، یک باس آزاد در نظر گرفته می شود. روش انتقال داده از سمت Master به Slave به شرح زیر است.

  1. Master وضعیت شروع را به همراه آدرس Slave مورد نظر را ارسال می‌کند.
  2. Master داده ها را به سمت Slave ارسال می‌کند.
  3. Master انتقال داده را با ارسال یک وضعیت پایان خاتمه می‌دهد.

example i2c write to slave

در صورتی که Master قصد دریافت داده از سمت Slave را داشته باشد. روش انتقال داده به صورت زیر است.

  1. Master وضعیت شروع را به همراه آدرس Slave مورد نظر را ارسال می‌کند.
  2. Master ثبت درخواستی را برای خواندن به Slave ارسال می‌کند.
  3. Master داده را از Slave دریافت می‌کند.
  4. Master انتقال داده را با ارسال یک وضعیت پایان خاتمه می‌دهد.

example i2c read from slave

 


پیکربندی I2c در نرم‌افزار STM32Cube


برای راه اندازی I2C در STM32 ابتدا بایستی داخل نرم افزار STM32CubeMX پروژه جدیدی ایجاد کنید. در صورتی که با نحوه ساخت پروژه پروژه جدید داخل این نرم افزار آشنا نیستید. بخش اول آموزش میکروکنترلرهای STM32 را مطالعه کنید. سپس یکی از I2C های میکروکنترلر را انتخاب کرده و وارد بخش مربوط به I2C مورد نظر شوید. در بخش Mode گزینه I2C دارای ۴ حالت مختلف است. در این آموزش قصد داریم تا حالت I2C را توضیح دهیم. حالت های دیگر را در آموزش های آینده توضیح می‌دهیم. پس این گزینه را بر روی I2C تنظیم کنید.

پیکربندی I2c در نرم‌افزار STM32Cube - دیجی اسپارک

 

در بخش Configuration بخش Parameter Settings تنظیم سرعت و کلاک در اختیار شما قرار دارد. در صورتی که قصد راه اندازی ماژول خاصی را دارید با توجه به دیتاشیت ماژول این بخش را تنظیم کنید. اما در صورتی که قصد تنظیم میکروکنترلر به عنوان Slave را داشته باشید. تنظیمات بیشتر در اختیار شما قرار خواهد گرفت.

پیکربندی I2c در نرم‌افزار STM32Cube - دیجی اسپارک

سپس از صفحه Clock Configuration فرکانس کاری میکروکنترلر را به دلخواه تنظیم کنید. سپس وارد صفحه ی Project Manager شوید. پس از انتخاب نام و IDE برای پروژه بر روی CODE GENERATE کلیک کرده و وارد نرم افزار KEIL شوید.

 


 کدنویسی با استفاده از توابع HAL


برای راه اندازی I2C در STM32 میکروکنترلر های STM32 کتابخانه HAL توابع مختلفی را به شما ارائه میدهد. از جمله توابع پر کاربرد HAL_I2C عبارتند از؛

HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout)
HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout)

 

  • HAL_I2C_Master_Transmit

همانطور که از اسم تابع مشخص است. این تابع برای ارسال داده از سمت Master است. این تابع دارای ۵ ورودی است. در ورودی اول بایستی I2c فعال شده را قرار دهید. در ورودی دوم بایستی آدرس ۷ بیتی مربوط به Slave مرود نظر را قرار دهید. در ورودی سوم داده ای که قصد ارسال آن را دارید را قرار دهید. در ورودی چهارم بایستی سایز داده ارسالی را قرار دهید. در ورودی آخر بایستی حداکثر زمان مورد نظر برای ارسال داده قرار گیرد. برای درک بهتر این مطلب به مثال زیر توجه کنید (برای مثال فرض کنید آدرس Slave مورد نظر برابر است با ۰xD6).

uint8_t data[9]={"Digispark"};
HAL_I2C_Master_Transmit(&hi2c1,0xD6,data,9,100);

 

  • HAL_I2C_Master_Receive

این تابع زمانی استفاده می‌شود که Master قصد دریافت داده از یکی از Slave ها را داشته باشد. این تابع نیز همانند تابع HAL_I2C_Master_Transmit دارای ۵ ورودی است. تمام ورودی های این تابع نیز مشابه تابع HAL_I2C_Master_Transmit است. با این تفاوت که در ورودی سوم  بایستی بجای پوینتر pData* رشته مربوط به دریافت را قرار دهید. توجه داشته باشید که در بسیاری از ماژول ها زمانی که قصد داشته باشید داده ای از Slave دریافت کنید. ابتدا بایستی درخواست ارسال داده از سمت Slave را برای آن ارسال کنید. سپس عملیات دریافت را انتجام دهید.

uint8_t data[2];
HAL_I2C_Master_Receive(&hi2c1,0xd6,data,2,100);

 

توابع مربوط به Slave نیز همانند توابع Master هستند. با این تفاوت که بخش آدرس در آن قرار ندارد.

 


جمع بندی


در این آموزش ابتدا به معرفی I2C در STM32 و تاریخچه آن پرداخیتم. سپس با شباهت و تفاوت های I2C با دیگر ارتباط های سریال آشنا شدیم. در ادامه سخت افزار I2C در STM32 مورد بررسی قرار گرفت و مقاومت Pull-up مورد نیاز برای باس I2C معرفی شد. سپس در بخش انتقال داده در I2C قالب انتقال داده در پروتکل I2C مورد بررسی قرار گرفته و بخش های مختلف آن معرفی شد. پس از آن نحوه پیکربندی و تنظیمات مورد نیاز برای پیکربندی I2C در نرم افزار STM32CubeMX گفته شد. در آخر توابع HAL پر کاربرد مربوط به I2C معرفی شد.

 


لوازم مورد نیاز


 

چنانچه در مراحل راه اندازی و انجام این پروژه با مشکل مواجه شدید، بدون هیچ نگرانی در انتهای همین پست، به صورت ثبت نظر سوالتان را مطرح کنید. من در سریع‌ترین زمان ممکن پاسخ رفع مشکل شما را خواهم داد. همچنین اگر ایرادی در کدها و یا مراحل اجرایی وجود دارند می‌توانید از همین طریق اطلاع رسانی کنید.

 

در پایان نظرات و پیشنهادات خود را با ما درمیان بگذارید و با اشتراک گذاری این آموزش در شبکه های اجتماعی از وبسایت دیجی اسپارک حمایت کنید.

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

علی زاهدی

برنامه نویس و طراح سیستم های مبتنی بر میکروکنترلر

دانسته هایتان را مانند یک ساعت مچی در دست کنید، نه صرفا به این خاطر که نشان دهید آن را دارید. بلکه به این خاطر که اگر کسی از شما ساعت را پرسید، برایش بگویید.
لرد چسترفیلد

تبادل نظر و رفع عیب با ثبت دیدگاه

۱۳ دیدگاه

  • سلام، من میخواهم با ماژول mlx90614 که با پروتکل i2c کار میکنه با stm32f103t6c8 ارتباط برقرار کنم، از دو تابع هال فوق یعنی master transmit و master receive استفاده کردم اما جواب نمیده، راستش دقیقاً نمیدونم اصلاً ارتباط برقرار هست یا نه، چجوری باید بفهمم؟

    • با سلام
      بنظرم برای راه اندازی سنسور هایی مانند mlx90614 بهتر است به از کتابخانه های موجود استفاده کنید. یا درصورتی که قصد دارید کتابخانه خود را بنویسید نگاهی به کتابخانه های موجود برای این ماژول بیاندازید. تا با نحوه کتابخانه نویسی برای این ماژول آشنا شوید. لینک زیر کتابخانه ای برای راه اندازی این ماژول است لطفا لینک زیر را بررسی نمایید.

      https://github.com/dinamitemic/mlx90614

    • با سلام
      اگر از ماژول یا سنسوری استفاده می‌کنید که از پروتکل I2C برای برقراری ارتباط با میکروکنترلر استفاده می‌کند. بایستی دیتاشیت این سنسور را بررسی کنید. عموما آدرس Slave در دیتاشیت قطعه قرار دارد.

  • سلام.وقت بخیر.فکر میکنم یجایی رو اشتباه شدین.در طول یک پالس ساعت یک بیت منتقل می شود نه یک بایت.لطفا اصلاحش کنین که بقیه دچار اشتباه نشن

  • سلام ، ارادت ، ممنون از مطالب مفیدتون
    قربان چطور میشه دو میکرو از همین میکرویی ک فرمودین رو به هم وصل کرد با همین پروتکل؟
    ینی ادرس اسلیو همین میکرو چیه؟

    • با سلام از توجه شما سپاسگزارم
      در نرم افزار CubeMX زمانی که I2C میکروکنترلر را فعال میکند. میتوانید تنظیمات مربوط به Master و Slave بودن میکروکنترلر را نیز کنترل کنید. تنظیمات ادرس Slave نیز در این قسمت انجام می‌شود.

  • سلام من با این میکرو سعی دارم روی at24c512 اطلاعات رو ذخیره کنم از دستور
    HAL_I2C_Mem_Write(&hi2c1, 0XA0, 40000,I2C_MEMADD_SIZE_16BIT , &write_data, 1, 100)
    استفاده می کنم می خوام روی خونه ی ۴۰۰۰۰ مقدار write_data را قرار دهم ولی آدرس حافظه را با این که ۱۶ بیت مشخص می کنم ولی همواره به صورت ۸ بیت ارسال می شود به همین خاطر فقط تا خونه ی ۲۵۵ قابل استفاده است چی کار باید بکنم؟
    چون از ماژول استفاده کردم از سخت افزاری که هست مطمعنم

    • با سلام
      کتابخانه هایی از قبل برای راه اندازی این آیسی نوشته شده است. که با یک سرچ ساده در سایت github.com میتوانید کتابخنه مورد نظر خود را پیدا کنید.

  • سلام عرض ادب
    بنده stm32f103c8 رو با بورد arduino mega 2560 توسط i2c ارتباط دادم و داده ها راحت جابجا شد،
    stm رو یکبار master و یکبار slave کردم و موردی نداشتم
    اما وقتی ۲ عدد stm رو با هم ارتباط میدم هیچ دیتایی ندارم
    آیا تنظیم خاص سخت افزاری و یا نرم افزاری وجود داره که من فراموش کردم ؟
    ممنون میشم راهنمایی بفرمایید