Передмова
Щоб спробувати роботу інтерфейсу SPI на простому прикладі я обрав мікросхему зсувного регістру SN74HC595, який приймає по послідовній шині байт і виставляє цей байт на виході вже у паралельному вигляді. Спектр застосування доволі широкий. Це і розширення GPIO, коли не вистачає ніжок на MCU для проекту, і робота з 7-ми сегментними дисплеями, і робота зі світлодіодними матрицями, тощо.
Мета
- підключимо зсувний регістр SN74HC595 до STM32;
- створимо проект в STM32CubeMX, налаштуємо периферію;
- напишемо невеличкий код для демонстрації.
Налаштування периферії в STM32CubeIDE
![]() |
Налаштування проекту |
- Обираємо SPI і налаштовуємо як "Transmit only master", так як все одно будемо тільки передавати байти;
- Обираємо "Serial Wire" для програмування MCU за допомоги ST-Link (не обов'язково);
- Налаштовуємо одину шпильку на вихід GPIO_OUTPUT (яку вам зручно) і називаємо її "CS_HC595" вибір кристалу.
Схема підключення
- STM32: PB11 (CS) - 74HC595: 12 (RCLK) Storage register
- STM32: PB15 (MOSI) - 74HC595: 14 (SER) Serial data input
- STM32: PB13 (SCK) - 74HC595: 11 ( SRCLK) Shift register
![]() |
Макетна схема для Nucleo-F103RB |
![]() |
Макетна схема для STM32F103C8 (Blue Pill) |
Демонстраційна програма
Відкриваємо файл "main.c". У визначених програмою STM32CubeIDE ділянках для користувача пишемо такий код:
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { for (int i = 0; i < 256; ++i) { HAL_GPIO_WritePin(CS_HC595_GPIO_Port, CS_HC595_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, (uint8_t*) &i, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(CS_HC595_GPIO_Port, CS_HC595_Pin, GPIO_PIN_SET); HAL_Delay(150); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
Це простий цикл від 0 до 255, або від 0x00h до 0xFFh у шістнадцятковому виді. В цьому циклі ми по SPI з MCU шлемо один байт ітерації циклу до зсувного регістру кожні 150 мілісекунд. Простими словами, байт посланий по послідовній шині, зсувний регістр прийме і виставить на паралельну шину вже у двійковому форматі. І будемо спостерігати як перебираються цифри від 0 до 255 у двійковому форматі.
Можете проекспериментувати з надсиланням байтів і зробити, наприклад, вогник що біжить зліва праворуч та повертається з право ліворуч. Шляхом зсуву бітів у циклі.
/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { for (int i = 0; i < 8; ++i) { int tmp = 1 << i; HAL_GPIO_WritePin(CS_HC595_GPIO_Port, CS_HC595_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, (uint8_t*) &tmp, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(CS_HC595_GPIO_Port, CS_HC595_Pin, GPIO_PIN_SET); HAL_Delay(150); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
/* USER CODE BEGIN WHILE */ while (1) { for (int i = 0; i < 8; ++i) { int tmp = ~(1 << i); HAL_GPIO_WritePin(CS_HC595_GPIO_Port, CS_HC595_Pin, GPIO_PIN_RESET); HAL_SPI_Transmit(&hspi1, (uint8_t*) &tmp, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(CS_HC595_GPIO_Port, CS_HC595_Pin, GPIO_PIN_SET); HAL_Delay(150); } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */