Ардуино указатель на класс

Переменные, массивы, объекты, указатели, ссылки, . :

Данные:

Однобайтовые типы данных:

принимают любые, возвращают 0 или 1

если принят не 0, то вернётся 1

Целочисленные значения или символы

от -128 до 127

Беззнаковые целочисленные значения

от 0 до 255

Двухбайтовые типы данных:

от -32’768 до 32’767

В Arduino Due, тип int идентичен типу long

Беззнаковые целочисленные значения

от 0 до 65’535

В Arduino Due, тип unsigned int идентичен типу unsigned long

Четырёхбайтовые типы данных:

от -2’147’483’648 до 2’147’483’647

Беззнаковые целочисленные значения

от 0 до 4’294’967’295

Числа с плавающей точкой

от -2’147’483’648,0 до 2’147’483’647,0

Восьмибайтовые типы данных:

Числа с плавающей точкой удвоенной точности

от -9’223’372’036’854’775’808,0 до 9’223’372’036’854’775’807,0

Тип double действует как тип float, кроме Arduino Due

от -9’223’372’036’854’775’808 до 9’223’372’036’854’775’807

Беззнаковые целочисленные значения

от 0 до 18’446’744’073’709’551’615

Типы данных с определяемым размером

Нет принимаемых или возвращаемых значений

Массив A указанного размера, с элементами указанного типа

Массив А указанного типа, без прямого указания размера

Двумерный массив А указанного типа и размера

Двумерный массив А указанного типа, без прямого указания размера

Массив или строка, состоящая из указанного кол-ва символов

Массив или строка, без прямого указания количества символов

Преобразование числовых типов:

Приводит значение A к указанному типу.

Приводит результат A+B к указанному типу.

Сначала приводит A и B , к указанному типу, а потом вычисляет результат A+B .

Приводит указатель A к указанному типу указателя.

Спецификаторы памяти:
(указываются перед типом)

Объявление переменной в виде константы, её можно читать, но нельзя менять, т.к. она хранится в области flash памяти.

Объявление переменной, значение которой может быть изменено без явного использования оператора присвоения =. Используются для работы с прерываниями.

Объявление локальной переменной, значение которой не теряется, между вызовами функции. Если переменная объявлена глобально (вне функций), то её нельзя подключить в другом файле.

Объявление глобальной переменной, которая определена во внешнем файле.

Объявление локальной переменной, значение которой требуется хранить в регистрах процессора, а не в ОЗУ, для обеспечения ускоренного доступа.

Значения некоторых констант:

Ложь, используются вместо 0
Истина, используется вместо 1

Низкий уровень
Высокий уровень

Конфигурация вывода как вход
Конфигурация вывода как выход
Конфигурация вывода как вход с подтяжкой

Передача младшим битом вперёд
Передача старшим битом вперёд

Тактовая частота Arduino в Гц

Число Пи
Половина числа Пи
Два числа Пи
Число Эйлера

Префиксы:

Запись числа в 2ой системе ( 0b 10101)

Запись числа в 2ой системе ( B 10101)

Запись числа в 8ой системе ( 0 12345)

Запись числа в 16ой системе ( 0x 1234A)

Модификаторы:

Число типа long (12345 L )

Число типа long lond (12345 LL )

Число беззнакового типа (12345 U )

Комбинация модификаторов (12345 UL )

Показатель экспоненты (3 E -5 = 3•10-5)

Переменные, массивы, объекты, указатели, ссылки, . :

Это указание имени и типа переменной.
int A; // объявление переменной А

Это выделение памяти под переменную.
A =1; // определение ранее объявленной A

Действуют постоянно, в любом месте кода.

Создаются внутри функций, циклов и т.д.
удаляются из памяти при выходе из них.

Указывается в одинарных кавычках.
char A=’ Z ‘; // присвоение символа «Z»

Указывается в двойных кавычках.
String A=» Z «; // присвоение строки «XY»

Это переменная с указанием класса, вместо типа, через объект можно обращаться к методам класса

Ссылка, это альтернативное имя переменной, она возвращает значение переменной, на которую ссылается.

int A=5; // создана переменная A = 5
int & C=A; // создана ссылка C на переменную A
A++; C++; // в результате A=7 и C=7
// Ссылку нельзя переопределить: &C=Z;

Указатель, это переменная, значением которой является адрес.

int * Y1=&A; // указателю Y1, передан адрес переменной A
int ( * Y2)(int)=F; // указателю Y2, передан адрес функции F
B=Y1; // получаем адрес переменной A из указателя Y1
B= * Y1; // получаем значение A разыменовывая указатель
// Указатель можно переопределять: Y1=&Z;

Создание альтернативного имени для типа

typedef bool dbl; // создаём свой тип «dbl», как тип bool
dbl A=1; // создаём переменную A типа bool

Это переменная состоящая из нескольких однотипных элементов, доступ к значениям которых осуществляется по их индексу.

int A[5]; // объявлен массив A из 5 элементов типа int
int A[2]=<7,9>; // объявлен и определён массив A из 2 эл-тов
char A[ ]=»Hi»; // создана строка A, как массив символов

Это объединение нескольких переменных под одним именем.

struct < int A=5; float B=3; >C; // создана структура «С»
int D = C.A; // получаем значение переменной A структуры С
int Z = C.A; // присваиваем Z значение A структуры С

Значения некоторых констант:

Ложь, используются вместо 0
Истина, используется вместо 1

Источник

Arduino.ru

Указатель на неопределенный класс . ?

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

У тя область видимости класса XXX скорее всего, глобальная

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

Весь класс целиком. Рабочий.

Я уже перестал понимать к чему это. К #42 или к #44?

Но, в любом случае повторю второй раз (третий раз повторять не буду, просто буду игнорировать Ваши вопросы). Если Вы хотите задать вопрос, приводите скетч полностью, чтобы его можно было просто взять и запустить без дописывания и/или удаления чего-либо. Если будете приводить огрызки, ответов от меня больше не будет никаких.

Я прекрасно понимаю Вас, но данный скетч у Вас не получится просто так запустить. Он же привязан жестко к определенной аппаратной базе. Конечно при инициализации устройств идет проверка на их работоспособность, но если устройства нет, то и ЕГО часть скетча ес-но и вызываться не будет. Программа не зависнет, просто скажет, что работать не с чем — гудбай.

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

И как выложить скетч из 12-ти файлов ?

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

Схема контроллера, если интересно конечно:

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

Я прекрасно понимаю Вас, но данный скетч у Вас не получится просто так запустить.

Ни хрена Вы не понимаете. Это не Ваше дело, получится у меня его запустить или нет, скетч должет быть полным.

Вот, например, Вы задали вопрос

процедуры pinMode и digitalWrite не работают, т.е. ВООБЩЕ ничего не происходит. Пин так и остается INPUT.

И что я должен думать? Вы создавали экземпляр этого класса или не создавали? Если нет, то конструктор и не должен был работать. Если создавали, то как? Когда? Мне всё это из Вас клещами тянуть? Или самому придумывать как бы я сделал? Так у меня заработает — проблема-то у Вас, а не у меня.

И как выложить скетч из 12-ти файлов ?

Ну, в принципе так же, как и из одного, только смысла в этом нет никакого, абсолютно. В нём никто не станет разбираться. Если у Вас есть проблема. Вы должны специально подготовить маленький, минимально возможный скетч, который эту проблему демонстрирует и выложить его. Но его (маленький скетч) выложить полностью. Только так у Вас есть шанс получить вразумительный ответ.

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

Ну, в принципе так же, как и из одного, только смысла в этом нет никакого, абсолютно. В нём никто не станет разбираться. Если у Вас есть проблема. Вы должны специально подготовить маленький, минимально возможный скетч, который эту проблему демонстрирует и выложить его. Но его (маленький скетч) выложить полностью. Только так у Вас есть шанс получить вразумительный ответ.

Спасибо, я так далее и буду делать.

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

И что я должен думать? Вы создавали экземпляр этого класса или не создавали? Если нет, то конструктор и не должен был работать. Если создавали, то как? Когда? Мне всё это из Вас клещами тянуть? Или самому придумывать как бы я сделал? Так у меня заработает — проблема-то у Вас, а не у меня.

Конечно создавал. Иначе откуда бы я знал, что там на пине происходит. Осцилограф и показал, что НИЧЕГО не происходит.
Но я так понял, что это из-за того, что класс глобальный.

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

это из-за того, что класс глобальный.

вы видите хоть какой-то смысл в этой фразе? :)

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

У тя область видимости класса XXX скорее всего, глобальная

Мне как, верить всему, что здесь пишут, или выборочно ? Если выборочно, то по какому принципу ?

А ну да. Видимость класса глобальная, а не класс. Сорри.

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

А ну да. Видимость класса глобальная, а не класс. Сорри.

ну а вывод то из этого какой? :)

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

Мне как, верить всему, что здесь пишут, или выборочно ?

Верить или не верить можно в Бога. Всё остальное нужно осмысливать и, как минимум, понимать.

Вот-вот. Как создавали, когда создавали, сколько штук создавали — ответы на все эти вопросы — ХЗ. Ну и ответ на Ваш основной вопрос — тоже ХЗ!

Так что либо маленький, но полный скетч, либо разбирайтесь сами.

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

Так что либо маленький, но полный скетч, либо разбирайтесь сами.

так для того чтоб написать «маленький, но полный скетч», демонстрирующий проблему — надо пониматьв чем проблема состоит :)

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

так для того чтоб написать «маленький, но полный скетч», демонстрирующий проблему — надо пониматьв чем проблема состоит :)

Это тоже верно. Если у Вас пин порта должен аппаратно сбрасывает другой чип, а он его не сбрасывает, то вариантов несколько:

1. Неправильно написанная программа.
2. Нерабочий чип.
3. В даташите чипа неверно указаны временные задержки.
4. Временные задержки по каким-то причинам не соответствуют расчетным. Даже если в качестве задержки используется команда NOP процессора без цикла, то иногда время ее выполнения — один такт — не соответствует даташиту на процессор — я с таким сталкивался на Atmega88.

Если подумать, можно еще найти возможные причины. Так что действительно, определение проблемы это половина ее решения.
Красиво и правильно написанная программа не всегда будет правильно работать с «железом».

Источник

ОБОРУДОВАНИЕ
ТЕХНОЛОГИИ
РАЗРАБОТКИ

Блог технической поддержки моих разработок

Урок 15. Указатели в C для Ардуино. Преобразование разных типов данных в байты.

В уроке узнаем, что такое указатели, и как они позволяют оптимизировать код программы, научимся преобразовывать сложные типы данных (int, long, float…) в последовательность байтов.

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

Тема указателей в языке C++ важная и обширная. Сейчас я очень коротко расскажу об указателях. Подробно примеры их использования будут рассмотрены в следующих уроках по мере необходимости.

Указатели в C для Ардуино.

При разработке программы мы работаем с переменными разных типов, массивами, объектами, функциями…

  • Ко всем им мы обращаемся по именам, заданным при объявлении.
  • Все они хранятся в памяти, разбитой на ячейки — байты.
  • Все занимают разное число байтов в памяти.
  • Но у всех объектов есть адрес начала блока памяти, в котором они расположены.

Указатель это переменная, которая содержит адрес ячейки памяти. Указатель ссылается на начало блока памяти, в котором содержится переменная или функция.

  • Указатели могут быть использованы для передачи данных по ссылке. Это намного ускоряет обработку данных, т.к. нет необходимости в копировании данных, как это делается при передаче с использованием имени переменной.
  • Указатели используются для динамического распределения памяти, например, для массива неограниченного размера.
  • Указатели удобно использовать для преобразования различных типов данных в байтовые потоки.

Косвенная адресация.

Узнать адрес конкретной переменно в C++ можно операцией получения адреса &. Она выдает адрес переменной, перед которой написан символ &.

А для обращения к переменной по адресу (указателю) есть операция косвенной адресации *. Она выдает значение ячейки памяти по адресу, на который ссылается указатель.

cod = 15; // переменная cod = 15
ptr
Cod= &cod; // переменая ptrCod = адрес переменной cod
vl = * ptrCod; // переменная vl = значению по адресу из ptrCod, т.е. vl = cod = 15

Надо понимать, что &cod это число, конкретный адрес. А ptrCod это переменная типа указатель, т.е. переменная для адреса.

Виды указателей.

  • на основные типы;
  • на массивы;
  • на составные объекты (описываемые классами);
  • на функции;
  • на указатели;
  • на void.

Указатели на основные типы.

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

int *ptrdt; // указатель на переменную типа int
float *ptrx, *ptry, *ptrz; // указатели на переменные типа float

Чтобы отличать указатели от обычных переменных принято добавлять к имени символы ptr. Но это условие необязательно и многие его не придерживаются.

При объявлении указателей выделяется необходимое число байтов памяти, в зависимости от типа данных. Например, для dt (int) компилятор выделит 2 байта, а для x (float) будет зарезервировано 4 байта.

Указатели на массивы.

Очень эффективно использование указателей при работе с массивами. Имя массива уже представляет собой скрытую форму применения указателей.

Имя массива это указатель на его первый элемент.

int weights[10]; // массив weights
weights == &weights[0]; // имя это адрес первого элемента массива

Удобно использовать указатели на массивы, т.е. имена массивов, как аргументы функций.

int weights[10]; // массив weights
calculateAll(weights); // функция использует в качестве аргумента имя массива

Указатель на функцию.

Подобно имени массива, имя функции само по себе является указателем. Указатель на функцию хранит адрес памяти программы, по которому расположен ее код. По этому адресу передается управление при вызове функции. Такие указатели используются:

  • для вызова функции через обращение к переменной с ее адресом, а не через имя;
  • для передачи имени функции в качестве аргумента в другую функцию.

В роке 10 мы использовали функцию MsTimer2::set() . В качестве второго аргумента мы задали имя другой функции ( timerInterupt )- обработчика прерывания.

MsTimer2::set(2, timerInterupt); // задаем период прерывания и имя обработчика прерывания

Объявляется указатель на функцию так:

По сравнению с объявлением функции добавились скобки и *.

int (*ptrCalc)(int, float); // объявление указателя на функцию с аргументами int и float
ptrCalc = calculate; // присвоение указателю ptrCalc адреса функции calculate
Serial.printf(ptrCalc(x, 2.345) ); // вызов функции через указатель

int calculate(int, float) <
// тело функции calculate
>

Указатели на void.

Указатели на void используются для ссылки на объект, тип которого не определен. Например, для хранения различных типов данных в одних и тех же ячейках памяти.

Перед использованием указателя на void для хранения конкретного типа данных надо выполнить явное преобразование к этому типу.

Динамические переменные.

Когда мы объявляем переменную, компилятор выделяет для нее нужное количество ячеек памяти. Эти ячейки не могут использоваться для других целей, даже если в этой переменной уже нет необходимости. Поэтому такая переменная называется статической. Если статическая переменная требует значительного размера памяти (например, большой массив), то может возникнуть необходимость удалить ее и освободить память для новых переменных.

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

Выделение памяти для динамической переменной осуществляется с помощью оператора new :

тип_данных *имя_указателя = new тип_данных;

long *dt = new long;
Выделяется память, достаточная для типа long (4 байта). Адрес начала записывается в указатель dt.

int *weights = new int[50];
Выделяется память для 50 значений типа int (100 байтов). Адрес начала записывается в указатель weights, который может использоваться как имя массива.

Можно при объявлении выполнить инициализацию значения по адресу указателя:

long *dt = new long(102345); // значение памяти по адресу dt = 102345

Освободить память, выделенную оператором new, можно с помощью оператора delete.

// выделение памяти
long *dt = new long;
int *weights = new int[50];

// освобождение памяти
delete [] weights;
delete dt;

Заметьте, что для освобождения памяти массивов надо использовать оператор delete []. Если забыть про скобки, то будет удален только первый элемент массива, а остальные будут недоступны.

Указатели на составные объекты (описываемые классами).

Для создания динамических объектов также используется оператор new.

Button *buttonPlus = new Button; // выделение памяти под объект buttonPlus типа Button

При создании статического объекта, доступ к его свойствам и методам происходит операцией прямого обращения – ”.”.

buttonPlus.scanState();
buttonPlus.flagClick = false;

Для работы с динамическим объектом через указатель, для доступа к его свойствам и методам используется оператор косвенного обращения ”->”.

buttonPlus->scanState();
buttonPlus->flagClick = false;

Операции с указателями.

С указателями можно производить простые операции:

  • косвенное обращение (разадресация);
  • присваивание;
  • сложение с константой;
  • вычитание;
  • инкремент;
  • декремент;
  • сравнение;
  • явное приведение типов.

Операция разадресации позволяет получить доступ к величине, адрес которой хранится в указателе. Конструкцию *имя_указателя можно считать именем переменной. С ней допустимы все действия, которые разрешены для типа, заданного при объявлении указателя.

Арифметические операции с указателями автоматически учитывают размер типа переменной. Т.е. для типа данных char инкремент указателя увеличит адрес памяти на 1 байт, а для типа long прибавление 1 к указателю прибавит к реальному адресу памяти 4 байта. Арифметические операции применяют в основном при работе с данными, размещенными в памяти последовательно, например, с массивами.

Преобразование разных типов данных в байты.

В прошлом уроке мы сохраняли данные в EEPROM платы Ардуино. Сохраняли мы данные типа byte. EEPROM хранит данные в байтах и наши данные в байтах. Все просто. Но, допустим, нам надо сохранить в EEPROM переменную типа int . Она занимает в памяти 2 байта и для записи в энергонезависимую память ее надо преобразовать в отдельные байты. Можно сделать так:

int dt = 0x1234; // переменная типа int, которую надо преобразовать в байты
byte byteEeprom1 = (byte)(dt & 0xff); // младший байт = 0x34
byte byteEeprom2 = (byte)(dt >> 8); // старший байт = 0x12

Мы получили два байта, но пришлось выполнить несколько операций, в том числе сдвиг на 8 разрядов. Для обработки переменной типа long сдвигов и других операций будет значительно больше. А вот что делать с переменной типа float я вообще не представляю. Преобразовать ее в число с фиксированной запятой? Наверное, что-то можно придумать, но это будет сложное решение и потребует значительных ресурсов от микроконтроллера. А ведь все переменные хранятся в памяти, разбитой на байты. Надо и взять их из памяти в виде байтов. Сделать это можно с помощью указателя.

Преобразуем переменную типа int в байты таким способом.

int dt = 0x1234; // переменная типа int, которую надо преобразовать в байты
byte byteEeprom1 = * ((byte *)(& dt)); // младший байт = 0x34
byte byteEeprom2 = * ((byte *)(& dt) + 1); // старший байт = 0x12

Для чтения байта мы:

  • получили адрес переменной: & dt;
  • явно преобразовали адрес к указателю на тип byte: (byte *) ;
  • применили операцию косвенной адресации: * ;
  • для чтения второго байта прибавили 1 к указателю.

В этом примере мы не объявляли указатель вообще. В строках кода для чтения байтов операции получения и преобразования адреса повторились. Для преобразования данных с большими размерами лучше объявить указатель. Это значительно ускорит работу программы.

Пример преобразования переменной типа float в байты:

float dt = 2.58901; // переменная типа float, которую надо преобразовать в байты
byte* ptrdt; // указатель на тип byte
ptrdt = (byte*)(& dt); // получаем адрес переменной dt

byte byteEeprom1 = * ptrdt; // считываем байты
byte byteEeprom2 = * (ptrdt+1);
byte byteEeprom3 = * (ptrdt+2);
byte byteEeprom4 = * (ptrdt+3);

Осталось записать байты в EEPROM. Конечно, это можно сделать без промежуточных переменных.

// записываем байты в EEPROM
EEPROM.write(0, * ptrdt);
EEPROM.write(1, *(ptrdt+1));
EEPROM.write(2, *(ptrdt+2));
EEPROM.write(3, *(ptrdt+3));

Для чтения данных типа float из EEPROM — считываем байты и записываем их последовательно в область памяти по указателю ptrdt:

// чтение байтов из EEPROM и запись в область памяти для dt
* ptrdt = EEPROM.read(0);
* (ptrdt+1) = EEPROM.read(1);
* (ptrdt+2) = EEPROM.read(2);
* (ptrdt+3) = EEPROM.read(3);

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

Указатели – очень важная тема для практического программирования микроконтроллеров. В будущих уроках, по мере необходимости, мы будем рассматривать способы их использования на конкретных примерах. Тогда, возможно, Вам придется вернуться к этому уроку.

В следующем уроке поговорим о надежности программ для Ардуино, узнаем, как использовать сторожевой таймер.

Источник