Форум программистов, компьютерный форум, киберфорум
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
82 / 2 / 0
Регистрация: 10.02.2024
Сообщений: 165

Как вы заменяете удобство классов С++ на СИ, при программировании под МК

04.01.2025, 11:46. Показов 3339. Ответов 60
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Всем доброго дня.
*(Хотя, кажется в этой ветке сидит одна небольшая группа людей, которые дают ответы на все мои вопросы. Спасибо вам, большое!)

-------------------------------------

В общем, ситуация такая: Начинал я программировать на с++ в arduino ide. Привык к работе с классами их удобству. Но, чтобы отстыковаться от arduino в принципе, начал изучение и потихоньку заменял ардуиовский фукнционал сишным кодом. Все получалось хорошо, пока не дошел до темы классов. До этого думал, что классы легко заменяются стурктурами и будут так же удобны в использовании, да еще и более эффективны.

Но Оказалось, что эффективность теряется, когда, в стремлении за удобством, я каждую функцию "класса" добавляю через указатель в структуру, чтобы было удобно использовать через точку
C
1
structObj.func()
. В этом случае в опертивку будут еще и помещяться указатели фукнций на каждый экземпляр структуры, а это капец жирно.

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

Так же видел варинаты, что к струткуре "класса" прописываются функции, к названию которых добавляется название "класса", чтобы в программе не пересекались имена. И вызывается функция, в которую передается указатель на структуру. Но это же тоже много лишних символов в коде появляется.

--------------------------------------

Проекты у меня большие, разбиваю их на разные файлы по ~300 строк кода, каждый файл это какой-то самостоятельный модуль и реализовывать его через класс, одно удовольствие. В проекте обучно около 10 таких отдельных модулей. Т.е. программа большая.

Но я теперь в тупике и не знаю что делать. Без классов на с++ программа станет сильно менее читаемой. А оставаясь на си, я вроде как теряю какие-то приемущества в низкоуровневости и быстродейсвии СИ на МК.

И в итоге, вопрос: как вы, опытные разработчики МК, решаете этот вопрос? Какие "парадигмы" используете при написании больших программ на СИ? Или вообще на СИ переходит нет прям какой-то необходимости? Или есть?

В общем, прошу, высказать, ваше мнение.

--------------------------------------

*Так же на вопрос "зачем мне вообще использовать классы на мк". У меня кажды программа сильно похожа на предыдущую, только меняется количство подключенной переферии. А сейчас я сделал такую модель , что есть 1 центральный контроллер, и он может общаться с любым количеством дочерних. На каждом дочернем одна программа, которая готова, по команде центрального, создать любой из нужных мне объектов и повесить на нужный пин. Такми образом я имею неограниченое число универсальных пинов, а на всех дочерних платах одинаковй код. И такая универсальность очень тесно завязана на классах. Вот именно, при мыслях о переходе с классов на структуры у меня и возникли проблемы.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
04.01.2025, 11:46
Ответы с готовыми решениями:

В чём удобство классов? (Общая тема (дискуссионная)
Всем, добрый день! Мой вопрос будет общего характера. И кому будет не жалко своего времени, хотелось бы услышать ответ. А вопрос в...

Смерть под обломками за удобство
Хакеры кндр украли 600 млн долларов на строительство ракет ссылка...

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

60
443 / 168 / 29
Регистрация: 12.12.2020
Сообщений: 1,342
08.01.2025, 23:10
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Еще как! В моих библиотеках они активно используются:
у меня самые популярные это такие:

C
1
2
3
#define   SETBIT(reg, bit)          reg |= (1<<bit)           
#define   CLRBIT(reg, bit)       reg &= (~(1<<bit))
#define   INVBIT(reg, bit)          reg ^= (1<<bit)
ну и т.д.
0
Эксперт .NET
 Аватар для Rius
13294 / 7753 / 1683
Регистрация: 25.05.2015
Сообщений: 23,614
Записей в блоге: 14
08.01.2025, 23:15
А у нас за такое по рукам бьют и pr отклоняют.
0
443 / 168 / 29
Регистрация: 12.12.2020
Сообщений: 1,342
08.01.2025, 23:18
А почему? Помоему очень повышает читаемость кода
0
Эксперт .NET
 Аватар для Rius
13294 / 7753 / 1683
Регистрация: 25.05.2015
Сообщений: 23,614
Записей в блоге: 14
08.01.2025, 23:40
Помимо этого, в аргументы можно передать всякое и компилятор не поперхнётся.
И только потом вы когда-нибудь обнаружите, что вот у того регистра такого-то бита и в помине не было, опечатка, которую никто не заметил, а компилятор не имел возможности отследить.
Или что данные разных типов были приведены для совершения операции к какому-то типу по разумению компилятора и получился нежданчик. Но не при написании, а при эксплуатации.
Это потенциальный баг.
0
 Аватар для COKPOWEHEU
4087 / 2685 / 432
Регистрация: 09.09.2017
Сообщений: 11,941
08.01.2025, 23:43
Цитата Сообщение от Alex1126 Посмотреть сообщение
у меня самые популярные это такие:
А с какой целью ухудшаете читаемость кода? Если уж оборачивать куда более наглядные &=,|= в макросы, то хоть там, где это имеет смысл:
C
1
PM_BITMASK(TIM3->CHCTLR1, TIM_OC1M, 0b110); //В регистре TIM3->CHCTLR1 стирает биты по маске TIM_OC1M и выставляет вместо них соответственно сдвинутые 0b110
0
443 / 168 / 29
Регистрация: 12.12.2020
Сообщений: 1,342
08.01.2025, 23:43
Ну так используя первоначальную конструкцию
C
1
reg |= (1<<bit)
так же подставить всякое и так же потом только обнаружить что у этого регистра такого бита не было никогда...
0
 Аватар для COKPOWEHEU
4087 / 2685 / 432
Регистрация: 09.09.2017
Сообщений: 11,941
08.01.2025, 23:45
Цитата Сообщение от Rius Посмотреть сообщение
И только потом вы когда-нибудь обнаружите, что вот у того регистра такого-то бита и в помине не было
От этого по большому счету не застрахуешься. Разве что весь заголовочный файл переписывать.
0
Эксперт .NET
 Аватар для Rius
13294 / 7753 / 1683
Регистрация: 25.05.2015
Сообщений: 23,614
Записей в блоге: 14
08.01.2025, 23:47
Исходные операции тоже, да.
В этом месте и рулит c++.
0
443 / 168 / 29
Регистрация: 12.12.2020
Сообщений: 1,342
08.01.2025, 23:49
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
А с какой целью ухудшаете читаемость кода?
Как правило при настройке перефирии я не использую эти макросы, там я пишу полностью
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    // Установка скорости обмена
    UBRRH = (F_CPU/(16*UART_BAUD)-1) >> 8;
    UBRRL = (F_CPU/(16*UART_BAUD)-1);
 
    UCSRB = 
        (1<<RXCIE) |    //RXCIE-разрешение прерывания по завершению приёма
        (1<<TXCIE) |    //TXCIE-разрешение прерывания по завершению передачи
        (0<<UDRIE) |    //UDRIE-разрешение прерывания при очистке регистра данных UDR
        (1<<RXEN) |     //RXEN-разрешение приёма
        (1<<TXEN) |     //TXEN-разрешение передачи
        (0<<UCSZ2) |    //UCSZ2-формат посылки (совместно с UCSZ1-UCSZ0 "0"-8 бит данных, "1"-9 бит данных)
        0;
    UCSRC =                 //Режим UART, 1 стоп-бит, 8 бит кадр, без паритета
        //(1<<UMSEL01) |    //UMSEL=0- асинхронный режим работы USART
        //(1<<UMSEL00) |
        //(1<<UPM01) |      //UPM1-UPM0=00 без контроля чётн/нечётн
        //(1<<UPM00) |
        //(1<<USBS0) |      //USBS0=0 - 1 стоп-бит
        //(1<<UCSZ02) |
        (1<<UCSZ1) |    //формат посылки UCSZ2-UCSZ0=0b011 - 8 бит в кадре
        (1<<UCSZ0) |
        (0<<UCPOL) |    //UCPOL - для асинхронного режима ДОЛЖЕН быть сброшен в 0
        0;
а вот когда работаю с пинами то там да (и то стараюсь обернуть в более понятные косструкции):

C
1
2
3
4
#define CLK_ON  SETBIT(RG_PORT,CLK)
#define CLK_OFF CLRBIT(RG_PORT,CLK)
#define ZD_ON   SETBIT(RG_PORT,ZD)
#define ZD_OFF  CLRBIT(RG_PORT,ZD)
0
 Аватар для COKPOWEHEU
4087 / 2685 / 432
Регистрация: 09.09.2017
Сообщений: 11,941
08.01.2025, 23:50
И как же он рулит? Вот есть запись RCC->APB1PCENR |= RCC_IOPAEN;. Как ваш хваленый С++ узнает, что IOPAEN относится не к APB1, а к APB2? В хедерах он описан просто как #define RCC_IOPAEN ((uint32_t)0x00000004). Предлагаете переписать 5000 строк однообразных дефайнов? Вот уж удобство так удобство.
0
Эксперт .NET
 Аватар для Rius
13294 / 7753 / 1683
Регистрация: 25.05.2015
Сообщений: 23,614
Записей в блоге: 14
08.01.2025, 23:56
Предлагаете переписать 5000 строк однообразных дефайнов? Вот уж удобство так удобство
Ну у вас же есть файлы описания регистров от производителя чипа? Парсите их и генерите код. Вручную не надо писать, потому что так допустить ошибку - как нефиг делать.
0
 Аватар для COKPOWEHEU
4087 / 2685 / 432
Регистрация: 09.09.2017
Сообщений: 11,941
08.01.2025, 23:57
Цитата Сообщение от Alex1126 Посмотреть сообщение
а вот когда работаю с пинами то там да (и то стараюсь обернуть в более понятные косструкции):
А теперь представьте, что один светодиод у вас висит на PA3, второй на PB7, третий на PC1. А на другой отладочной плате их было удобнее развести на PB0, PB4, PB2. Не обеспечивают ваши макросы должной гибкости.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Вот есть запись RCC->APB1PCENR |= RCC_IOPAEN;
Кстати, если уж хочется заняться копипастом, то битовые поля есть и в Си, так что и тут никакого выигрыша не будет.
0
Эксперт .NET
 Аватар для Rius
13294 / 7753 / 1683
Регистрация: 25.05.2015
Сообщений: 23,614
Записей в блоге: 14
08.01.2025, 23:59
Компания нанавистников cube, hal и прочих библиотек, во главе с эдди, чтоб ему вечно в бане сидеть, годами втирает, что тысячи строк готового кода от производителя - отстой. Так что всё в русле.
0
 Аватар для COKPOWEHEU
4087 / 2685 / 432
Регистрация: 09.09.2017
Сообщений: 11,941
09.01.2025, 00:04
Цитата Сообщение от Rius Посмотреть сообщение
Ну у вас же есть файлы описания регистров от производителя чипа? Парсите их и генерите код.
То есть все-таки мартышкин труд. Производитель уже сам написал заголовочные файлы, в которых эти биты описаны. Вы же хотите эту работу повторить, но руками и на основе текстового описания, которое менее надежно. Хедер-то хотя бы тестировался, а вот ошибки в .svd ни на что не влияют, и вполне могут быть пропущены. Не говоря уж о том, что не для всех камней эти svd вообще есть.

Добавлено через 2 минуты
Цитата Сообщение от Rius Посмотреть сообщение
тысячи строк готового кода от производителя - отстой.
С тем, что исполняемый код у них отстой, вряд ли кто будет спорить. Но в константах-то где можно накосячить?! Хотя умудряются, да. То два независимых 32-битных регистра в одну 64-битную переменную склеят (а способов атомарного доступа не завезут), то наоборот, то половину битов описать забудут.
0
Эксперт .NET
 Аватар для Rius
13294 / 7753 / 1683
Регистрация: 25.05.2015
Сообщений: 23,614
Записей в блоге: 14
09.01.2025, 00:06
COKPOWEHEU, то есть у нас с вами всего лишь разные ценности. У нас - избежать ошибок при кодировании максимально возможной автоматизацией для минимизации ошибок от человеческого фактора.
0
443 / 168 / 29
Регистрация: 12.12.2020
Сообщений: 1,342
09.01.2025, 00:06
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
А теперь представьте, что один светодиод у вас висит на PA3, второй на PB7, третий на PC1. А на другой отладочной плате их было удобнее развести на PB0, PB4, PB2. Не обеспечивают ваши макросы должной гибкости.
Ну так я же привел код. Вот более полный кусок:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define LOW     CHKBIT(PIND,PD2)
#define HI      CHKBIT(PIND,PD3)
 
#define LOW_BUTT    PA0
#define HI_BUTT     PA1
#define BUTT_PORT   PINA
 
#define BUTT_LOW_PRESS  CHKBIT(BUTT_PORT,LOW_BUTT)
#define BUTT_HI_PRESS   CHKBIT(BUTT_PORT,HI_BUTT)
 
#define RG_PORT PORTB
#define DT  PB2
#define CLK PB1
#define ZD  PB0
 
#define CLK_ON  SETBIT(RG_PORT,CLK)
#define CLK_OFF CLRBIT(RG_PORT,CLK)
#define ZD_ON   SETBIT(RG_PORT,ZD)
#define ZD_OFF  CLRBIT(RG_PORT,ZD)
Порты и пины меняются в одном месте под конкретный проект, конкретную плату.
0
Эксперт .NET
 Аватар для Rius
13294 / 7753 / 1683
Регистрация: 25.05.2015
Сообщений: 23,614
Записей в блоге: 14
09.01.2025, 00:06
Дубль
0
443 / 168 / 29
Регистрация: 12.12.2020
Сообщений: 1,342
09.01.2025, 00:06
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
А теперь представьте, что один светодиод у вас висит на PA3, второй на PB7, третий на PC1. А на другой отладочной плате их было удобнее развести на PB0, PB4, PB2. Не обеспечивают ваши макросы должной гибкости.
Ну так я же привел код. Вот более полный кусок:

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define LOW     CHKBIT(PIND,PD2)
#define HI      CHKBIT(PIND,PD3)
 
#define LOW_BUTT    PA0
#define HI_BUTT     PA1
#define BUTT_PORT   PINA
 
#define BUTT_LOW_PRESS  CHKBIT(BUTT_PORT,LOW_BUTT)
#define BUTT_HI_PRESS   CHKBIT(BUTT_PORT,HI_BUTT)
 
#define RG_PORT PORTB
#define DT  PB2
#define CLK PB1
#define ZD  PB0
 
#define CLK_ON  SETBIT(RG_PORT,CLK)
#define CLK_OFF CLRBIT(RG_PORT,CLK)
#define ZD_ON   SETBIT(RG_PORT,ZD)
#define ZD_OFF  CLRBIT(RG_PORT,ZD)
Порты и пины меняются в одном месте под конкретный проект, конкретную плату.
0
 Аватар для COKPOWEHEU
4087 / 2685 / 432
Регистрация: 09.09.2017
Сообщений: 11,941
09.01.2025, 00:13
Цитата Сообщение от Rius Посмотреть сообщение
COKPOWEHEU, то есть у нас с вами всего лишь разные ценности. У нас - избежать ошибок при кодировании максимально возможной автоматизацией для минимизации ошибок от человеческого фактора.
А у нас - чтобы контроллер работал так, как мы хотим. Предсказуемо, просто, эффективно и читаемо.
Цитата Сообщение от Alex1126 Посмотреть сообщение
Ну так я же привел код. Вот более полный кусок:
А теперь перенесите CLK на PC6.
Для сравнения, как я делал давным-давно, когда еще активно писал под AVR:
C
1
2
3
4
5
6
7
#define LCD_RST     D,7
#define LCD_CE      B,0
#define LCD_DC      B,4
...
DDR_1(LCD_RST); PORT_1(LCD_RST);
DDR_1(LCD_CE); PORT_1(LCD_CE);
DDR_1(LCD_DC); PORT_1(LCD_DC);
0
Эксперт .NET
 Аватар для Rius
13294 / 7753 / 1683
Регистрация: 25.05.2015
Сообщений: 23,614
Записей в блоге: 14
09.01.2025, 00:18
COKPOWEHEU, у нас тоже.
Разница в том, что с макросами вы оставляете место для будущих ошибок. Но вам можно.
А нам нельзя. Однажды обнаруженное никогда не должно повториться.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
09.01.2025, 00:18
Помогаю со студенческими работами здесь

Как рассчитываются задержки в функции Delay_ms при программировании на ATmega32?
Добрый день! Подскажите, пожалуйста, как рассчитываются задержки... В microC есть функция Delay_ms. Например, Delay_ms(11). Она...

Что в программировании подразумевается под объединением?
Здравствуйте,что в программировании считается объединением? 1)5 пункт.Что подразумевается под объединением P? просто последовательная...

Пропадает гаджет-часы при изменении масштаба шрифтов и значков (Удобство чтения с экрана)
Драстя. Столкнулся с неприятной байдой: спарва я поместил гаджеты календаря и часов. Решил все увеличить чтоб глаза не напрягать, но при...

Программировании сенсорного дисплея для планшетного компьютера под Windows 7
Прощу прощенья если вопрос задан не в том разделе. Но я не знаю какой именно язык программирования мне необходим, да и к софту вопрос не...

Как лучше делить приложение при программировании в WF? А то кодовая каша получается. Вообще читать невозможно
Как лучше делить приложение при программировании в WF? А то кодовая каша получается. Вообще читать невозможно.


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
[golang] Угол между стрелками часов
alhaos 12.05.2026
По заданным значениям часа и минуты необходимо определить значение меньшего угла между стрелками аналогового циферблата часов. import "math" func angleClock(hour int, minutes int) float64 { . . .
Debian 13: Установка Lazarus QT5
ВитГо 09.05.2026
Эта инструкция моя компиляция инструкций volvo https:/ / www. cyberforum. ru/ blogs/ 203668/ 10753. html и его же старой инструкции по установке Lazarus с gtk2. . .
Нейросеть на алгоритме "эстафета хвоста" как перспектива.
Hrethgir 06.05.2026
На десерт, когда запущу сервер. Статья тут https:/ / habr. com/ ru/ articles/ 1030914/ . Автор я сам, нейросеть только помогает в вопросах которые мне не известны - не знаю людей которые знали-бы. . .
Асинхронный приём данных из COM-порта
Argus19 01.05.2026
Асинхронный приём данных из COM-порта Купил на aliexpress термопринтер QR701. Он оказался странным. Поключил к Arduino Nano. Был очень удивлён. Наотрез отказывается печатать русские буквы. Чтобы. . .
попытка написать игровой сервер на C++
pyirrlicht 29.04.2026
попытка написать игровой сервер на плюсах с открытым бесконечным миром. возможно получится прикрутить интерпретатор питон для кастомизации игровой логики. что есть на текущий момент:. . .
Контроль уникальности выбранного документа-основания при изменении реквизита
Maks 28.04.2026
Алгоритм из решения ниже разработан на примере нетипового документа "ЗаявкаНаРемонтСпецтехники", разработанного в КА2. Задача: уведомлять пользователя, если указанная заявка (документ-основание). . .
Благородство как наказание
Maks 24.04.2026
У хорошего человека отношения с женщинами всегда складываются трудно. А я человек хороший. Заявляю без тени смущения, потому что гордиться тут нечем. От хорошего человека ждут соответствующего. . .
Валидация и контроль данных табличной части документа перед записью
Maks 22.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в КА2. Задача: контроль и валидация данных табличной части документа перед записью с учетом регламента компании. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru