سیسوگ در قسمت بیستم و سوم آموزش میکروکنترلر STM8 به بررسی رابط سریال (SPI) پرداخت. در این از قسمت آموزش میکروکنترلر STM8 قصد دارد I2C را مورد بررسی قرار دهد. با سیسوگ همراه باشید.
I2C یکی دیگر از روشهای ارتباطی محبوب در ارتباطات سریال سنکرون است که توسط NXP توسعه یافته است. فقط از دو سیم برای ارتباط استفاده میکند و به همین ترتیب، رابط دو سیم (TWI) نامیده میشود. درست مانند SPI، رابط I2C به طور گسترده در ارتباط با ساعتهای زمان واقعی (RTC)، سنسورهای دیجیتال، تراشههای حافظه و غیره استفاده میشود. این ویژگیها با SPI مشترک هستند. اما در مقایسه با SPI، آن را کندتر و محدودتر میکند. تا 127 دستگاه میتواند در یک باسI2C همکاری کند.
ارتباط I2C بین دستگاههایی که سطح ولتاژمنطقی متفاوتی دارند امکانپذیر نمیباشد.
در I2C دو سیم ارتباطی بطور مستقیم به هم وصل میشوند یعنی SDA به SDA و SCL به SCL.
باس I2C نیز مانند SPI، دارای یک میکروکنترلر مستر و یک یا چند Slave است. میکروکنترلر مستر مسئولیت ایجاد سیگنالهای ساعت و برقراری ارتباط را بر عهده دارد. زمانیکه مستر شناسه Slave را با دستور خواندن / نوشتن ارسال کند ارتباط برقرار میشود. Slave با پردازش درخواست مستر و ارسال داده به این فرمان پاسخ میدهد.
اگر تمایل دارید اطلاعات بیشتری درباره باس I2C بدست آورید لینکهای زیر مناسب هستند:
پروتکل های دیگر مانند SMBus و I2S شباهتهای بسیاری با I2C دارند، بنابراین با یادگیریI2C میتوانید با دیگر پروتکلها نیز ارتباط برقرار کنید.
اتصالات سختافزاری
نمونه کد I2C
این کد نشان میدهد، چگونه ارتباط سنسور نور دیجیتال BH1750 I2C را با STM8 برقرار کنیم. LCD نیز برای نمایش خروجی سنسور نور در لوکس استفاده میشود.
main.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | #include "STM8S.h" #include "BH1750.h" #include "stm8s_lcd.h" void delay_ms(uint16_t ms); void clock_setup(void); void GPIO_setup(void); void I2C_setup(void); void lcd_print(unsigned char x_pos, unsigned char y_pos, unsigned int value); void main() { unsigned int LX = 0x0000; unsigned int tmp = 0x0000; clock_setup(); GPIO_setup(); I2C_setup(); LCD_init(); BH1750_init(); LCD_clear_home(); LCD_goto(0, 0); LCD_putstr("STM8 I2C"); LCD_goto(0, 1); LCD_putstr("Lx"); delay_ms(10); while(TRUE) { tmp = get_lux_value(cont_L_res_mode, 20); if(tmp > 10) { LX = tmp; } else { LX = get_lux_value(cont_H_res_mode1, 140); } lcd_print(3, 1, LX); delay_ms(200); }; } void clock_setup(void) { CLK_DeInit(); CLK_HSECmd(DISABLE); CLK_LSICmd(DISABLE); CLK_HSICmd(ENABLE); while(CLK_GetFlagStatus(CLK_FLAG_HSIRDY) == FALSE); CLK_ClockSwitchCmd(ENABLE); CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV2); CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, DISABLE); } void GPIO_setup(void) { GPIO_DeInit(GPIOB); GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_FAST); GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_FAST); } void I2C_setup(void) { I2C_DeInit(); I2C_Init(100000, BH1750_addr, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, (CLK_GetClockFreq() / 1000000)); I2C_Cmd(ENABLE); } void lcd_print(unsigned char x_pos, unsigned char y_pos, unsigned int value) { char tmp[5] = {0x20, 0x20, 0x20, 0x20, 0x20} ; tmp[0] = ((value / 10000) + 0x30); tmp[1] = (((value / 1000) % 10) + 0x30); tmp[2] = (((value / 100) % 10) + 0x30); tmp[3] = (((value / 10) % 10) + 0x30); tmp[4] = ((value % 10) + 0x30); LCD_goto(x_pos, y_pos); LCD_putstr(tmp); } |
BH1750.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include "STM8S.h" #define BH1750_addr 0x46 #define power_down 0x00 #define power_up 0x01 #define reset 0x07 #define cont_H_res_mode1 0x10 #define cont_H_res_mode2 0x11 #define cont_L_res_mode 0x13 #define one_time_H_res_mode1 0x20 #define one_time_H_res_mode2 0x21 #define one_time_L_res_mode 0x23 void BH1750_init(void); void BH1750_write(unsigned char cmd); unsigned int BH1750_read_word(void); unsigned int get_lux_value(unsigned char mode, unsigned int delay_time); |
BH1750.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | #include "BH1750.h" void delay_ms(uint16_t ms) { uint32_t j= ms *100; while(j--) ; } void BH1750_init(void) { delay_ms(10); BH1750_write(power_down); } void BH1750_write(unsigned char cmd) { I2C_GenerateSTART(ENABLE); while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(BH1750_addr, I2C_DIRECTION_TX); while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(cmd); while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(ENABLE); } unsigned int BH1750_read_word(void) { unsigned long value = 0x0000; unsigned char num_of_bytes = 0x02; unsigned char bytes[2] = {0x00, 0x00}; while(I2C_GetFlagStatus(I2C_FLAG_BUSBUSY)); I2C_GenerateSTART(ENABLE); while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(BH1750_addr, I2C_DIRECTION_RX); while(!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); while(num_of_bytes) { if(I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_RECEIVED)) { if(num_of_bytes == 0) { I2C_AcknowledgeConfig(I2C_ACK_NONE); I2C_GenerateSTOP(ENABLE); } bytes[(num_of_bytes - 1)] = I2C_ReceiveData(); num_of_bytes--; } }; value = ((bytes[1] << 8) | bytes[0]); return value; } unsigned int get_lux_value(unsigned char mode, unsigned int delay_time) { unsigned long lux_value = 0x00; unsigned char dly = 0x00; unsigned char s = 0x08; while(s) { BH1750_write(power_up); BH1750_write(mode); lux_value += BH1750_read_word(); for(dly = 0; dly < delay_time; dly += 1) { delay_ms(1); } BH1750_write(power_down); s--; } lux_value >>= 3; return ((unsigned int)lux_value); } |
توضیحات
در ابتدا CPU و کلاک داخلی را تنظیم میکنیم.
1 2 3 4 5 | CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV8); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV2); …. …. CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE); |
ورودی / خروجیهای I2C به عنوان خروجیهای open drain تنظیم شده است، زیرا دارای مقاومت پول-آپ خارجی هستند که ورودی / خروجیهای باس را به VDD وصل میکنند. پین SCL همیشه به عنوان خروجی میکروکنترلر میزبان است، اما جهت پین SDA با توجه به عملیات خواندن و نوشتن متفاوت است. که به طور خودکار توسط سختافزارI2C انجام میشود.
1 2 3 | GPIO_DeInit(GPIOB); GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_FAST); GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_FAST); |
I2C دارای پارامترهای زیادی است که نیاز به تنظیم دارد. اولاً سرعت باس I2C، شناسهI2C، کلاک duty cycle، مد آدرس، تایید نوع و سرعت کلاک داخلی. در اینجا شناسه مستر و Slave تنظیم میشوند، ما از STM8 به عنوان یک Slave استفاده نمیکنیم.
1 2 3 4 5 6 7 8 9 10 11 | void I2C_setup(void) { I2C_DeInit(); I2C_Init(100000, BH1750_addr, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, (CLK_GetClockFreq() / 1000000)); I2C_Cmd(ENABLE); } |
اکثر نمونهایی که برای I2Cدر اینترنت وجود دارد ،I2C را فقط با 24 مجموعه EEPROM نشان میدهند. در اینجا کار متفاوتی انجام میدهیم و به جای تکرار نمونههای EEPROM از سنسور دیجیتال BH1750 I2C استفاده میکنیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | unsigned int BH1750_read_word(void) { unsigned long value = 0x0000; unsigned char num_of_bytes = 0x02; unsigned char bytes[2] = {0x00, 0x00}; while(I2C_GetFlagStatus(I2C_FLAG_BUSBUSY)); I2C_GenerateSTART(ENABLE); while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(BH1750_addr, I2C_DIRECTION_RX); while(!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); while(num_of_bytes) { if(I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_RECEIVED)) { if(num_of_bytes == 0) { I2C_AcknowledgeConfig(I2C_ACK_NONE); I2C_GenerateSTOP(ENABLE); } bytes[(num_of_bytes - 1)] = I2C_ReceiveData(); num_of_bytes--; } }; value = ((bytes[1] << 8) | bytes[0]); return value; } |
همانند SPI، اول باید آزاد بودن سختافزارI2C را بررسی کنیم. سپس، نخستین قدم برای ارتباط I2C را برداشته و وضعیت مستر و Slave بودن را چک میکنیم. سپس، با فرمان خواندن آدرس یا شناسه Slave را ارسال میکنیم، که نشان میدهد، میخواهیم از روی Slave بخوانیم. مجدداً قبل از ادامه پرچم بررسی میشود. سپس سنسور 16 بیت خروجی میدهد که باید به صورت دو مقدار 8 بیتی آن را استخراج کنیم. این عملیات در حلقه “while” انجام میشود. درنهایت، دو بایت به هم متصل میشوند که نشان دهنده خروجی نور است.
تابع زیر عملکرد تعیین ارزش لوکس از سنسور را ساده میکند. این تابع را در حلقه اصلی برای استخراج میانگین نور در لوکس به کار میبریم.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | unsigned int get_lux_value(unsigned char mode, unsigned int delay_time) { unsigned long lux_value = 0x00; unsigned char dly = 0x00; unsigned char s = 0x08; while(s) { BH1750_write(power_up); BH1750_write(mode); lux_value += BH1750_read_word(); for(dly = 0; dly < delay_time; dly += 1) { delay_ms(1); } BH1750_write(power_down); s--; } lux_value >>= 3; return ((unsigned int)lux_value); } |
لینکهای دانلود
مطالب مرتبط
- قسمت اول − میکروکنترلر STM8 چیست و از کجا آمده است؟
- قسمت دوم − معرفی بردهای Discovery میکروکنترلر STM8
- قسمت سوم − کامپایلر و پروگرامر
- قسمت چهارم − STM8CubeMX
- قسمت پنجم − آماده سازی ابزارهای نرمافزاری برای STM8
- قسمت ششم − چگونه برنامه خود را روی STM8 آپلود کنیم؟
- قسمت هفتم− LED چشمکزن
- قسمت هشتم − کلاک سیستم (CLK)
- قسمت نهم − وقفه خارجی (EXTI)
- قسمت دهم − Beeper
- قسمت یازدهم − LCD کاراکتری
- قسمت دوازدهم − مبدل آنالوگ به دیجیتال (ADC)
- قسمت سیزدهم − تایمر نگهبان آنالوگ (AWD)
- قسمت چهادهم − تایمر نگهبان (IWDG)
- قسمت پانزدهم − تایمر نگهبان محدوده ای (WWDG)
- قسمت شانزدهم− اصول اولیه تایمرها
- قسمت هفدهم− تایمر 2
- قسمت هجدهم −تایمر 4
- قسمت نوزدهم −PWM
- قسمت بیستم − PWM تایمر 1
- قسمت بیست و یکم − بررسی اجمالی ارتباطات
- قسمت بیست و دوم − رابط سریال (UART)
- قسمت بیست و سوم − رابط کاربری سریال (SPI)
- دوره رایگان آموزش میکروکنترلر STM8 – سیسوگ
سلام وقت بخیر
به دلیل تحریم ها امکان دانلود stm32cubemx 1.5.0 وجود نداره – اگر ممکنه لینک دانلود مستقیم رو براش فراهم کنید ممنون میشم.
سلام دوست عزیز
ممنونم برای پشنهادتون
بررسی میکنیم 🙂
سلام وقت بخیر، ممکنه کد یا کتابخانه ای برای راه اندازی ds3231 با stm8 قرار بدهید
سلام دوست عزیز – بیسیک های لازم برای راه اندازی این بخش گفته شده
فکر میکنم به سادگی خودتون بتونید این آیسی رو راه اندازی کنید.
سلام من با stm32f103 و keil میخوام راه اندازی کنم دستور های i2c مثل I2C_GenerateSTART(ENABLE); رو error implicit declaration میده. رابط i2c هم فعاله. مشکل از کجاست ممنون.
سلام آروین جان. خب این میکرو STM8 هستش و کلا با STM32 که شما دارید باهاش کار میکنید کلا فرق داره. شما برای راهاندازی I2C در STM32 بهتر است که از کتابخانه HAL یا LL استفاده کنید.
سلام
من میخواهم میکرو stm8s003 را به عنوان i2c-slave پیکربندی کنم و دیتاهای دریافتی را توسط یه نمایشگر که به stm8 متصل است را نمایش بدهم لطفا راهنمایی کنید
فکر میکنم با یه سرچ ساده بتو نید به جواب برسید
البته خوندن داکیومت هم پیشنهاد میکنم – برای شروع کد زیر رو ببینید
https://github.com/joaquimorg/STM8SProjects/tree/master/FWLib/examples/I2C/I2C_10bitsCommunication/slave
سلام
ممنون از پاسخ شما این لینک را قبلاً رفتم ولی مشکلی که دارم و در مورد مثال های شما هم همینطوره اینه که فقط چند تا فایل در فولدر هست و اصلا توضیحی داده نشده که برای وارد کردن این مثال داخل کامپایلر چه روندی را باید انجام داد من از stvd استفاده میکنم وقتی یه پروژه میسازم و سعی میکنم از فایل های مثال درون پروژه استفاده کنم با یه مجموعه خطا مواجه میشوم که راه حلی هم برایش نمیدانم مثلا در مورد استفاده از وقفه i2c در حالت slave و تنظیماتی که دارد و باید درون هدر فایل های مربوطه انجام داد .
خوب فکر میکنم مشکل شما بیشتر درک ساختار برنامه نویسی است
برای این که یه برنامه روی میکروکنترلر اجرا بشه لازمه یه مقدمات اولیه انجام بشه مثل پیکر بندی سخت فزار و و مقدار دهی صحیح وکتورتیبل !!!
وقتی شما یه برنامه چشمک زن رو ران میکنید – یعنی تمام این کار ها انجام شده خوب بعدش چی؟
باقیه تنها کتابخانه نویسی است و استفاده از سخت افزار میکرو – پس خیلی خلاصه بگم – شما لازمه این فایل ها رو به پروژه چشمک زنتون اضافه کنید و از فانکشن ها استفاده کنید
به همین خوشمزگی
سلام
اگه امکانش هست سنسور SHT1x رو هم آموزش بدین
ممنون
سلام دوست عزیز
تا اونجا که من اطلاع دارم پروتکل سنسور های sht و dht مثل هم هست
و فکر میکنم قبلا توی سایت سنسور های dht رو راه اندازی کرده باشیم
sht رابط I2c
DHT onewire هستش
اگه امکانش هست یه آموزش در این زمینه بزارین
ممنون
سلام دوست عزیز
قبلا سنسور DHT رو راه اندازی اش رو گداشتیم
به پست زیر مراجعه کنید.
سنسور دما و رطوبت DHT
سنسور SHT پروتکل I2c هست و با DHT متفاوت هستش
ببخشید الان متوجه منظورتون شدم
خوب ببینید dht درواقع نمونه چینی ساخته شده از روی sht هست و دقیقا جای هم میخورن تا اونجا که به خاطر دارم و البته پروتکل هم i2c نیست – یع چیز الکی است که تنها شباهت هایی با i2c داره.