در قسمت بیستو دوم آموزش میکروکنترلر 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 بدستآورید لینکهایزیر مناسب هستند:
- SPI_Bus
- serial-peripheral-interface-spi
- spi.pdf
- tutorial-arduino-and-the-spi-bus
- serial-peripheral-interface-spi
- basics-of-the-spi-communication-protocol
سختافزار SPI موجود در میکروکنترلرSTM8 نسبتبه دیگر میکروکنترلرها، ویژگیهای بیشتری دارد. یکیدیگر از ویژگیهای این رابط سریال موجود در میکروکنترلر STM8، سختافزار CRC است. این ویژگی از ارسال اطلاعات درست بین دستگاهها اطمینان حاصل میکند.
اتصالات سختافزاری:
نمونه کد :
main.c:
#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:
#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:
#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 و کلاک داخلی روی بیشترین مقدار تنظیم میشوند.
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); …. …. CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);
ورودی/خروجیها را نیز تعریف میکنیم:
#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 تنظیم میکنیم.
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 موردنیاز است.
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 میپردازیم. با ما همراه باشید.
منبع: سیسوگ