0 / 0 / 0
Регистрация: 06.09.2016
Сообщений: 27
1

Как оптимизировать код СИ? atmega8

23.05.2023, 18:14. Показов 478. Ответов 15

Студворк — интернет-сервис помощи студентам
Здравствуйте, проблема такая. Пишу код для микроконтроллера для блока вынужденных колебаний. Столкнулся с проблемой переполнение памяти, причину не могу найти. Значит в функции control_outlet2, если заменить переменную value_frequency на любое целое число, то выходной hex файл разгружается аж на 5кб, и загружается естественно если эту переменную оставить, что критично в ситуации прошивки данного микроконтроллера. Вот кусок кода, проблемная функция и главный обработчик событий.
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
volatile uint8_t value_inlet1;
volatile uint8_t value_outlet1;
volatile uint8_t value_pause;
volatile uint8_t value_inlet2;
volatile uint8_t value_outlet2;
volatile uint8_t value_frequency;
 
// Функция управления выпуском2
void control_outlet2() {
    if (timer_flag_outlet2) {
        timer_flag_outlet2 = 0;
 
        // Расчет времени работы выпуска2
        uint16_t total_time = (uint16_t)((1.0 / (0.4 + (3.6 * (value_frequency / 99.0)))) * 1000);
        uint16_t outlet2_time = (value_outlet2 * total_time) / 100;
        
        if (outlet2_time <= total_time) {
            // Включение выпуска2
            PORTC |= (1 << PIN_OUTLET2);
            for (int i = 0; i < outlet2_time; i++) {
                _delay_ms(1);
            }
            PORTC &= ~(1 << PIN_OUTLET2);
        }
    }
}
 
 
int main() {
    
    // Установка пинов ввода/вывода
    DDRC |= (1 << PIN_INLET1) | (1 << PIN_OUTLET2);
    
    timer_init();
    lcdInit();
    initializeButtons();
    // lcdSetDisplay(LCD_DISPLAY_ON);
    // lcdSetCursor(LCD_CURSOR_OFF);
    
    
    
    // Загрузка значений из EEPROM
    readDigitsFromEEPROM();
    
    while (1) {
        
        value_inlet1 = (digits[0] * 10 + digits[1]);
        value_outlet1 = (digits[3] * 10 + digits[4]);
        value_pause = (digits[6] * 10 + digits[7]);
        value_inlet2 = (digits[9] * 10 + digits[10]);
        value_outlet2 = (digits[12] * 10 + digits[13]);
        value_frequency = (digits[14] * 10 + digits[15]);
        
        // Чтение состояния кнопок и обработка нажатий
        if (!(PIND & (1 << BUTTON_UP))) {
            _delay_ms(10); // Для устранения дребезга контактов
            processButtonPress(BUTTON_UP);
            while (!(PIND & (1 << BUTTON_UP)));
        }
        if (rightButtonState == 1) {
            if (!(PIND & (1 << BUTTON_DOWN))) {
                _delay_ms(10); // Для устранения дребезга контактов
                processButtonPress(BUTTON_DOWN);
                while (!(PIND & (1 << BUTTON_DOWN)));
            }
            rightButtonState = 0;
        }
        if (enterButtonState == 1) {
            if (!(PIND & (1 << BUTTON_ENTER))) {
                _delay_ms(10); // Для устранения дребезга контактов
                processButtonPress(BUTTON_ENTER);
                while (!(PIND & (1 << BUTTON_ENTER)));
            }
            enterButtonState = 0;
        }
        
        // Код основной программы
        
        // Расчет времени работы впуска1
        //control_inlet1();
 
        // Расчет времени работы выпуска
        control_outlet2();
        
        // Отображение значений на дисплее
        displayValues();
    }
 
    return 0;
}
Я убирал все значения с плавающей точкой в данном вычислении все приходило в норму более менее где то на 4 кб разгрузилось. Но здесь обязательны эти значения. Пытался найти другие выходы, способы, формулы, чтобы избежать этих чисел, но никак везде так или иначе присутствуют точки
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
23.05.2023, 18:14
Ответы с готовыми решениями:

Как можно оптимизировать код? Код считывает кол-во скобок
s = input() s = cheked = set() ans = 0 L = len(s) for l in range(L+1 if L % 2 else L, 1, -2):...

Как можно максимально оптимизировать данный код через логическое индексирование? Код полностью работает
header = data = , , , , , , , , , , , , ] import numpy as np def...

Как оптимизировать код
Доброй ночи господа у меня к вам такая просьба как можно упростить данный код? #include &lt;iostream&gt;...

Как оптимизировать код?
Как мне оптимизировать этот код? import turtle WIDTH, HEIGHT = 320, 180 screen =...

15
429 / 307 / 125
Регистрация: 18.07.2017
Сообщений: 1,407
23.05.2023, 19:26 2
Цитата Сообщение от FaBios Посмотреть сообщение
Я убирал все значения с плавающей точкой в данном вычислении все приходило в норму более менее где то на 4 кб разгрузилось.
На сколько я помню, в avr нет аппаратной поддержки чисел с плавающей точкой. Поэтому приходится считать все это софтварно. Собственно, эти 4 кб, скорее всего? как раз и есть код для работы с double.
1
133 / 424 / 51
Регистрация: 23.11.2021
Сообщений: 2,337
Записей в блоге: 3
23.05.2023, 19:32 3
Цитата Сообщение от FaBios Посмотреть сообщение
uint16_t total_time = (uint16_t)((1.0 / (0.4 + (3.6 * (value_frequency / 99.0)))) * 1000)
Заменить все константы на целочисленные и поменять порядок вычислений.
Еще повезло, что у avr-gcc double 32-битный и является по сути псевдонимом float.
1
0 / 0 / 0
Регистрация: 06.09.2016
Сообщений: 27
24.05.2023, 16:47  [ТС] 4
Цитата Сообщение от Eddy_Em Посмотреть сообщение
Заменить все константы на целочисленные и поменять порядок вычислений.
Так и сделал, перевел все вычисления к миллисекундам. Пока не написал на форум додуматься не смог до этого (как обычно). Все равно конечно память заполнилась но уже не критично, думаю в камень должна влезть. Плюс еще и в симуляции протеуса как то по другому работать начало. Но я уже понял что протеусу лучше не особо доверять, кода дисплейчик на постоянное обновление ставил.

Цитата Сообщение от assemberist Посмотреть сообщение
На сколько я помню, в avr нет аппаратной поддержки чисел с плавающей точкой. Поэтому приходится считать все это софтварно.
Вот это интересно конечно, не знал. И что интересно (как начинающему) ему просто не нравится что ты пишешь ему с точками, но кода он сам вычисляет ведь в его вычислениях тоже эти точки присутствуют, но памяти меньше при этом схавал.
0
133 / 424 / 51
Регистрация: 23.11.2021
Сообщений: 2,337
Записей в блоге: 3
24.05.2023, 16:52 5
Цитата Сообщение от FaBios Посмотреть сообщение
конечно память заполнилась
printf и прочих непотребств нет в коде?
0
assemberist
24.05.2023, 17:03
  #6

Не по теме:

Цитата Сообщение от FaBios Посмотреть сообщение
Вот это интересно конечно, не знал.
Кроме того в некоторых младших контроллерах (в attiny13 и attiny85 например) нет еще и целочисленного деления. Что уж про мат. сопроцессор говорить.

0
0 / 0 / 0
Регистрация: 06.09.2016
Сообщений: 27
24.05.2023, 17:14  [ТС] 7
Цитата Сообщение от Eddy_Em Посмотреть сообщение
printf и прочих непотребств нет в коде?
Неа, у меня функции управления дисплеем, кнопки, таймеры, прерывания, работа с еепром, и вот основное вычисление, до него hex файл 4 кб весил.

Добавлено через 8 минут
Цитата Сообщение от assemberist Посмотреть сообщение
Кроме того в некоторых младших контроллерах (в attiny13 и attiny85 например) нет еще и целочисленного деления. Что уж про мат. сопроцессор говорить.
Надо покурить эту информацию в инете, раз микроконтроллерами занялся. Мне просто на данный момент понадобилось заделать проектик для производства (чисто в своих интересах), там платка блок вынужденных колебаний, раскорячена на каких то микрухах, здоровая, старая, и уже не поставляется, думаю какая нить микруха выйдет погулять и не найдешь. А на атмеге все компактно и заменить можно все компоненты, ну и современно как то
0
429 / 307 / 125
Регистрация: 18.07.2017
Сообщений: 1,407
24.05.2023, 18:50 8
Цитата Сообщение от FaBios Посмотреть сообщение
Пытался найти другие выходы, способы, формулы, чтобы избежать этих чисел, но никак везде так или иначе присутствуют точки
По-моему, можно провести ряд обычных школьных преобразований.
https://www.cyberforum.ru/cgi-bin/latex.cgi?\frac{1.0}{0.4 + 3.6 * \frac{frequency}{99.0}} * 1000 = \frac{1000.0}{0.4 + 3.6 * \frac{frequency}{99.0}} = \frac{10000.0}{4.0 + 36.0 * \frac{frequency}{99.0}} = \frac{10000.0}{4.0 + 4.0 * \frac{frequency}{11.0}}
https://www.cyberforum.ru/cgi-bin/latex.cgi?\frac{10000.0}{4.0 * (1.0 + \frac{frequency}{11.0})} = \frac{2500.0}{1.0 + \frac{frequency}{11.0})} = \frac{2500.0}{\frac{11.0 + frequency}{11.0})} = \frac{27500.0}{11.0 + frequency}
1
Модератор
Эксперт по электронике
8806 / 6589 / 894
Регистрация: 14.02.2011
Сообщений: 23,171
24.05.2023, 22:19 9
Цитата Сообщение от FaBios Посмотреть сообщение
Мне просто на данный момент понадобилось заделать проектик для производства
выбери хотя бы stm32f4xx или постарше, там присутствует поддержка чисел с плавающей точкой, да и памяти там побольше
0
73 / 24 / 6
Регистрация: 26.11.2022
Сообщений: 178
25.05.2023, 00:23 10
Цитата Сообщение от ValeryS Посмотреть сообщение
выбери хотя бы stm32f4xx или постарше, там присутствует поддержка чисел с плавающей точкой, да и памяти там побольше
судя по тому что в коде присутствует
C
1
_delay_ms(10);
а так же
C
1
2
3
4
5
// Включение выпуска2
            PORTC |= (1 << PIN_OUTLET2);
            for (int i = 0; i < outlet2_time; i++) {
                _delay_ms(1);
            }
тут любой микроконтроллер не справится. ибо он будет занят только ожиданиями )

нельзя так писать систему управления чем - либо
0
3575 / 2243 / 406
Регистрация: 09.09.2017
Сообщений: 9,392
25.05.2023, 02:20 11
Цитата Сообщение от FaBios Посмотреть сообщение
На сколько я помню, в avr нет аппаратной поддержки чисел с плавающей точкой. Поэтому приходится считать все это софтварно.
Вот это интересно конечно, не знал. И что интересно (как начинающему) ему просто не нравится что ты пишешь ему с точками, но кода он сам вычисляет ведь в его вычислениях тоже эти точки присутствуют, но памяти меньше при этом схавал.
Это элементарно проверяется просмотром дизассемблерного листинга. Если включена отладочная информация (а она по умолчанию включена), то строчку Си-шного кода можно найти просто поиском. А дальше смотрите много ли ассемблерных инструкций она занимает. Особое внимание, естественно, всяким call, rcall и т.п.
А на счет "внутри с точкой" тоже будьте осторожны. Если в формуле вы не задали ни одного дробного числа, то и расчет будет целочисленным: 1/2 == 0. Плюс те расчеты, которые компилятор может провести на этапе компиляции, он сразу и проведет, а в код подставит только число-результат.
Цитата Сообщение от FaBios Посмотреть сообщение
думаю какая нить микруха выйдет погулять и не найдешь. А на атмеге все компактно и заменить можно все компоненты, ну и современно как то
Направление правильное, но "недожали". В том смысле что AVR тоже устарели, лучше уже осваивать ARM или RISC-V. stm32, gd32, ch32 и т.п. Но с ними свои проблемы.
Во-первых, довольно неприятные корпуса с шагом 0.5 мм. Гораздо труднее изготовить плату и потом запаять. Есть, конечно, костыль в виде готовых плат-переходников вроде blue-pill, black-pill, longan nano и подобных.
Во-вторых, гораздо более сложная начинка. Там, где в AVR достаточно выставить пяток битов в трех регистрах, тут придется изучать пару десятков регистров. Из них нужно те же три, но поначалу решительно непонятно какие именно. В общем, документации изучать придется на порядок больше. Опять же есть костыль в виде ST-cube, но и на нем без знаний далеко не уедешь. А если знания есть - сам Куб начинает мешать. Уж больно поганый код он генерирует.
1
0 / 0 / 0
Регистрация: 06.09.2016
Сообщений: 27
25.05.2023, 11:27  [ТС] 12
Цитата Сообщение от Aledveu Посмотреть сообщение
тут любой микроконтроллер не справится. ибо он будет занят только ожиданиями )
Вы имеете ввиду как то таймерами это организовать? Но у меня проблема не с постоянными ожиданиями (пока что по крайней мере), даже если убрать этот код и просто оставить где присваивается переменная с вычислениями, то память так же остается загруженной.

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
А на счет "внутри с точкой" тоже будьте осторожны. Если в формуле вы не задали ни одного дробного числа, то и расчет будет целочисленным: 1/2 == 0. Плюс те расчеты, которые компилятор может провести на этапе компиляции, он сразу и проведет, а в код подставит только число-результат.
Действительно есть такое теперь. А я опять сидел думал что опять не так работает почему то.

Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
В том смысле что AVR тоже устарели, лучше уже осваивать ARM или RISC-V. stm32, gd32, ch32 и т.п. Но с ними свои проблемы.
Вы меня заинтересовали сильно что есть еще и arm какой-то. Ну после 20 минутного гугления, в голову пришла мысль что я ведь не адронный коллайдер программирую, мне бы просто помигать парочкой транзисторов грамотно. Я с avr то элементарные вещи пока не могу понять. То есть круто бы было разбираться в в технологиях помощнее, но кажется что для моих задач это лишнее. А задача у меня такая:
Есть 6 параметров - впуск1, выпуск1, пауза, впуск2, выпуск2, цикл. Первые 5 параметров задаются значениями от 1 до 99, это процент от всего времени на котором они заканчиваются. Цикл задается тоже от 1 до 99, но здесь это уже шкала, где 1 это 0,4 гц, а где 99 это 4 гц.. то есть это и есть то самое "все время". Вот и всё, не думаю что для этой задачи нужны мощные вычислительные процессы.
0
73 / 24 / 6
Регистрация: 26.11.2022
Сообщений: 178
25.05.2023, 12:32 13
Если программа не влезает в память контроллера - делайте дизассемблерный листинг и смотрите что больше всего занимает места. При этом не надо знать ассемблер так как при наличии отладочной информации вы увидите просто сколько строк занимает какая функция. так же не забывайте что у вас может быть мёртвый код из библиотек, или какие-нибудь ненужные данные типа шрифтов для ЖК

Судя по вашему описанию вам арифметика с плавающей точкой вообще не нужна и можно обойтись целочисленной.
Для начала аккуратно аналитически упростите математичесие выражения - как показал assemberist
но для применяемого результата, которые вы будете вставлять в условие проверки или в таймер

использование delay в главном цикле идея прохая поскольку в этом же цикле вы проверяете вышло ли время для подачи сигнала. Главный цикл не должен содержать никаких задержек.
0
3575 / 2243 / 406
Регистрация: 09.09.2017
Сообщений: 9,392
25.05.2023, 12:35 14
Цитата Сообщение от FaBios Посмотреть сообщение
Вы имеете ввиду как то таймерами это организовать?
Скорее, конечным автоматом или вообще RTOS. Если не сталкивались с подобным, лучше с конечного автомата начать.
Цитата Сообщение от FaBios Посмотреть сообщение
Вы меня заинтересовали сильно что есть еще и arm какой-то.
ARM это общее название кучи ядер. На нем основаны упомянутые stm32, gd32f и прочие. А еще, например, RaspberryPi. А еще, к примеру, Apple M1, но это уже совсем другой уровень.
И RISC-V это тоже ядро, и на нем тоже делают как контроллеры (gd32vf, ch32), так и процессоры.
Цитата Сообщение от FaBios Посмотреть сообщение
кажется что для моих задач это лишнее.
Не сомневаюсь. Наверняка современные 32-битные контроллеры для вас избыточны. Но именно эта область сейчас развивается, так что если хотите продолжать заниматься контроллерами, так или иначе придется их изучать. Плюс они бывают даже дешевле 8-биток.
Впрочем, если задача разовая, и сама эта тема вам не слишком интересна, никто не запрещает и на AVR оставаться.
0
429 / 307 / 125
Регистрация: 18.07.2017
Сообщений: 1,407
25.05.2023, 12:52 15
Цитата Сообщение от FaBios Посмотреть сообщение
Вы имеете ввиду как то таймерами это организовать? Но у меня проблема не с постоянными ожиданиями (пока что по крайней мере)
Да, не считать подошло ли время, а просто таймер завести, а void control_outlet2(); оформить как прерывание таймера.
Ну и плюсом можно высчитать задержки _delay_ms(10); и также организовать их через использование таймера (в atmega8 их 3).

Это поможет косвенно, потому что прямая работа с таймерами экономит больше памяти: Что там нужно?
1) Включить прерывание таймера по достижению значения. По сути запись 1-го байта в регистр.
2) Настроить режим работы таймера и предделитель Тоже самое.

Чтобы отмерять время.

3) Выставить текущее значение таймера
4) Загрузить время, которое должен отмерять таймер,
5) Включить сам таймер

6) забыть про него и идти заниматься другими делами. Когда таймер досчитает до загруженного значения он дернет прерывание.

7) Выполняем нужные действия
8) Если таймер больше не нужен останавливаем. А можно и не делать, тогда он будет отрабатывать с заданной частотой.
9) выходим из прерывания

Возможно что-то забыл, последний раз году в 18-м занимался, а даташит листать лень, но не суть.
За исключением 6-7 шагов Каждая операция занимает 2-8 байт ибо это обычное выставление значений в 1-2 регистрах. Но придется посидеть над даташитом. Ососбенно если раньше подобным не занимался.
0
429 / 307 / 125
Регистрация: 18.07.2017
Сообщений: 1,407
25.05.2023, 23:44 16
Цитата Сообщение от assemberist Посмотреть сообщение
Да, не считать подошло ли время, а просто таймер завести
Кстати, есть програмка avr wizard. Она генерит оптимальный инициализирующий код и функции прерываний. Мало того, так еще и комментарии пишет. С ней таймер тактование и вся остальная переферия настраиваются за 5 минут. Но даташит все-равно почитать придется чтобы понять что включаешь-выключаешь.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
25.05.2023, 23:44
Помогаю со студенческими работами здесь

Как оптимизировать код?
Написал программу, которая считает время, проведённое за компьютером. Каким образом её можно...

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

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

Как оптимизировать код
Привет! Как можно &quot;уменьшить&quot; данный код? string filename = @&quot;test.exe&quot;; //...

Как оптимизировать код?
как можно вместо кучи строк добавить цикл в запрос на MySQL? if (empty($error)) {...

Как оптимизировать код ?
Как привести его в порядок ? $(document).ready(function(){ var otherVideo =...

Как оптимизировать код
Решал задачу с информатикса. Все работает, но на одном из тестов выдает тайм-лимит. Можно ли...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2023, CyberForum.ru