Подключение 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

7441
RSS
Игорь
13:54
Ссылки битые на архивы, не перезальете случаем?
15:00 (отредактировано)
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

Артем
10:52

ссылки с проектами мертвые

13:57

починил

Артем
14:10

Спасибо!!! R9WAY

Артем
12:09

Доброго дня, в файле для работы со светодиодами не обнаружил куска кода transmit_data[0] = 170;

его отсутствие, ошибка, да?

19:14

Добрый день.

Его нет в проекте, т.к. это пример вывода одного байта, там сразу пример бегущих огней, где передача байта также происходит, но передаваемое значение постоянно меняется, чтобы уровень сигнала изменялся так, что светодиоды засвечивались по очереди.

Загрузка...