Основы работы со структурами

Страница на этапе разработки

Сегодня мы рассмотрим работу структуры, что это такое и как ее можно использовать.
Описание структуры:

struct имя_типа{
  тип_1  элемент_1;
  тип_2  элемент_2;

  тип_n  элемент_n;
};

Смотря на описание тяжело понять что с ней делать и как ее можно использовать.
Для понимания структуры мы рассмотрим несколько примеров как ее можно использовать. Сам алгоритм программы для нас не важен, мы рассматриваем пример использования. И так, рассмотрим на примере светодиодов: допустим у нас есть два светодиода которыми мы хотим управлять один находится на PC13 второй на PA5. Для переключения их состояния мы используем функцию:
    HAL_GPIO_WritePin(port, pin, GPIO_PIN_RESET/SET);
Для переключения состояния светодиодов нам надо явно указывать порт и номер ножки и логическое состояние. Если у Вас большой программный код, можно допустить ошибку в указании данных, и тут на помощь нам приходит структура. Создадим нужную структуру нам:

typedef struct {
    GPIO_TypeDef  *port;  // указатель на порт (GPIOA, GPIOB, …)
     uint16_t pin;        // номер пина (GPIO_PIN_5, …)
    uint8_t state;       // логическое состояние (0/1)
} Led_t;
Теперь используем нашу структуру:
Led_t led1 = {GPIOC, GPIO_PIN_13, 0}; // светодиод на PC13
Led_t led2 = {GPIOA, GPIO_PIN_5, 0};  //светодиод на PA5
Функции для работы со структурой: 

void Led_On(Led_t *led) {
    HAL_GPIO_WritePin(led->port, led->pin, GPIO_PIN_SET);
    led->state = 1;
}

void Led_Off(Led_t *led) {
    HAL_GPIO_WritePin(led->port, led->pin, GPIO_PIN_RESET);
    led->state = 0;
}

void Led_Toggle(Led_t *led) {
    HAL_GPIO_TogglePin(led->port, led->pin);
    led->state = !led->state;
}

Теперь напишем основной программный код, где мы будем использовать структуру:

//объявим структуру
Led_t led1 = {GPIOC, GPIO_PIN_13, 0}; 
Led_t led2 = {GPIOA, GPIO_PIN_5, 0};

И в рабочем цикле опишем работу наших функций:

       Led_Toggle(&led1);
        HAL_Delay(500);
        Led_On(&led2);
        HAL_Delay(200);
        Led_Off(&led2);
        HAL_Delay(200);

Тоже самое мы можем сделать например для чтения данных с кнопки:

typedef struct {
    GPIO_TypeDef *port;   // порт кнопки
    uint16_t pin;         // пин кнопки
    uint8_t state;        // текущее устойчивое состояние (0 или 1)
    uint8_t lastState;    // последнее прочитанное состояние
    uint32_t lastDebounceTime; // время последнего изменения
    uint32_t debounceDelay;    // задержка для антидребезга (мс)
} Button_t;

Функция для работы с нашей кнопкой:

uint8_t Button_Read(Button_t *btn){
    uint8_t reading = HAL_GPIO_ReadPin(btn->port, btn->pin);
    if (reading != btn->lastState) {
          btn->lastDebounceTime = HAL_GetTick();  // запоминаем время
    }
    if ((HAL_GetTick() — btn->lastDebounceTime) > btn->debounceDelay) {
        if (reading != btn->state) {
            btn->state = reading;
        }
    }
    btn->lastState = reading;
    return btn->state;
}

Инициализация нашей кнопки:

Button_t button1 = {GPIOA, GPIO_PIN_0, 0, 0, 0, 50};// PA0, 50 мс антидребезг

Использование в программном коде:

Button_t button1 = {GPIOA, GPIO_PIN_0, 0, 0, 0, 50}; // кнопка на PA0
Led_t led1 = {GPIOC, GPIO_PIN_13, 0};                // LED на PC13
    while (1) {
        if (Button_Read(&button1)) {
            Led_On(&led1);
        } else {
            Led_Off(&led1);
        }
    }
Кроме удобства в использовании структуры когда у Вас много однотипных параметров, структуру можно использовать в подпрограммах когда нужно вернуть больше одного значения без использования массивов.