سیسوگ در قسمت بیستم و دوم آموزش میکروکنترلر STM8 به بررسی رابط سریال (UART) پرداخت. در این از قسمت آموزش میکروکنترلر STM8 رابط کاربری سریال (SPI) را مورد بررسی قرار میدهد. با سیسوگ همراه باشید.
ارتباط SPI :
ارتباط SPI یک روش ارتباط سنکرون درون خطی است و توسط تعدادی از دستگاهها از جمله سنسورها، نمایشگرهای TFT، توسعه دهنده GPIO، کنترل کننده PWM، تراشههای حافظه، دستگاه های پشتیبانی افزونه و غیره استفاده میشود.
همیشه یک مستر در باس ارتباطی SPI وجود دارد که کلاک را تولید میکند و slave ها را انتخاب میکند. مستر دستورات را به slave ها میفرستد و slaveها به دستورات ارسالی از طرف مستر پاسخ میدهند. تعداد slave ها در باس SPI نامحدود است. به جز پین انتخاب تراشه، تمامی دستگاههای SPI در یک باس میتوانند کلاک و پینهای اطلاعاتی مشابه را به اشتراک بگذارند.
باس SPI دوبلکس به چهار پین ورودی / خروجی نیاز دارد:
- (Master-Out-Slave-In (MOSI متصل به (Slave-Data-In (SDI.
- (Master-In-Slave-Out (MIS0 متصل به (Slave-Data-Out (SD0.
- سریال کلاک (SCLK) متصل به (Clock Slave (SCK.
- (Slave Select (SS متصل به (Chip Select (CS.
اگر تمایل دارید اطلاعات بیشتری درباره باس SPI بدست آورید لینکهای زیر مناسب هستند:
tutorial-arduino-and-the-spi-bus
سختافزار SPI موجود در میکروکنترلر STM8 نسبت به دیگر میکروکنترلرها، ویژگیهای بیشتری دارد. یکی دیگر از ویژگیهای این رابط سریال موجود در میکروکنترلر STM8، سختافزار CRC است. این ویژگی از ارسال اطلاعات درست بین دستگاهها اطمینان حاصل میکند.
اتصالات سختافزاری:
نمونه کد :
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 | #include "STM8S.h" #include "MAX72XX.h" void _delay_ms(uint16_t ms); void clock_setup(void); void GPIO_setup(void); void SPI_setup(void); void main() { unsigned char i = 0x00; unsigned char j = 0x00; unsigned char temp[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; const unsigned char text[96] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x04, 0x08, 0x08, 0x04, 0x7E, 0x00, //M 0x00, 0x42, 0x42, 0x7E, 0x7E, 0x42, 0x42, 0x00, //I 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x24, 0x00, //C 0x00, 0x7E, 0x1A, 0x1A, 0x1A, 0x2A, 0x44, 0x00, //R 0x00, 0x3C, 0x42, 0x42, 0x42, 0x42, 0x3C, 0x00, //O 0x00, 0x7C, 0x12, 0x12, 0x12, 0x12, 0x7C, 0x00, //A 0x00, 0x7E, 0x1A, 0x1A, 0x1A, 0x2A, 0x44, 0x00, //R 0x00, 0x7E, 0x7E, 0x4A, 0x4A, 0x4A, 0x42, 0x00, //E 0x00, 0x7E, 0x04, 0x08, 0x10, 0x20, 0x7E, 0x00, //N 0x00, 0x7C, 0x12, 0x12, 0x12, 0x12, 0x7C, 0x00, //A 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; clock_setup(); GPIO_setup(); SPI_setup(); MAX72xx_init(); while(TRUE) { for(i = 0; i < sizeof(temp); i++) { temp[i] = 0x00; } for(i = 0; i < sizeof(text); i++) { for(j = 0; j < sizeof(temp); j++) { temp[j] = text[(i + j)]; MAX72xx_write((1 + j), temp[j]); _delay_ms(9); } } }; } 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_HSIDIV1); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE); 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(GPIOC); GPIO_Init(GPIOC, ((GPIO_Pin_TypeDef)GPIO_PIN_5 | GPIO_PIN_6), GPIO_MODE_OUT_PP_HIGH_FAST); } void SPI_setup(void) { SPI_DeInit(); SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_2, SPI_MODE_MASTER, SPI_CLOCKPOLARITY_HIGH, SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_1LINE_TX, SPI_NSS_SOFT, 0x00); SPI_Cmd(ENABLE); } |
MAX72xx.h:
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 | #include "STM8S.h" #define CS_pin GPIO_PIN_3 #define CS_port GPIOA #define NOP 0x00 #define DIG0 0x01 #define DIG1 0x02 #define DIG2 0x03 #define DIG3 0x04 #define DIG4 0x05 #define DIG5 0x06 #define DIG6 0x07 #define DIG7 0x08 #define decode_mode_reg 0x09 #define intensity_reg 0x0A #define scan_limit_reg 0x0B #define shutdown_reg 0x0C #define display_test_reg 0x0F #define shutdown_cmd 0x00 #define run_cmd 0x01 #define no_test_cmd 0x00 #define test_cmd 0x01 #define digit_0_only 0x00 #define digit_0_to_1 0x01 #define digit_0_to_2 0x02 #define digit_0_to_3 0x03 #define digit_0_to_4 0x04 #define digit_0_to_5 0x05 #define digit_0_to_6 0x06 #define digit_0_to_7 0x07 #define No_decode_for_all 0x00 #define Code_B_decode_digit_0 0x01 #define Code_B_decode_digit_0_to_3 0x0F #define Code_B_decode_for_all 0xFF void MAX72xx_init(void); void MAX72xx_write(unsigned char address, unsigned char value); |
MAX72xx.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 | #include "MAX72xx.h" void _delay_ms(uint16_t ms) { uint32_t j= ms *100; while(j--) ; } void MAX72xx_init(void) { GPIO_Init(CS_port, CS_pin, GPIO_MODE_OUT_PP_HIGH_FAST); MAX72xx_write(shutdown_reg, run_cmd); MAX72xx_write(decode_mode_reg, 0x00); MAX72xx_write(scan_limit_reg, 0x07); MAX72xx_write(intensity_reg, 0x04); MAX72xx_write(display_test_reg, test_cmd); _delay_ms(10); MAX72xx_write(display_test_reg, no_test_cmd); } void MAX72xx_write(unsigned char address, unsigned char value) { while(SPI_GetFlagStatus(SPI_FLAG_BSY)); GPIO_WriteLow(CS_port, CS_pin); SPI_SendData(address); while(!SPI_GetFlagStatus(SPI_FLAG_TXE)); SPI_SendData(value); while(!SPI_GetFlagStatus(SPI_FLAG_TXE)); GPIO_WriteHigh(CS_port, CS_pin); } |
توضیحات:
این بار نیز CPU و کلاک داخلی روی بیشترین مقدار تنظیم می شوند.
1 2 3 4 5 | CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); …. …. CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE); |
ورودی/خروجیها را نیز تعریف میکنیم:
1 2 3 4 5 6 7 8 | #define CS_pin GPIO_PIN_3 #define CS_port GPIOA …. …. GPIO_DeInit(GPIOC); GPIO_Init(CS_port, CS_pin, GPIO_MODE_OUT_PP_HIGH_FAST); GPIO_Init(GPIOC, ((GPIO_Pin_TypeDef)GPIO_PIN_5 | GPIO_PIN_6), GPIO_MODE_OUT_PP_HIGH_FAST); |
GPIO ها باید به عنوان ورودی/خروجیهای سریع پیکربندی شوند، زیرا ارتباط SPI سریعتر از عملیات GPIO ساده است.
برای قسمت پیکربندی SPI، در اینجا از MAX7219 استفاده میکنیم و پورت آن را به گونهای تنظیم میکنیم که MSB سریع ارسال کند. همچنین از کلاک داخلی سریع استفاده میکنیم. SPI را روی مد Half-Duplex-Master تنظیم میکنیم.
1 2 3 4 5 6 7 8 9 10 11 12 13 | void SPI_setup(void) { SPI_DeInit(); SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_2, SPI_MODE_MASTER, SPI_CLOCKPOLARITY_HIGH, SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_1LINE_TX, SPI_NSS_SOFT, 0x00); SPI_Cmd(ENABLE); } |
نمودار زمان بندی MAX7219 نشان میدهد، در زمان دریافت MAX7219 باید CS مقدار Low را داشته باشد.
همانطور که نشان میدهد، انتقال داده با هر لبه بالارونده انجام میشود. همه این موارد برای تنظیم سختافزار SPI مورد نیاز است.
1 2 3 4 5 6 7 8 9 10 11 12 13 | void MAX72xx_write(unsigned char address, unsigned char value) { while(SPI_GetFlagStatus(SPI_FLAG_BSY)); GPIO_WriteLow(CS_port, CS_pin); SPI_SendData(address); while(!SPI_GetFlagStatus(SPI_FLAG_TXE)); SPI_SendData(value); while(!SPI_GetFlagStatus(SPI_FLAG_TXE)); GPIO_WriteHigh(CS_port, CS_pin); } |
قبل از ارسال داده به MAX7219، باید بررسی کنیم آیا سختافزارSPI به دلایلی مشغول هست یا خیر. با تنظیمات پایه (PA3) که پایه انتخاب Slave هست CS را Low قرار میدهیم. هر بار که چیزی را ارسال میکنیم، باید منتظر بمانیم تا به طور کامل ارسال شود. در نهایت، CS راروی high تنظیم میکنیم تا اطلاعات ارسال شده را قفل کنیم. این فانکشن و همچنین آپدیت نمایشها دلیل استفاده از MAX7219 است.
در قسمت بیست و چهارم آموزش میکروکنترلر STM8 به رابط I2C میپردازیم. با سیسوگ همراه باشید.
لینکهای دانلود
مطالب مرتبط
- قسمت اول − میکروکنترلر STM8 چیست و از کجا آمده است؟
- قسمت دوم − معرفی بردهای Discovery میکروکنترلر STM8
- قسمت سوم − کامپایلر و پروگرامر
- قسمت چهارم − STM8CubeMX
- قسمت پنجم − آماده سازی ابزارهای نرمافزاری برای STM8
- قسمت ششم − چگونه برنامه خود را روی STM8 آپلود کنیم؟
- قسمت هفتم− LED چشمکزن
- قسمت هشتم − کلاک سیستم (CLK)
- قسمت نهم − وقفه خارجی (EXTI)
- قسمت دهم − Beeper
- قسمت یازدهم − LCD کاراکتری
- قسمت دوازدهم − مبدل آنالوگ به دیجیتال (ADC)
- قسمت سیزدهم − تایمر نگهبان آنالوگ (AWD)
- قسمت چهادهم − تایمر نگهبان (IWDG)
- قسمت پانزدهم − تایمر نگهبان محدوده ای (WWDG)
- قسمت شانزدهم− اصول اولیه تایمرها
- قسمت هفدهم− تایمر 2
- قسمت هجدهم −تایمر 4
- قسمت نوزدهم −PWM
- قسمت بیستم − PWM تایمر 1
- قسمت بیست و یکم − بررسی اجمالی ارتباطات
- قسمت بیست و دوم − رابط سریال (UART)
- قسمت بیست و چهارم − رابط I2C
- دوره رایگان آموزش میکروکنترلر STM8 – سیسوگ
نخیر، کاملا درسته
من اشتباه متوجه شدم !!!
عذر میخوام.
سلام دوست عزیز
ممنون از پیام اصلاحیتون
سلام
توی شکل گرافیکی بالای مقاله، جهت فلش های MISO و MOSI احتمالا اشتباه و به جای هم کشیده شده.
خواستم یادآوری کنم.
ممنونم از شما.
(Master-In-Slave-Out (MIS0 متصل به (Slave-Data-Out (SDO.
0 رو به جای O نوشتید.
ممنون از آموزش های خوبتون.
سلام
ممنون از توجه شما… این اشتباه تایپی اصلاح شد.