پیش از این آموزش های مختلفی برای میکروکنترلرهای 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
همانطور که گفته شد این پروتکل برای ارسال و دریافت داده بین دستگاه مختلف از ۲ پایه استفاده میکند. این پایه ها عبارتند از SDA (Serial Data Line) که داده بر روی این خط جابجا میشود و SCL (Serial Clock Line) این پایه برای کلاک است. کلاک I2C توسط Master تولید میشود. درایو های I2C عموما به صورت “Open-drain” هستند. اوپن درین به نوعی خروجی گفته میشود که میتواند سطح ولتاژ خط باس را پایین بکشد (در بیشتر موارد به سمت صفر ولت یا همان زمین).
و یا در حالت دیگر میتواند خط باس را آزاد کرده تا اجازه دهد مقاومت Pull-up متصل به خط سطح ولتاژ را بالا بکشد. برای درک بهتر این موضوع به تصویر زیر توجه کنید.
انتقال داده در I2C
در طول یک پالس ساعت SCL یک بیت داده ارسال میشود. هر بایت از ۸ بیت داده بر روی خط SDA تشکیل شده است. یک بایت ممکن است آدرس یکی از Slave ها، آدرس یک ثبات و یا داده نوشته شده و یا خوانده شده از Slave باشد. بین یک وضعیت شروع و پایان میتوان هر تعداد بایت داده را از Master به Slave منتقل کرد. داده ها بر روی خط SDA زمانی که پالس ساعت در سطح بالا (یک منطقی) نباید تغییراتی داشته باشند. زیرا تغییر داده در این حالت به عنوان دستورات کنترلی (وضعیت شروع/پایان) شناخته میشود.
وضعیت شروع و پایان I2C
اگر منطق خطوط باس را صفر و یک در نظر بگیریم. زمانی که خط SCL در سطح ۱ باشد و خط SDA یک تغییر ۱ به صفر داشته باشد. این تغییر به عنوان وضعیت شروع شناخته میشود. همچنین زمانی که خط SCL در سطح ۱ باشد و خط SDA یک تغییر ۰ به ۱ داشته باشد. این تغییر به منظور وضعیت پایان شناخته میشود.
وضعیت شروع مجدد I2C
در I2C حالتی با نام “وضعیت شروع مجدد” وجود دارد که کمتر به آن توجه میشود. این حالت مشابه وضعیت شروع است. با این تفاوت که قبل از وضعیت پایان اتفاق می افتد. این وضعیت شروع مجدد زمانی مفید است که Master میخواهد ارتباط جدیدی را ایجاد کند. بدون این که وضعیت پایان را ارسال کند (ممکن است پس از ارسال شرط پایان خطوط باس توسط Master های دیگر اشغال شود).
ACK و NACK در I2C
در پروتکل I2C پس از ارسال هر بایت داده (از جمله بایت آدرس) بیت نهم تحت عنوان تایید گیرنده ارسال میشود. این بین دارای دو حالت، تایید داده ارسال شده ACK (Acknowledge) و عدم تایید داده ارسال شده NACK (Not Acknowledge) ارسال میشود. بیت ACK به گیرنده اجازه می دهد تا با فرستنده ارتباط برقرار کند و اعلام کند که داده با موفقیت دریافت شد و امکان ارسال داده دیگر وجود دارد. قبل از اینکه گیرنده بتواند ACK ارسال کند ، فرستنده باید خط SDA را آزاد کند. درصورتی که پس از ارسال هشت بیت داده در صورتی که گیرنده بتواند سطح خط SDA را پایین بکشد. یک ACK اتفاق افتاده است. در غیر این صورت انتقال داده متوقف میشود.
انتقال داده فقط در صورت آزاد بودن گذرگاه ممکن است آغاز شود. اگر بعد از یک وضعیت پایان هر دو خط SDA و SCL سطح ولتاژ بالا باشند ، یک باس آزاد در نظر گرفته می شود. روش انتقال داده از سمت Master به Slave به شرح زیر است.
- Master وضعیت شروع را به همراه آدرس Slave مورد نظر را ارسال میکند.
- Master داده ها را به سمت Slave ارسال میکند.
- Master انتقال داده را با ارسال یک وضعیت پایان خاتمه میدهد.
در صورتی که Master قصد دریافت داده از سمت Slave را داشته باشد. روش انتقال داده به صورت زیر است.
- Master وضعیت شروع را به همراه آدرس Slave مورد نظر را ارسال میکند.
- Master ثبت درخواستی را برای خواندن به Slave ارسال میکند.
- Master داده را از Slave دریافت میکند.
- Master انتقال داده را با ارسال یک وضعیت پایان خاتمه میدهد.
پیکربندی I2c در نرمافزار STM32Cube
برای راه اندازی I2C در STM32 ابتدا بایستی داخل نرم افزار STM32CubeMX پروژه جدیدی ایجاد کنید. در صورتی که با نحوه ساخت پروژه پروژه جدید داخل این نرم افزار آشنا نیستید. بخش اول آموزش میکروکنترلرهای STM32 را مطالعه کنید. سپس یکی از I2C های میکروکنترلر را انتخاب کرده و وارد بخش مربوط به I2C مورد نظر شوید. در بخش Mode گزینه I2C دارای ۴ حالت مختلف است. در این آموزش قصد داریم تا حالت I2C را توضیح دهیم. حالت های دیگر را در آموزش های آینده توضیح میدهیم. پس این گزینه را بر روی I2C تنظیم کنید.
در بخش Configuration بخش Parameter Settings تنظیم سرعت و کلاک در اختیار شما قرار دارد. در صورتی که قصد راه اندازی ماژول خاصی را دارید با توجه به دیتاشیت ماژول این بخش را تنظیم کنید. اما در صورتی که قصد تنظیم میکروکنترلر به عنوان Slave را داشته باشید. تنظیمات بیشتر در اختیار شما قرار خواهد گرفت.
سپس از صفحه 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
سلام آدرس slav چجوری پیدا کنم ممنون
با سلام
اگر از ماژول یا سنسوری استفاده میکنید که از پروتکل 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 را قرار دهم ولی آدرس حافظه را با این که ۱۶ بیت مشخص می کنم ولی همواره به صورت ۸ بیت ارسال می شود به همین خاطر فقط تا خونه ی ۲۵۵ قابل استفاده است چی کار باید بکنم؟
چون از ماژول استفاده کردم از سخت افزاری که هست مطمعنم
با سلام
پیشنهاد میکنم لینک زیر را بررسی کنید.
https://github.com/Majid-Derhambakhsh/i2c-eeprom
با سلام و عرض ادب
آیا با این مثالی که زدید میشود آی سی AT24C02 را راه اندازی کرد؟
با سلام
کتابخانه هایی از قبل برای راه اندازی این آیسی نوشته شده است. که با یک سرچ ساده در سایت github.com میتوانید کتابخنه مورد نظر خود را پیدا کنید.
سلام عرض ادب
بنده stm32f103c8 رو با بورد arduino mega 2560 توسط i2c ارتباط دادم و داده ها راحت جابجا شد،
stm رو یکبار master و یکبار slave کردم و موردی نداشتم
اما وقتی ۲ عدد stm رو با هم ارتباط میدم هیچ دیتایی ندارم
آیا تنظیم خاص سخت افزاری و یا نرم افزاری وجود داره که من فراموش کردم ؟
ممنون میشم راهنمایی بفرمایید