Помогите разобраться со структурой

Добрый день. Не могу разобраться со структурой. Программа работает, но не правильно.
Есть структура

struct ChannelPWM_t
{
    int8_t hour;   // час
    int8_t minute; // минута
    int8_t ledPWM; // Значение шим
};

Создаю массив в котором хранится расписание из пяти точек.

ChannelPWM_t schedulePWM[maxPointPWM]; // Расписание - массив из 5 точек хранится во внешнем EEPROM

Массив заполнен данными: “часы, минуты, значение ШИМ” для пяти точек:
16,0,0;
16,40,70;
20,0,70;
22,0,50;
23,0,0;

Данные из массива считываются правильно. Есть функция AutoMode, в которой при получении текущего времени от DS3231, вычисляэтся значение ШИМ для текущего времени. Но возникла проблема. При отладочном выводе в сериал отдельно значений, все выводится правильно. Для “Старта” - 16, 0 Для “Финиша” 23,0. Но в функции расчеты неправильные. Не могу понять что не так. Подозреваю, что при расчетах беруться адреса переменных, потому что значения нереальные.
Со структурами начал разбираться, но видно чего то не понимаю.
Вот код функции с коментрариями:

void AutoMode()
{
    uint32_t currentTime_UL = GetTime.hour * 3600 +
                              GetTime.minute * 60 +
                              GetTime.second;

    uint32_t TimeStart_UL = schedulePWM[0].hour * 3600 + // подозреваю, что подставляет адрес памяти
                            schedulePWM[0].minute * 60;  // а не значение переменных !!!!! Как записать Правильно?????

    uint32_t TimeFinish_UL = schedulePWM[maxPointPWM - 1].hour * 3600 + // подозреваю, что подставляет адрес памяти
                             schedulePWM[maxPointPWM - 1].minute * 60;  // а не значение переменных !!!!! Как записать Правильно?????

    // !!Отладочный вывод (начало)

    Serial.print("Current ");       // все нормально!!!
    Serial.println(currentTime_UL); // выводит адекватные значения

    Serial.print("schedulePWM.hour ");
    Serial.println(schedulePWM[0].hour); // выводит правильное значение
    Serial.print("schedulePWM.minute ");
    Serial.println(schedulePWM[0].minute); // выводит правильное значение
    Serial.print("Start ");
    Serial.println(TimeStart_UL); // БРЕД !!!!!
    Serial.println();

    Serial.print("schedulePWM.hour ");
    Serial.println(schedulePWM[maxPointPWM - 1].hour); // выводит правильное значение
    Serial.print("schedulePWM.minute ");
    Serial.println(schedulePWM[maxPointPWM - 1].minute); // выводит правильное значение
    Serial.print("Finish ");
    Serial.println(TimeFinish_UL); // БРЕД !!!!!
    Serial.println();

    // !!Отладочный вывод (конец)

    int8_t _currentPWM;

    if (currentTime_UL < TimeStart_UL)
    {
        Serial.println("111!!!"); // !!Отладочный вывод
        analogWrite(LEDPIN, 0);
    }

    if (currentTime_UL >= TimeStart_UL && currentTime_UL <= TimeFinish_UL)
    {
        Serial.println("222!!!"); // !!Отладочный вывод
        for (uint8_t i = 0; i < maxPointPWM - 1; i++)
        {

            uint32_t time1_UL;
            time1_UL = (schedulePWM[i].hour * 3600) + // Здесь по идеи тоже бред
                       (schedulePWM[i].minute * 60);

            uint32_t time2_UL;
            time2_UL = (schedulePWM[i + 1].hour * 3600) +
                       (schedulePWM[i + 1].minute * 60); // Здесь по идеи тоже бред

            if (currentTime_UL > time1_UL && currentTime_UL <= time2_UL)
            {
                _currentPWM = schedulePWM[i].ledPWM + (schedulePWM[i + 1].ledPWM - schedulePWM[i].ledPWM) *
                                                          (currentTime_UL - time1_UL) / (time2_UL - time1_UL);

                currentPWM = _currentPWM;
                analogWrite(LEDPIN, map(_currentPWM, 0, 99, 0, 255));
            }
        }
    }

А это результаты в сериал.

00:00:04
schedulePWM.hour 16
schedulePWM.minute 0
Start 4294959360 --------------------------------- Откуда такое число??? Должно же быть 57600

schedulePWM.hour 23
schedulePWM.minute 0
Finish 17264 ---------------------------------Откуда такое число??? Должно быть 82800

Current 4
111!!!
Mode : 2
Current_PWM = 0

Не могу понять почету при обращении к элементу в Serial.println выводит 16, 0, 23, 0, а при выводе расчетного значения выдает дичь?
Помогите разобраться. Заранее благодарю.

А где проверка выхода за границу массива?

1 лайк

И покажите, как заполняете массив данными

Наверное дело в преобразовании типов при вычислении. (Почитайте про это).
А пока добавьте всем константам в вычислениях окончание UL
schedulePWM[i].hour * 3600UL
Так же у вас используются и знаковые и не знаковые переменные. Это в данном случае вроде не влияет, но желательно понимать - может переменная быть отрицательной или нет.

2 лайка

UL помогло. Все заработало. Только не понимаю как это повлияло. Переполнения не должно же быть при uint32. Но все заработало.
Переменные сначала были беззнаковые, это уже на второй день менял, думал может поможет :smile:
Та много в коде уже исправлено было, но безрезультатно. Ифов тоже нужно поубирать лишних.
Огромная благодарность за помощь. Всего две буквы, а столько гемороя. Но зато за два дня начитался о структурах. :smile:

Помогло добавить UL.
проверку за гарницу не делал, так как в цикле стоит
for (uint8_t i = 0; i < maxPointPWM - 1; i++). По идеи выйти не должен.
Спасибо Вам за помощь. Удачи.

Если i == maxPointPWM - 1, то чему будет равно i + 1 ? И что выдаст

            time2_UL = (schedulePWM[i + 1].hour * 3600ul) +
                       (schedulePWM[i + 1].minute * 60ul); 

Вот тут-то вы за границу массива и выскакиваете

1 лайк

Как раз оно обязано там быть и реально возникало.

Первым вычисляется выражение в скобках. Операнды умножения иметь типы int8 и int16. Значит, считаться будет в int16. Часов там 16. 16 * 3600 = 57600 - что в int16 явно не лезет. Вот оно переполнение. А int32 появляется только при выполнении присваивания, когда переполнение уже произошло и пить боржом поздно.

Кстати, не думайте, что дело в скобках, без них то же самое, т.к. приоритет умножения выше, чем присваивания.

1 лайк

Понял Вас. Все правильно Вы написали.
по идеи если сделать
for (uint8_t i = 0; i < maxPointPWM - 2; i++)
тогда time2_UL при maxPointPWM = 5 максимально будет 4 (3+1).
будет правильней? Тогда не выйду за границы массива? Или можно как то грамотней сделать?
Нужно тогда пересмотреть заполнение тоже.

Спасибо за подсказку.

И все таки с массивом у меня было правильно. Выхода за границу нет. при -2 не работает. Сейчас разобрался там в цикле i < maxPointPWM-1.
При maxPointPWM = 5 цикл закончится при i=3, тогда i + 1 нормально. Ошибка бы была, если б условие выхода было i <= maxPointPWM-1
А так нормально все работает.