четвер, 1 лютого 2018 р.

STM32: керуємо зсувним регістром SN74HC595 по SPI

Передмова

Щоб спробувати роботу інтерфейсу SPI на простому прикладі я обрав мікросхему зсувного регістру SN74HC595, який приймає по послідовній шині байт і виставляє цей байт на виході вже у паралельному вигляді. Спектр застосування доволі широкий. Це і розширення GPIO, коли не вистачає ніжок на MCU для проекту, і робота з 7-ми сегментними дисплеями, і робота зі світлодіодними матрицями, тощо.

Мета

З метою ознайомлення з інтерфейсом SPI:
  • підключимо зсувний регістр SN74HC595 до STM32;
  • створимо проект в STM32CubeMX, налаштуємо периферію;
  • напишемо невеличкий код для демонстрації.

Налаштування периферії в STM32CubeIDE

Створюємо новий проект в STM32CubeMX і налаштовуємо периферію як показано на малюнку:
Налаштування проекту

  1. Обираємо SPI і налаштовуємо як "Transmit only master", так як все одно будемо тільки передавати байти;
  2. Обираємо "Serial Wire" для програмування MCU за допомоги ST-Link (не обов'язково);
  3. Налаштовуємо одину шпильку на вихід GPIO_OUTPUT (яку вам зручно) і називаємо її "CS_HC595" вибір кристалу.
Генеруємо проект, даємо назву, наприклад "STM32F103RB_SPI_SN74HC595N". Переходимо до збірки схеми.

Схема підключення

Так як в SN74HC595N шпильки називаються по своєму, то я наведу вам відповідність SPI сигналів до виводів SN74HC595N:
  • 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 */

Відео-посібник