Форум программистов, компьютерный форум, киберфорум
Наши страницы
Микроконтроллеры ATmega AVR
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
Mihacrasavchik
-7 / 0 / 1
Регистрация: 11.06.2018
Сообщений: 10
1

Как переписать библиотеку Arduino содержащую классы на чистый Си для Atmega

14.01.2020, 04:56. Просмотров 548. Ответов 29
Метки нет (Все метки)

Я тут понял что классы в Си отсутствуют и их можно заменить структурами. Замена классов на структуры у меня вызывают сложности. Прошу по возможности привести примеры и объяснения
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.01.2020, 04:56
Ответы с готовыми решениями:

ATmega для Arduino
Здравствуйте! Сделал себе на днях Arduino. Когда дело дошло до контроллера я обзвонил все...

Как правильно переписать программу на чистый C с C++
Написал программу на C++, но оказалось что нужно на C (прошу прощения, если не правильно описал...

Как бы переписать меню с jQuery на чистый JS?
всем привет! помогите пожалуйста... вот есть классное меню: https://jsfiddle.net/rgtzfs5o/ но...

Ethernet shield к Arduino NG (Atmega 8)
Доброго Вам времени суток ув. форумчане. Недавно задался целью поднять веб сервер на arduino NG /...

Переделка библиотеки UTFT arduino под чистый Си AvrStudio
Имеется дисплей TFT 320х240 на контроллере ssd1289 попробывал найти библиотеку в сети что то...

29
ValeryS
Модератор
7966 / 5935 / 785
Регистрация: 14.02.2011
Сообщений: 20,420
Завершенные тесты: 1
14.01.2020, 05:45 2
Цитата Сообщение от Mihacrasavchik Посмотреть сообщение
Я тут понял что классы в Си отсутствуют и их можно заменить структурами.
в свете C++ что структура, что класс- одно и то же, разница в видимости
у структуры по умолчанию public, у класса privat
а в Си все по другому, например там нет в структурах конструкторов, функций-членов .....
так что заменить нельзя
1
Voland_
1744 / 1076 / 108
Регистрация: 04.01.2010
Сообщений: 3,706
14.01.2020, 09:56 3
Цитата Сообщение от ValeryS Посмотреть сообщение
в свете C++ что структура, что класс- одно и то же, разница в видимости
отчасти несогласный. В структуре нельзя удалить компонент, ввиду его неиспользуемости. А в классе компилятор свободно этим пользуется.

Цитата Сообщение от ValeryS Посмотреть сообщение
а в Си все по другому, например там нет в структурах конструкторов, функций-членов .....
ну как это нету? объявите в структуре указатель на функции - и будет вам счастье.

PS: в стандарте C99 даже инкапсуляция возможна. Вы можете вставить одну структуру в другую, и ее поля станут членами "родительской структуры", без вложенности.
0
COKPOWEHEU
2250 / 1358 / 308
Регистрация: 09.09.2017
Сообщений: 5,384
14.01.2020, 10:51 4
Цитата Сообщение от Voland_ Посмотреть сообщение
ну как это нету? объявите в структуре указатель на функции - и будет вам счастье.
и будет вместо прямого вызова функции извращения с загрузкой конкретного экземпляра структуры, считывание из памяти указателя и косвенный вызов. Плюс совершенно ненужный расход памяти на хранение указателей в каждом экземпляре.
Нет, если уж занимать "дословным" переводом, просто передают экземпляр структуры первым параметром (в С++ оно внутри так же реализовано, только от программиста скрыто).
Что-то вроде такого:
C++
1
2
3
4
5
6
7
8
class SomeClass{
public:
  int val;
  int func(int x){return val + x;}
};
...
SomeClass cl;
cl.func(1);
C
1
2
3
4
5
6
7
8
9
struct SomeStruct{
  int x;
};
int SomeStruct_func(struct SomeStruct *this, int val){
  return val + this->x;
}
...
struct SomeStruct str;
SomeStruct_func(&str, 1);
Другое дело, что такой дословный перевод обычно не имеет смысла.
Во-первых, сам подход языков несколько отличается, на Си проще написать набор функций, принимающих и передающих то, что им нужно, и не больше.
Во-вторых, сама реализация Ардуинских библиотек оставляет желать лучшего. Они писались под простоту и универсальность, а не под производительность и гибкость.
Так что стоит подумать не о "переводе", а о "пересказе", то есть не тупо воспроизводить чужую библиотеку, а, опираясь на нее, написать свою.
1
14.01.2020, 10:51
Voland_
1744 / 1076 / 108
Регистрация: 04.01.2010
Сообщений: 3,706
14.01.2020, 15:31 5
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
и будет вместо прямого вызова функции извращения с загрузкой конкретного экземпляра структуры, считывание из памяти указателя и косвенный вызов.
ну, я не утверждаю, просто если структуру объявить константой - компилятор "сечет" на этот счет, и может таки свернуть все к прямому вызову, либо косвенному вызову, но какому-нибудь быстрому. Тут зависит от ассемблера. И говорю в контексте gcc.
0
COKPOWEHEU
2250 / 1358 / 308
Регистрация: 09.09.2017
Сообщений: 5,384
14.01.2020, 16:35 6
Тут очень много ограничений, многое будет завязано на оптимизации и прочий ИИ компилятора.
Как минимум, распределение функций по единицам трансляции.
Да и потом, какой от этого выигрыш кроме чисто декоративного? Тот же this так или иначе придется передавать руками, как и обрабатывать. Функции перед инициализацией надо где-то прописать, тоже лишняя операция.
Единственное что так наследование можно смоделировать. Но как-то оно в Си-шном коде чужеродно выглядит.
0
joogorden
19 / 17 / 2
Регистрация: 31.01.2019
Сообщений: 77
14.01.2020, 17:42 7
А всём проблема использования C++ для Atmega?
0
COKPOWEHEU
2250 / 1358 / 308
Регистрация: 09.09.2017
Сообщений: 5,384
15.01.2020, 10:58 8
Теоретически ни в чем. В идеале на С++ можно написать код, не уступающий по производительности коду на Си, и даже обгоняющий его.
Вот только для этого надо четко осознавать какова сложность различных конструкций и свистелок. Придется сознательно отказываться от самых вкусных плюшек. В общем, бороться с языком.
Но если ограничиться диалектом "Си с классами", плюс constexpr, плюс шаблоны (аккуратно!) то вполне неплохо получается.
Не считая багов и оптимизации компилятора, когда код, собранный gcc оказывается лучше, чем он же, собранный g++.
Не считая совместимости, когда основной код на Си, а библиотеку какой-то... разработчик... решил написать на С++. И подключай как знаешь.
0
Mihacrasavchik
-7 / 0 / 1
Регистрация: 11.06.2018
Сообщений: 10
15.01.2020, 14:33  [ТС] 9
Цитата Сообщение от joogorden Посмотреть сообщение
А всём проблема использования C++ для Atmega?
Просто я программирую Arduino около трех лет, осенью делал небольшую программку на ассемблере. И теперь для меня Arduino IDE кажется легкой вещью, на которой ты не работаешь с железом, ассемблер слишком много времени отнимает в плане написания кода, и вот я решил попробовать программировать на C AVR и столкнулся с такими сложностями. Вот и задал вопрос.

Добавлено через 2 минуты
Цитата Сообщение от joogorden Посмотреть сообщение
А всём проблема использования C++ для Atmega?
А есть ПО для программирования AVR на C++, кроме Arduino IDE?
0
COKPOWEHEU
2250 / 1358 / 308
Регистрация: 09.09.2017
Сообщений: 5,384
15.01.2020, 15:18 10
Цитата Сообщение от Mihacrasavchik Посмотреть сообщение
А есть ПО для программирования AVR на C++, кроме Arduino IDE?
А что вам нужно для программирования на С++ кроме собственно компилятора (avr-g++), который можно прикрутить к любой среде разработки? Ну еще заливать прошивку через какую-нибудь avrdude.
1
joogorden
19 / 17 / 2
Регистрация: 31.01.2019
Сообщений: 77
15.01.2020, 17:34 11
Цитата Сообщение от Mihacrasavchik Посмотреть сообщение
А есть ПО для программирования AVR на C++, кроме Arduino IDE?
Например AtmelStudio
0
Изображения
Тип файла: png 1.PNG (159.6 Кб, 5 просмотров)
Mihacrasavchik
-7 / 0 / 1
Регистрация: 11.06.2018
Сообщений: 10
20.01.2020, 12:47  [ТС] 12
Блин, вот занялся кодом и какие-то ошибки пишет, не могу понять почему
0
Вложения
Тип файла: zip Архив ZIP - WinRAR.zip (14.8 Кб, 2 просмотров)
locm
20.01.2020, 13:17
  #13

Не по теме:

Цитата Сообщение от Mihacrasavchik Посмотреть сообщение
какие-то ошибки пишет
Вы их прочитать не можете? Здесь разместить или скрин выложить?

0
Mihacrasavchik
-7 / 0 / 1
Регистрация: 11.06.2018
Сообщений: 10
20.01.2020, 13:40  [ТС] 14
И вопрос в том как их исправить, и правильно ли я начал писать библиотеку, т.к. на просторах интернета как-то годной информации мало
0
Изображения
Тип файла: jpg 1.jpg (128.7 Кб, 6 просмотров)
COKPOWEHEU
2250 / 1358 / 308
Регистрация: 09.09.2017
Сообщений: 5,384
20.01.2020, 13:57 15
Цитата Сообщение от Mihacrasavchik Посмотреть сообщение
какие-то ошибки пишет
Очевидно, вам нужно что-то сделать, чтобы они пропали.
---
Код
StepDirDriver.c: In function ‘StepDirDriver_Init’:
StepDirDriver.c:10:2: error: ‘DDRD’ undeclared (first use in this function)
  DDRD|=(1<<s)|(1<<d)|(1<<e);//��������� ����� �� �����
В единице трансляции StepDirDriver (рекомендую ознакомиться, что означает этот термин) не объявлено что такое PORTD. Это стоит исправить.
Попутно хорошо бы поправить комментарии, чтобы они выглядели читаемым текстом, а не вопросами.
Код
main.c: In function ‘main’:
main.c:8:38: error: ‘StepDirDriver_Init’ undeclared (first use in this function)
  struct StepDirDriver Motor={3,4,5, &StepDirDriver_Init};
В единице трансляции main нет ни реализации, ни прототипа функции StepDirDriver_Init. Соответственно, невозможно получить ее адрес.
Попутно хорошо бы учесть 4-й комментарий и избавиться от плюсового запихивания методов в структуры. Выигрыша это не дает никакого - ни по читаемости, ни по быстродействию, ни по памяти - даже наоборот. Пусть себе остается отдельной функцией, в которую передается ссылка на объект.
---
StepDirDriver.h
C
1
2
3
int s;
int d;
int e;
Никогда не объявляйте переменные в заголовочных файлах! Я долго удивлялся почему компилятор не послал этот говнокод лесом.
C
1
2
3
s=p->pinStep;
d=p->pinDir;
e=p->pinEn;
Мало того, что для локальных целей используются глобальные переменные. Мало того, что у них тип неправильный. Так они еще и общие! За такое по рукам надо бить.
C
1
2
DDRD|=(1<<s)|(1<<d)|(1<<e);//”становка пинов на выход
PORTD|=(0<<s)|(0<<d)|(1<<e);//Ќачальные установки
Вы уверены, что "шаговый двигатель" будет висеть строго на PORTD?
Какой смысл несет запись PORTD |= (0<<x); ? Если вы думаете, что это установка бита в 0, я вас разочарую...
Почему у шагового двигателя всего 3 вывода? Всегда ж минимум 4 было.
Вот к комментариям претензий нет, хотя смотрятся диковато
---
На счет настройки выводов распишу еще подробнее. Операция сдвига на переменную достаточно затратна. Ради интереса посмотрите, в какое количество кода она разворачивается. Ее можно было бы оптимизировать заданием не номера бита, а маски. Но даже это не нужно, поскольку шаговых двигателей вряд ли будет настолько много, чтобы не позволить себе тупо скопипастить код каждого из них с индивидуальными настройками.
Ваш же подход криво скопирован с Ардуины, где он хоть как-то оправдан, поскольку там сквозная нумерация выводов без привязки к аппаратным портам. Естественно, это приводит к совершенно диким накладным расходам. С другой стороны, сам подход "электроника для домохозяек" изначально не про эффективность. Если хотите сделать по-человечески, можно пойти двумя путями:
Первый - хранить каждый пин как 3 или 4 переменные: адрес PORTx, адрес DDRx, адрес PINx, битовая маска:
C
1
2
3
4
5
6
struct Pin{
  volatile unsigned char *port;
  volatile unsigned char *ddr;
  volatile unsigned char *pin;
  unsigned char bitmask;
};
Теряем в оперативной памяти (кстати, не факт, можно во флешке хранить), немного выигрываем в скорости. При таком подходе функции для работы с ШД будут общими, передаются только наборы пинов.
Второй путь: макросы:
C
1
2
3
4
5
6
7
8
9
10
11
12
#define StepMotor_A D,3
#define StepMotor_B B,4
#define StepMotor_C A,1
#define StepMotor_D D,7
#define StepMorot_Name Drive
#include "StepMotor.h"
...
#define StepMotor_Name Rot
#include "StepMotor.h"
...
Drive_step(10);
Rot_step(-5);
(АХТУНГ! Писал из головы. Возможно, такой синтаксис не сработает).
Достоинства: максимальная скорость, простота настройки, почти не требует оперативки. Недостатки: вырвиглазный код на макросах; расход памяти программ.
0
Voland_
1744 / 1076 / 108
Регистрация: 04.01.2010
Сообщений: 3,706
20.01.2020, 15:38 16
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Я долго удивлялся почему компилятор не послал этот говнокод лесом.
это "норма" . Про gcc уже обсуждалось. Думаю, это как раз тот случай.
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
овнокод

Не по теме:

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

0
COKPOWEHEU
2250 / 1358 / 308
Регистрация: 09.09.2017
Сообщений: 5,384
20.01.2020, 16:32 17

Не по теме:

Цитата Сообщение от Voland_ Посмотреть сообщение
Вы свои первые пробы давно открывали?
Увы, самых-самых первых проб (школьных, на Паскале или Делфи) не сохранилось, хотя было бы, конечно, интересно вспомнить все это.
Из того, что помню, первый "шедевр" был в Delphi, когда я не знал, что окно умеет принимать нажатия клавиш, поэтому разместил на форме несколько TButton'ов с соответствующими хоткеями, и отлавливал нажатия на них.
Второй "шедевр" был, когда разбирался со структурами (record) в Паскале. Об операторе with (обращение к полям структуры как к обычным переменным) знал, а вот об обращении через точку - нет. Результатом был блок with, где из структуры поля копировались в локальные переменные, потом какая-то работа с ними, потом еще один with для копирования обратно.


Цитата Сообщение от Voland_ Посмотреть сообщение
ну что Вы так расчувствовались?
Из педагогических соображений. Это достаточно грубая ошибка, чтобы акцентировать на ней внимание эмоциональным комментарием. Есть шанс, что реакция "ваш код оскорбляет мои эстетические чувства" окажется эффективнее сухого указания на ошибку.
0
COKPOWEHEU
2250 / 1358 / 308
Регистрация: 09.09.2017
Сообщений: 5,384
21.01.2020, 14:13 18
Цитата Сообщение от 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
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
#if (1==0)
//Example:
#include "StepMotor.h"
 
#define SM_A1 B,1
#define SM_A2 B,2
#define SM_B1 B,3
#define SM_B2 B,4
void Motor1
#include "StepMotor.h"
 
#define SM_A1 B,1
#define SM_A2 B,2
#define SM_B1 B,3
#define SM_B2 B,4
void Motor2
#include "StepMotor.h"
...
Motor1(1);
Motor2(-2);
#endif
//==============================================================================================================
#ifndef _STEPMOTOR_H_
#define _STEPMOTOR_H_
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "pinmacro.h"
PROGMEM const char mat[8] = {0b0001, 0b0101, 0b0100, 0b0110, 0b0010, 0b1010, 0b1000, 0b1001};
#define scbit(var, bit, port, pbit) do{ \
  if((char*)&port <= ((char*)(__SFR_OFFSET + 31))) { \
    asm( \
      "sbrc %[_var], %[_bit] \r\n" \
      "  sbi %[_port], %[_pbit] \r\n" \
      "sbrs %[_var], %[_bit] \r\n" \
      "  cbi %[_port], %[_pbit] \r\n" \
      : \
      : [_var]"r"(var), [_bit]"I"(bit), [_port]"I" (_SFR_IO_ADDR(port)), [_pbit]"I"(pbit) \
    ); \
  }else{ \
    if(var & (1<<bit))port |= (1<<pbit); else port &=~(1<<pbit); \
  } \
}while(0)
 
#else
 
#if !defined(SM_A1) || !defined(SM_A2) || !defined(SM_B1) || !defined(SM_B2)
#error define SM_A1, SM_A2, SM_B1, SM_B2
#endif
(int8_t dir){ \
  static uint8_t pos = 0; \
  DDR_1(SM_A1); DDR_1(SM_A2); DDR_1(SM_B1); DDR_1(SM_B2); \
  if((dir < -2) || (dir > 2)){pos = 0; return;} \
  pos = (pos + dir) & 7; \
  uint8_t mask = pgm_read_byte( &mat[pos] ); \
  scbit(mask, 3, PORTx(SM_A1), BITx(SM_A1)); \
  scbit(mask, 2, PORTx(SM_A2), BITx(SM_A2)); \
  scbit(mask, 1, PORTx(SM_B1), BITx(SM_B1)); \
  scbit(mask, 0, PORTx(SM_B2), BITx(SM_B2)); \
}
#undef SM_A1
#undef SM_A2
#undef SM_B1
#undef SM_B2
 
#endif
Настройка выводов и подключение заголовочника, конечно, вырвиглазные, зато быстро работает и занимает 78 байт флеша на каждый мотор плюс 8 байт на константы.
0
Voland_
1744 / 1076 / 108
Регистрация: 04.01.2010
Сообщений: 3,706
21.01.2020, 16:20 19
Цитата Сообщение от COKPOWEHEU Посмотреть сообщение
Не удержался и написал

Не по теме:

(выглядит ужасно :D)

0
COKPOWEHEU
2250 / 1358 / 308
Регистрация: 09.09.2017
Сообщений: 5,384
21.01.2020, 17:02 20
Цитата Сообщение от Voland_ Посмотреть сообщение
(выглядит ужасно )
Это еще не самое ужасное, что я писал
Увы, макроязык в Си штука на редкость дубовая, сильно красивее вряд ли возможно сделать. Зато никаких накладных расходов и выводы можно перекидывать как душе угодно.
Ну и на счет ужасности - эту штуку один раз написал и забыл, пускай себе лежит в коробочке с другими макро-монструозиями. Вот когда в ней обнаружится баг...
0
21.01.2020, 17:02
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
21.01.2020, 17:02

Пдскажите по комплектации Arduino ATMEGA 2560 R3
Заказал в Китае Arduino ATMEGA 2560 R3 и несколько нужных датчиков. Датчик температуры и...

Arduino, ATmega (Attiny) или STM?
Доброго времени суток. Пишу диплом, и вот настал момент, когда нужно выбрать микроконтроллер. Меня...

Странные зависания Arduino Nano (Atmega 328P)
Доброго времени суток. Собрал проект на базе Arduino Nano для умного освещения и...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2020, vBulletin Solutions, Inc.