Подключение 74HC595 к STM32F103C8T6 по SPI

Подключение сдвигового регистра 74HC595 к микроконтроллеру STM32F103C8T6

Приобрести на Aliexpress

Цена: 1.54$ + 0.16$ = 1.70$

Микросхема 74HC595 - это сдвиговый регистр

  • последовательный 8-бит вход, параллельный 8-бит выход
  • напряжение питания 2-6 В
  • выходной ток до 25 мА (на ножку)

Эта микра дает возможность подключить и управлять восемью нагрузками используя только три ножки МК, её используют обычно для светодиодных индикаторов и реже для ЖК-дисплея. То бишь даже применяя восьмивыводный контроллер благодаря сдвиговому регистру можно добавить в устройство светодиодный индикатор.

Чутка теории из тех. документации:

Выдержка из даташита на микросхему 74HC595

Восьмиразрядный сдвиговый регистр принимает данные с вывода DS (14, MOSI) при переднем фронте (переход от лог.0 к лог.1) на выводе SHCP (11, SCK). Данные с входного сдвигового регистра переносятся в выходной регистр при импульсе на выводе STCP (12, PA6).

Также нужно не забыть на вывод OE (13) подать лог.0, чтобы вообще разрешить вывод данных и подтянуть вывод MR (10), чтобы не сбрасывались значения в сдвиговом регистре. Захват данных регистрами происходит при переднем фронте, а вывод при заднем фронте.

Подключение

Подключение микросхемы 74HC595 к микроконтроллеру показано ниже, ни в коем случае не оставляйте неиспользуемые ножки неподключенными (особенно это касается вывода сброса MR (10)), иначе работать не будет.

Подключение сдвигового регистра 74hc595 к микроконтроллеру stm32

Куб

Врубаем SPI (Serial Peripheral Interface) режиме передачи только от ведущего устройства (Transmit Only Master):

Настройки трогать обычно не нужно, но при высокой тактовой частоте предделитель придется выставить на 4, вместо 2.

Теперь любой вывод (здесь PA6) настраиваем на выход, включаем подтяжку к минусу.

Вывод байта

Для передачи чего-либо через SPI средствами HAL нужно иметь массив, здесь он состоит из одного элемента:

uint8_t transmit_data[1];

Присваиваем значение нулевому элементу, которое и будет передано:

transmit_data[0] = 170;

Почему именно 170? Потому что в двоичной системе исчисления это выглядит так:

Перевод числа 170 из десятичной в двоичную систему

Где "1" СД будет светится, где "0" - нет. То есть светодиоды будут светится через один.

Числа в двоичном коде Keil не понимает (такой стандарт C51), поэтому написано в десятичной, можно также в шестнадцатеричной 0xAA.

Чтобы микросхема всё приняла сначала нужно установить низкий логический уровень на выводе STCP (11), благодаря подтяжке он уже установлен, передать 1 байт, подать импульс на вывод защёлки STCP (11) и тогда данные запишутся по переднему фронту и выведутся по заднему.

HAL_SPI_Transmit(&hspi1,(uint8_t*)transmit_data, 1, 100); // Передача данных по SPI GPIOA->BSRR |= GPIO_BSRR_BS6; // Установка высокого уровня GPIOA->BSRR |= GPIO_BSRR_BR6; // Установка низкого уровня

В итоге (показано на примере индикатора):

Отображение числа 0b10101010

Бегущие огни светодиоды

Вспомогательная переменная:

uint8_t i = 0;

В главном цикле сдвигаем бит, передаем получившееся значение по SPI и создаем импульс на выводе STCP (11):

transmit_data[0] = (i << 1); i++; if(i > 7) i = 0; HAL_SPI_Transmit(&hspi1,(uint8_t*)transmit_data, 1, 100); GPIOA->BSRR |= GPIO_BSRR_BS6; GPIOA->BSRR |= GPIO_BSRR_BR6; HAL_Delay(100);

В итоге:

Линейка светодиодов

Вывод символов на индикатор (динамическая индикация)

Чтобы осуществить динамическую индикацию нужно дополнительно задействовать выводы для включения/выключения целых разрядов, то есть управлять подачей питания на общий провод (общий К/A).

В моем случае в середине каждого сегмента индикатора целых два СД (красный и зеленый), поэтому настроено на выход аж 4 вывода (2 для красн., 2 для зелен.).

В общем настраиваем выводы как двухтактный выход с подтяжкой к минусу.

SPI в режиме передачи от ведущего к ведомому (SPI1 -> Transmit Only Master).

Отладка через SWD (SYS -> Debug Serial Wire).

Тактирование одного из таймеров (TIM17 -> Activated).

Настраиваем  таймер на частоту f > 40 Гц и включаем прерывание от него.

Таймер 17, глобальное прерывание

Связь между передаваемыми данными и выводимыми символами:

Пример отображения символа на светодиодном индикаторе

Для удобства создается массив с числами, при выводе которых будет отображение символов 0-9. Индикатор с общий анодом, то бишь придется инвертировать все значения, либо вызывать число из массива с инвертированием (знак ~ перед числом).

/* Массив чисел 0-9 для светодиодного индикатора */ uint8_t Number[10] = {123, 34, 241, 242, 170, 218, 219, 50, 251, 250};

main.c

/* USER CODE BEGIN Includes */ uint8_t Peredaem; // Переменная-число, которое и будет отображатся /* USER CODE END Includes */ HAL_TIM_Base_Start_IT(&htim17); // Разрешаем прерывание от таймера

stm43f0xx_it.c

/* Буфер для передачи на индикатор */ uint8_t transmit_data[1]; /* Создаём массив чисел 0-9 */ uint8_t Number[10] = {123, 34, 241, 242, 170, 218, 219, 50, 251, 250}; /* Для перекючения */ uint8_t toogle = 0; /* Переменная, объявленная в главном файле main.c*/ extern uint8_t Peredaem;

Непосредственно обновление происходит в обработчике прерывания от таймера:

void TIM17_IRQHandler(void) { /* USER CODE BEGIN TIM17_IRQn 0 */ if(toogle){ transmit_data[0] = ~Number[Peredaem%10]; // Число для младшего разряда HAL_SPI_Transmit(&hspi1,(uint8_t*)transmit_data, 1, 100); /* Создаем импульс на выводе STCP */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); /* Врубаем второй разряд и вырубаем первый */ GPIOB->BSRR |= GPIO_BSRR_BS_0; GPIOB->BSRR |= GPIO_BSRR_BR_10; } else{ transmit_data[0] = ~Number[Peredaem/10]; // Число для старшего разряда HAL_SPI_Transmit(&hspi1,(uint8_t*)transmit_data, 1, 100); /* Создаем импульс на выводе STCP */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET); /* Врубаем первый разряд и вырубаем второй */ GPIOB->BSRR |= GPIO_BSRR_BR_0; GPIOB->BSRR |= GPIO_BSRR_BS_10; } /* Переключаем значение (0/255) */ toogle = ~toogle; /* USER CODE END TIM17_IRQn 0 */ HAL_TIM_IRQHandler(&htim17); /* USER CODE BEGIN TIM17_IRQn 1 */ /* USER CODE END TIM17_IRQn 1 */ }

Ну и в главном цикле:

/* USER CODE BEGIN WHILE */ while (1) { while(Peredaem < 99){ Peredaem++; HAL_Delay(100); } while(Peredaem > 0){ Peredaem--; HAL_Delay(100); } /* USER CODE END WHILE */

В итоге:

Счет от 1 до 50 с помощью динамической индикации



Проект Keil и STM32CubeMX (бегущие огни): 74hc595_stm32_spi1.zip

Проект Keil и STM32CubeMX (динамическая индикация): 74hc595_stm32_led_indicator.zip

622
RSS
Игорь
13:54
Ссылки битые на архивы, не перезальете случаем?
15:00
Хм, точно битые, исправлю.
А пока вот залил на диск:

74hc595_stm32_spi1.zip
drive.google.com/file/d/1eUE_FERGKPNSsXviq73f7TXv2o9P0opf/view?usp=sharing

74hc595_stm32_led_indicator.zip
drive.google.com/file/d/1xgBoISV3YdgiHb1Cs6VXWCZ1Vk3ZqlOr/view?usp=sharing
21:07

Благодарю

19:33

Здравствуйте. Прочитал Вашу статью «Подключение 74HC595 к STM32F103C8T6 по SPI» у меня к Вам вопрос. Вы можете мне помочь с «Вывод символов на индикатор (Статическая индикация)» 2 регистра и 2 индикатора.?

00:06 (отредактировано)

Здравствуйте.

Тут  должно быть все просто, последовательный выход регистра 1 Q7S подключается на вход DS регистра 2.

Данные шлются на вход DS регистра 1.

То есть, если используется тот же SPI, как в статье, тогда нужно будет отправить не один байт, а два (для двух индикаторов).

uint8_t transmit_data[2] = {123, 124}; // 124 - символ для первого инд. 123 - для второго
HAL_SPI_Transmit(&hspi1,(uint8_t*)transmit_data, 2, 100); // Передача данных по SPI
GPIOA->BSRR |= GPIO_BSRR_BS6; // Установка высокого уровня
GPIOA->BSRR |= GPIO_BSRR_BR6; // Установка низкого уровня

https://meandr.org/archives/5107

Загрузка...