середа, 8 лютого 2017 р.

STM32: Бібліотека для 7-ми сегментного дисплею


Передмова

Семисегментний дисплей, мабуть, найдешевший з дисплеїв. І його застосування в деяких проектах цілком виправдане. З недоліків, це мала інформативність (тільки цифри і деякі знаки), та займає багато ніжок мікроконтролера (7 ніжок на сегменти + 1 ніжка "кома" + по одному виводу мікроконтролера на кожен розряд дисплею).

Бібліотека проста в застосуванні та налаштуванні. Може працювати з 1 - 9 розрядним дисплеєм. Можна при необхідності додати розрядність по аналогії (якщо це комусь може знадобитись). Бібліотека створювалась під свої потреби і має обмежений "сервіс". Але при необхідності можна додати функцій. Наприклад, рядок цифр що біжить (scroll лівий, правий), вивід чисел типу float, тощо. Також майте на увазі, що сегменти дисплею мають бути під'єднані до виводів якогось одного порту мікроконтролера, а розряди дисплею вже по бажанню/можливостям/зручностям, до будь яких портів і виводів мікроконтролеру.

Як приклад, розглянемо схему підключення, налаштування та роботу з чотирьох розрядним 7-сегментним дисплеєм з загальним катодом. Підключати будемо до плати розробника STM32VLDiscovery на мікроконтролері STM32F100RB. Але у вас може бути будь який інший мікроконтролер.

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

На схемі вказано до яких ніжок мікроконтролера під'єднано дисплей. Це для прикладу, який будемо розглядати далі. А ви можете під'єднувати до виводів мікроконтролеру по своїм міркуванням. Головне щоб сегменти дисплею (A,B,C,D,E,F,G і H (DP)) знаходились на одному порту мікроконтролера (GPIOA, GPIOB, GPIOC, GPIOD, тощо). Тисніть на малюнок для збільшення.
Схема підключення 7-сегментного дисплею

Опис функцій бібліотеки LED7Seg

  • void LED7SegInit(void) - функція ініціалізації дисплею. Викликати, якщо проект не створювався за допомоги CUBEMX. Потрібно внести корективи у функцію, щоб відповідало до яких портів і виводів під'єднаний дисплей. Якщо проект створювався за допомоги CUBEMX, де вказані ніжки до яких під'єднаний дисплей, то викликати цю функцію не треба взагалі. CUBEMX сам згенерує ініціалізацію потрібних ніжок і портів.
  •  void LED7SegPrint(uint32_t incomingNumber) - функція друку цілого позитивного числа. Вхідні параметри: ціле позитивне число.
  • void LED7SegPrintSeparate(uint8_t* aDigit, uint8_t number_of_digits) - функція друку чисел (або знаків, таких як "мінус", або взагалі "пусто") в кожен розряд окремо. Вхідні параметри: вказівник на масив з чисел (знаків), та кількість розрядів дисплею.
  • void LED7SegShow(void) - ця функція відповідає саме за світіння потрібних сегментів і розрядів дисплею (динамічна індикація). Цю функцію потрібно викликати як можна частіше. Розмістити її в головному безкінечному циклі, та потурбуватись, щоб виклик цієї функції ніщо не затримувало. Або створити окреме переривання по таймеру для виклику цієї функції. Або, якщо використовувати RTOS, створити окрему задачу для виклику цієї функції з високим пріоритетом.

LED7Seg.h

Заголовний файл LED7Seg.h містить підключення файлу CMSIS периферії вашого мікроконтролеру в прикладі це #include "stm32f1xx.h". Визначення назв ніжок і портів до яких під'єднано дисплей, якщо це не визначено у файлі main.h за допомоги CUBEMX. Визначено з яких сегментів складаються цифри на дисплеї. Деякі знаки, які можна відтворити на дисплеї. Кількість розрядів дисплею. Прототипи функцій.
/*
 * Автор: Андрій Гончаренко
 * Email: taburyak@gmail.com
 * м.Дніпро
 * 2017
 * Бібліотека у вільному розповсюдженні
 */

#ifndef _LED7SEG_H
#define _LED7SEG_H

// підключити файл з вашою серією мікроконтролера
#include "stm32f1xx.h"

// якщо не визначили ніжки і порти до яких під'єднано дисплей у файлі main.h за допомоги CUBEMX,
// то треба ніжки і порти позначити тут відповідно до електричної схеми підключення дисплею
#if !defined SEG_A_Pin
 #define SEG_A_Pin        GPIO_PIN_0
 #define SEG_A_GPIO_Port  GPIOB
#endif

#if !defined SEG_B_Pin
 #define SEG_B_Pin        GPIO_PIN_1
 #define SEG_B_GPIO_Port  GPIOB
#endif

#if !defined SEG_C_Pin
 #define SEG_C_Pin        GPIO_PIN_2
 #define SEG_C_GPIO_Port  GPIOB
#endif

#if !defined SEG_D_Pin
 #define SEG_D_Pin        GPIO_PIN_3
 #define SEG_D_GPIO_Port  GPIOB
#endif

#if !defined SEG_E_Pin
 #define SEG_E_Pin        GPIO_PIN_4
 #define SEG_E_GPIO_Port  GPIOB
#endif

#if !defined SEG_F_Pin
 #define SEG_F_Pin        GPIO_PIN_5
 #define SEG_F_GPIO_Port  GPIOB
#endif

#if !defined SEG_G_Pin
 #define SEG_G_Pin        GPIO_PIN_6
 #define SEG_G_GPIO_Port  GPIOB
#endif

#if !defined SEG_H_Pin
 #define SEG_H_Pin        0u
 #define SEG_H_GPIO_Port  0u
#endif

#if !defined D0_Pin
 #define D0_Pin         GPIO_PIN_8
 #define D0_GPIO_Port   GPIOB
#endif

#if !defined D1_Pin
 #define D1_Pin         GPIO_PIN_9
 #define D1_GPIO_Port   GPIOB
#endif

#if !defined D2_Pin
 #define D2_Pin         GPIO_PIN_6
 #define D2_GPIO_Port   GPIOC
#endif

#if !defined D3_Pin
 #define D3_Pin         GPIO_PIN_6
 #define D3_GPIO_Port   GPIOA
#endif

#if !defined D4_Pin
 #define D4_Pin         0u
 #define D4_GPIO_Port   0u
#endif

#if !defined D5_Pin
 #define D5_Pin         0u
 #define D5_GPIO_Port   0u
#endif

#if !defined D6_Pin
 #define D6_Pin         0u
 #define D6_GPIO_Port   0u
#endif

#if !defined D7_Pin
 #define D7_Pin         0u
 #define D7_GPIO_Port   0u
#endif

#if !defined D8_Pin
 #define D8_Pin         0u
 #define D8_GPIO_Port   0u
#endif

// складаємо з окремих сегментів відповідні цифри
#define DIG0   ( SEG_A_Pin | SEG_B_Pin | SEG_C_Pin | SEG_D_Pin | SEG_E_Pin | SEG_F_Pin )
#define DIG1   ( SEG_B_Pin | SEG_C_Pin )
#define DIG2   ( SEG_A_Pin | SEG_B_Pin | SEG_G_Pin | SEG_E_Pin | SEG_D_Pin )
#define DIG3   ( SEG_A_Pin | SEG_B_Pin | SEG_G_Pin | SEG_C_Pin | SEG_D_Pin )
#define DIG4   ( SEG_F_Pin | SEG_G_Pin | SEG_B_Pin | SEG_C_Pin )
#define DIG5   ( SEG_A_Pin | SEG_F_Pin | SEG_G_Pin | SEG_C_Pin | SEG_D_Pin )
#define DIG6   ( SEG_A_Pin | SEG_C_Pin | SEG_D_Pin | SEG_E_Pin | SEG_F_Pin | SEG_G_Pin )
#define DIG7   ( SEG_A_Pin | SEG_B_Pin | SEG_C_Pin )
#define DIG8   ( SEG_A_Pin | SEG_B_Pin | SEG_C_Pin | SEG_D_Pin | SEG_E_Pin | SEG_F_Pin | SEG_G_Pin )
#define DIG9   ( SEG_A_Pin | SEG_B_Pin | SEG_C_Pin | SEG_D_Pin | SEG_F_Pin | SEG_G_Pin )
// крапка
#define POINT   ( SEG_H_Pin )
// складемо всі сегменти в купу
#define ALL_SEG ( SEG_A_Pin | SEG_B_Pin | SEG_C_Pin | SEG_D_Pin | SEG_E_Pin | SEG_F_Pin | SEG_G_Pin | SEG_H_Pin )
// порядковий номер в масиві digitsp знаку чи символу
#define NOP  10   // знак "пусто" всі сегменти відключено
#define MINUS  11 // знак - "мінус"

// всі сегменти мають бути під'єднано до одного порту і тут визначається загальний для сегментів порт
#define SEG_PORT SEG_A_GPIO_Port

// кількість розрядів дисплею
#define NUM_DIGIT 4

// Ініціалізація периферії дисплею
void LED7SegInit(void);
// Надрукувати число на дисплеї
void LED7SegPrint(uint32_t incomingNumber);
// Надрукувати числа в дисплей для кожного розряду окреме число
void LED7SegPrintSeparate(uint8_t* aDigit, uint8_t number_of_digits);
// // Запалювання потрібних сегментів та розрядів дисплею (динамічна індикація)
void LED7SegShow(void);
// виставляє в відповідні розряди індикатора числа-розряди
void digitToPort (uint8_t digit);
// число з лічильника розбиває на окремі розряди. вхідні аргументи: значення лічильника, масив для розрядів, кількість розрядів.
void splitToDigit(uint32_t counter, uint8_t* digit, uint8_t number_of_digits);

#endif
 
/*--------------------------------------------------------------------------------*/
//  ENF OF FILE
/*--------------------------------------------------------------------------------*/

LED7Seg.c

Файл LED7Seg.c містить вкладення заголовного файлу, масиви і змінні та самі функції бібліотеки.
/*
 * Автор: Андрій Гончаренко
 * м.Дніпро
 * 2017
 * Бібліотека у вільному розповсюдженні
 */

#include <led7seg.h>
 
// Масив для числа окремо цифра в кожен розряд індикатора
static uint8_t digit[NUM_DIGIT] = {};
// оголошуємо масив з назвами ніжок куди під'єднані розряди індикатора
static const uint16_t digitPin[] = {D0_Pin, D1_Pin, D2_Pin,
                                    D3_Pin, D4_Pin, D5_Pin,
                                    D6_Pin, D7_Pin, D8_Pin};
// оголошуємо масив з назвами портів куди під'єднані розряди індикатора
static GPIO_TypeDef* digitPort[] = {D0_GPIO_Port, D1_GPIO_Port, D2_GPIO_Port,
                                    D3_GPIO_Port, D4_GPIO_Port, D5_GPIO_Port,
                                    D6_GPIO_Port, D7_GPIO_Port, D8_GPIO_Port};
//оголошуємо масив з можливими варіантами символами на індикатор
static const uint16_t digitsp[]={DIG0,DIG1,DIG2,DIG3,DIG4,DIG5,DIG6,DIG7,DIG8,DIG9,~ALL_SEG,SEG_G_Pin};
//Функції ініціалізації та виводу інформації на дисплей

//Ініціалізація периферії до якої підключено дисплей
void LED7SegInit(void)
{
 GPIO_InitTypeDef GPIO_InitStruct;

   /* GPIO Ports Clock Enable */
   __HAL_RCC_GPIOB_CLK_ENABLE();

   /*Configure GPIO pin Output Level */
   HAL_GPIO_WritePin(GPIOB, SEG_A_Pin|SEG_B_Pin|SEG_C_Pin|SEG_D_Pin
                           |SEG_E_Pin|SEG_F_Pin|SEG_G_Pin|SEG_H_Pin
                           |D0_Pin|D1_Pin|D2_Pin|D3_Pin, GPIO_PIN_RESET);

   /*Configure GPIO pins : SEG_A_Pin SEG_B_Pin SEG_C_Pin SEG_D_Pin
                           SEG_E_Pin SEG_F_Pin SEG_G_Pin SEG_H_Pin
                            D0_Pin D1_Pin D2_Pin D3_Pin*/
   GPIO_InitStruct.Pin = SEG_A_Pin|SEG_B_Pin|SEG_C_Pin|SEG_D_Pin
                        |SEG_E_Pin|SEG_F_Pin|SEG_G_Pin|SEG_H_Pin
                        |D0_Pin|D1_Pin|D2_Pin|D3_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}

// Надрукувати число на дисплеї
void LED7SegPrint(uint32_t incomingNumber)
{
 splitToDigit(incomingNumber, digit, NUM_DIGIT);
}

// Надрукувати числа в дисплей для кожного розряду окреме число
void LED7SegPrintSeparate(uint8_t* aDigit, uint8_t number_of_digits)
{
 for (uint8_t i = 0; i < number_of_digits; i++)
  {
   digit[i] = *(aDigit+i);
  }
}

// Запалювання потрібних сегментів та розрядів дисплею (динамічна індикація)
void LED7SegShow(void)
{
 for(uint8_t i = 0; i < sizeof(digit)/sizeof(digit[0]); i++)
 {
  for(uint8_t i = 0; i < NUM_DIGIT; i++)
  {
   digitPort[i] -> BRR = digitPin[i]; //Вимикаємо всі розряди
  }
  digitPort[i] -> BSRR = digitPin[i]; //Вмикаємо потрібний розряд індикатора
  digitToPort(*(digit+i));               //Виводимо цифру у потрібний розряд
  HAL_Delay(1);                          //Невеличка затримка. Хай цифра світиться якийсь час
 }
}

// Локальні, внутрішні функції

//Функція виставляє в порт потрібну цифру
void digitToPort (uint8_t digit)
{
 SEG_PORT -> ODR &= ~ALL_SEG; //Вимикаємо всі сегменти
 SEG_PORT -> ODR |= digitsp[digit]; //Запалюємо потрібні
}

// число з лічильника розбиває на окремі розряди. вхідні аргументи: значення лічильника, масив для розрядів, кількість розрядів.
void splitToDigit(uint32_t number, uint8_t* digit, uint8_t number_of_digits)
{
 uint32_t tmp = number;

 for (uint8_t i = 0; i < number_of_digits; i++)
 {
  *(digit+i) = tmp % 10;
  tmp = tmp / 10;
 }

}

/*--------------------------------------------------------------------------------*/
//  ENF OF FILE
/*--------------------------------------------------------------------------------*/

Як користуватись

За допомоги CubeMX

Створюєте новий проект в CubeMX, обираєте свій мікроконтролер, наприклад STM32F100RBT6, та позначаєте потрібні ніжки мікроконтролеру на вихід (GPIO_Output). Та не забуваймо дати назву ніжкам (Enter User Label) за принципом:

Сегменти:
  • Сегмент А дисплею - SEG_A,
  • Сегмент B дисплею - SEG_B,
  • Сегмент C дисплею - SEG_C,
  • Сегмент D дисплею - SEG_D,
  • Сегмент E дисплею - SEG_E,
  • Сегмент F дисплею - SEG_F,
  • Сегмент G дисплею - SEG_G,
  • Сегмент H (крапка) дисплею - SEG_H (за потреби);
Розряди:
  • Перший розряд - D0,
  • Другий розряд - D1,
  • Третій розряд - D2,
  • Четвертий розряд - D3;
Зробіть як на малюнку. Червоним позначено виводи до яких підключений дисплей. LED_BLUE, LED_GREEN та USER_BUTTON це периферія плати розробника STM32VLDiscovery. Нам знадобиться для прикладу ще й USER_BUTTON. Налаштуйте ніжку до якої під'єднана кнопка на вхід:
Налаштування підключення дисплею в CubeMX
Генеруєте код для свого засобу розробки. До згенерованого проекту додаєте файли бібліотеки. LED7Seg.h до теки "INC", а LED7Seg.c до теки "SRC" проекту. Та додаєте до файлу main.c такі рядки:
/* USER CODE BEGIN Includes */
#include <stdbool.h> // для оперування змінними типу bool
#include <led7seg.h> // підключаємо бібліотеку 7-сегментного дисплею
/* USER CODE END Includes */
В головній функції main(), оголосимо змінні потрібні для прикладу:
  /* USER CODE BEGIN 1 */
 uint32_t counter = 0;   // ініціалізуємо змінну лічильника 
 bool flagButton = false;  // ініціалізуємо змінну прапорця кнопки
  /* USER CODE END 1 */
Надрукуємо початкове значення лічильника на дисплей. По суті, ми просто задали яке число має світитись на дисплеї.
  /* USER CODE BEGIN 2 */
  LED7SegPrint(counter); // надрукуємо початкове значення лічильника на дисплей
  /* USER CODE END 2 */
Після цього рядка ще нічого не з'явиться на дисплеї, бо за саме світіння потрібних сегментів відповідає інша функція - LED7SegShow().
В безкінечному циклі буде опитування кнопки і коли натиснуто кнопку до лічильника додамо одиницю:
 /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
   // як натиснули кнопку і прапорець кнопки скинуто
   if(HAL_GPIO_ReadPin(USER_BUTTON_GPIO_Port,USER_BUTTON_Pin) && !flagButton)
   {
    LED7SegPrint(++counter);  // додали одиницю до лічильника
    flagButton = true;  // встановили прапорець кнопки
   } else if(!HAL_GPIO_ReadPin(USER_BUTTON_GPIO_Port,USER_BUTTON_Pin) && flagButton){
    flagButton = false;    // коли кнопку відпустили - скинули прапорець кнопки
   }
   LED7SegShow();   // засвітили потрібні сегменти на дисплеї
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */
Також в безкінечному циклі постійно викликається функція LED7SegShow(), яка відповідає за динамічну індикацію дисплею.
Якщо потрібно на дисплей вивести якісь специфічні символи, то тоді порядок такий:
  • якщо цього символу немає в бібліотеці (початково в бібліотеці "0-9", "-" і "пусто" (всі сегменти відключено), то треба його створити. Про це далі;
  • оголосити масив uint8_t розміром на кількість задіяних сегментів;
  • заповнити масив "кодами" символів;
  • вивести це на дисплей.
Наприклад, зобразимо на дисплеї "-, NOP, NOP, -", де "NOP" - це нічого, жоден сегмент не світиться.
Оголошуємо в програмі масив:
  uint8_t digit[4] = {}; // Масив для символів в кожен розряд дисплею окремо
Заповнюємо масив "кодами" символів:
digit[0] = MINUS; // -
digit[1] = NOP;   // NOP
digit[2] = NOP;   // NOP
digit[3] = MINUS; // -
Та друкуємо це на дисплей викликавши функцію LED7SegPrintSeparate з параметрами: digit - ім'я масиву та кількість сегментів дисплею:
LED7SegPrintSeparate(digit,4);
Звісно що світінням потрібних сегментів займеться функція LED7SegShow().

Як додати користувацькі символи

Розглянемо це на прикладі. Додамо користувацький символ - літеру "А".
До файлу LED7Seg.h додати такі рядки:
#define LITA ( SEG_F_Pin | SEG_E_Pin | SEG_A_Pin | SEG_B_Pin | SEG_C_Pin | SEG_G_Pin )  // з яких сегментів складається літера "А"
#define A 12    // код літери "А", або порядковий номер у масиві (код 10 та 11 зайнятий NOP і MINUS) 
А до файлу LED7Seg.c внесемо такі зміни. До масиву digitsp[] додамо ім'я створеного символу, що назначили у заголовному файлі:
//оголошуємо масив з можливими варіантами символами на індикатор
static const uint16_t digitsp[]={DIG0,DIG1,DIG2,DIG3,DIG4,DIG5,DIG6,DIG7,DIG8,DIG9,~ALL_SEG,SEG_G_Pin,LITA};
Це і все. Тепер можна наприклад вивести таку інформацію на дисплей, наприклад, "А2-4":
uint8_t digit[4] = {};
digit[0] = 4;          // 4
digit[1] = MINUS;      // -
digit[2] = 2;          // 2
digit[3] = A;          // A
LED7SegPrintSeparate(digit,4);

Без CubeMX

Якщо ви не використовуєте CubeMX, або не зазначили там ніжки, до яких підключено дисплей, то потрібно позначити їх в заголовному файлі:
// якщо не визначили ніжки і порти до яких під'єднано дисплей у файлі main.h за допомоги CUBEMX,
// то треба ніжки і порти позначити тут відповідно до електричної схеми підключення дисплею
#if !defined SEG_A_Pin
 #define SEG_A_Pin        GPIO_PIN_0
 #define SEG_A_GPIO_Port  GPIOB
#endif

#if !defined SEG_B_Pin
 #define SEG_B_Pin        GPIO_PIN_1
 #define SEG_B_GPIO_Port  GPIOB
#endif

#if !defined SEG_C_Pin
 #define SEG_C_Pin        GPIO_PIN_2
 #define SEG_C_GPIO_Port  GPIOB
#endif

#if !defined SEG_D_Pin
 #define SEG_D_Pin        GPIO_PIN_3
 #define SEG_D_GPIO_Port  GPIOB
#endif

#if !defined SEG_E_Pin
 #define SEG_E_Pin        GPIO_PIN_4
 #define SEG_E_GPIO_Port  GPIOB
#endif

#if !defined SEG_F_Pin
 #define SEG_F_Pin        GPIO_PIN_5
 #define SEG_F_GPIO_Port  GPIOB
#endif

#if !defined SEG_G_Pin
 #define SEG_G_Pin        GPIO_PIN_6
 #define SEG_G_GPIO_Port  GPIOB
#endif

#if !defined SEG_H_Pin
 #define SEG_H_Pin        0u
 #define SEG_H_GPIO_Port  0u
#endif

#if !defined D0_Pin
 #define D0_Pin         GPIO_PIN_8
 #define D0_GPIO_Port   GPIOB
#endif

#if !defined D1_Pin
 #define D1_Pin         GPIO_PIN_9
 #define D1_GPIO_Port   GPIOB
#endif

#if !defined D2_Pin
 #define D2_Pin         GPIO_PIN_10
 #define D2_GPIO_Port   GPIOB
#endif

#if !defined D3_Pin
 #define D3_Pin         GPIO_PIN_11
 #define D3_GPIO_Port   GPIOB
#endif

#if !defined D4_Pin
 #define D4_Pin         0u
 #define D4_GPIO_Port   0u
#endif

#if !defined D5_Pin
 #define D5_Pin         0u
 #define D5_GPIO_Port   0u
#endif

#if !defined D6_Pin
 #define D6_Pin         0u
 #define D6_GPIO_Port   0u
#endif

#if !defined D7_Pin
 #define D7_Pin         0u
 #define D7_GPIO_Port   0u
#endif

#if !defined D8_Pin
 #define D8_Pin         0u
 #define D8_GPIO_Port   0u
#endif
Розрядам і сегментам які не будуть задіяні потрібно назначити значення 0u.
А до функції LED7SegInit() у файлі LED7Seg.c внести поправки, щоб порти і виводи відповідали електричній схемі, на який порт і виводи підключений дисплей. Наприклад якщо всі ніжки дисплею під'єднано до порту "B" мікроконтролера, то функція ініціалізації може виглядати так:
//Ініціалізація перифірії до якої підключено дисплей
void LED7SegInit(void)
{
 GPIO_InitTypeDef GPIO_InitStruct;

   /* GPIO Ports Clock Enable */
   __HAL_RCC_GPIOB_CLK_ENABLE();

   /*Configure GPIO pin Output Level */
   HAL_GPIO_WritePin(GPIOB, SEG_A_Pin|SEG_B_Pin|SEG_C_Pin|SEG_D_Pin
                           |SEG_E_Pin|SEG_F_Pin|SEG_G_Pin|SEG_H_Pin
                           |D0_Pin|D1_Pin|D2_Pin|D3_Pin, GPIO_PIN_RESET);

   /*Configure GPIO pins : SEG_A_Pin SEG_B_Pin SEG_C_Pin SEG_D_Pin
                            SEG_E_Pin SEG_F_Pin SEG_G_Pin SEG_H_Pin
                            D0_Pin D1_Pin D2_Pin D3_Pin*/
   GPIO_InitStruct.Pin = SEG_A_Pin|SEG_B_Pin|SEG_C_Pin|SEG_D_Pin
                         |SEG_E_Pin|SEG_F_Pin|SEG_G_Pin|SEG_H_Pin
                         |D0_Pin|D1_Pin|D2_Pin|D3_Pin;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
   HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}
Та не забувайте викликати цю функцію на початку програми, щоб ініціалізувати периферію. Все інше так само.

Файли

Архів з бібліотекою - LED7Seg
Архів з проектом для - True Studio & CubeMX

2 коментарі: