Урок короткий, но очень важный. Разберемся в базовых типах данных STM32. Понимание этого вопроса абсолютно необходимо для разработки программ.
Предыдущий урок Список уроков Следующий урок
Все действия в программе мы производим над переменными. Поэтому необходимо точно знать форматы, размеры переменных, диапазоны чисел, которые они способны содержать. Переменные должны быть объявлены с указанием типа данных до использования в программе. Тип данных и задает параметры переменных.
Все это мы знаем из уроков Ардуино. Но базовые типы данных системы Ардуино и компилятора C для STM32 отличаются. Формальное применение знаний, полученных из курса Ардуино, может привести к фатальным последствиям для программ STM32. Давайте переучиваться.
Некоторые базовые типы данных стандартов языка программирования Си зависят от используемого микроконтроллера. В значительной мере от разрядности данных, с которыми он оперирует. Например, для 8ми разрядного микроконтроллера Ардуино тип int это 16 разрядов. Тот же тип для STM32 составляет 32 разряда.
Я не буду рассказывать о принципах, по которым стандарт языка Си определяет форматы базовых типов данных. Я буду освещать этот вопрос применительно к нашему микроконтроллеру STM32, нашей среде программирования.
Выделим из стандарта C99 языка программирования Си следующие базовые типы данных.
Тип данных | Пояснение | Разрядность бит (байт) |
Диапазон чисел |
char int8_t |
Целочисленный знаковый тип. | 8 (1) | - 128 … 127 |
unsigned char uint8_t |
Целочисленный беззнаковый тип. | 8 (1) | 0 … 255 |
short int16_t |
Целочисленный знаковый тип. | 16 (2) | - 32768 … 32768 |
unsigned short uint16_t |
Целочисленный беззнаковый тип. | 16 (2) | 0 … 65535 |
int int32_t |
Целочисленный знаковый тип. | 32 (4) | - 2147483648 … 2147483647 |
unsigned int uint32_t |
Целочисленный беззнаковый тип. |
32 (4) | 0 … 4294967295 |
long int32_t |
Целочисленный знаковый тип. | 32 (4) | - 2147483648 … 2147483647 |
unsigned long uint32_t |
Целочисленный беззнаковый тип. | 32 (4) | 0 … 4294967295 |
long long int64_t |
Целочисленный знаковый тип. | 64 (8) | - 9223372036854775808 … 9223372036854775807 |
unsigned long long uint64_t |
Целочисленный беззнаковый тип. | 64 (8) | 0 … 18446744073709551615 |
float | Формат с плавающей запятой одинарной точности. | 32 (4) | ± (3,4 * 10 -38 … 3,4 * 10 +38) |
double | Формат с плавающей запятой двойной точности. | 64 (8) | ± (1,7 * 10 -308 … 1,7 * 10 +308) |
long double | Формат с плавающей запятой повышенной точности. | 64 (8) | ± (1,7 * 10 -308 … 1,7 * 10 +308) |
_Bool | Логический тип. | 8 (1) | 0 (ложь) или 1 (истина) |
Я подкорректировал параметры в соответствии с нашей средой программирования, поверил все эти типы данных.
Есть в языке Си функция, которая возвращает количество байтов необходимое для указанного в качестве аргумента типа.
int n = sizeof(long); // считать размер типа long
Я написал программу, которая определяет размеры разных типов данных и выводит их через последовательный порт. Это основной блок программы.
sprintf((char *)str,"Тип char - %u байт\r\n", sizeof(char));
outputRes();
sprintf((char *)str,"Тип short - %u байт\r\n", sizeof(short));
outputRes();
sprintf((char *)str,"Тип int - %u байт\r\n", sizeof(int));
outputRes();
sprintf((char *)str,"Тип long - %u байт\r\n", sizeof(long));
outputRes();
sprintf((char *)str,"Тип long long - %u байт\r\n", sizeof(longlong));
outputRes();
sprintf((char *)str,"Тип float - %u байт\r\n", sizeof(float));
outputRes();
sprintf((char *)str,"Тип double - %u байт\r\n", sizeof(double));
outputRes();
sprintf((char *)str,"Тип long double - %u байт\r\n", sizeof(longdouble));
outputRes();
sprintf((char *)str,"Тип _Bool - %u байт\r\n\r\n", sizeof(_Bool));
outputRes();
Вот, что показал монитор последовательного порта CoolTerm.
Кто захочет проверить сам, полностью проект программы можно загрузить по ссылке:
Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!
В программах для STM32 можно пользоваться всеми типами данных из таблицы. Но я предлагаю ввести ограничения.
В таблице есть целочисленные типы данных с явно заданной разрядностью.
Их имена образуются из символов:
- int –целое знаковое;
- uint –целое беззнаковое (к int добавили u);
- число разрядов;
- _t – тип.
Формат таких типов данных не зависит от разрядности микроконтроллера.
- int8_t – целое знаковое 8 разрядов;
- uint8_t – целое беззнаковое 8 разрядов;
- int16_t – целое знаковое 16 разрядов;
- uint16_t – целое беззнаковое 16 разрядов;
- int32_t – целое знаковое 32 разрядов;
- uint32_t – целое беззнаковое 32 разрядов;
- int64_t – целое знаковое 64 разрядов;
- uint64_t – целое беззнаковое 64 разрядов;
Хороший стиль использовать при разработке программ для STM32 именно такие описания для целочисленных переменных. Давайте так и будем поступать в дальнейшем.
Я бы еще допустил использование типа char. Он явно указывает на назначение переменной – хранение кода символа и, в какой-то степени, улучшает читаемость программы.
Типы с плавающей запятой будем использовать из таблицы.
Думаю, вы заметили, что отсутствуют привычные логические типы данных bool и boolean.В языке Си современной редакции они заменены на тип _Bool.
Но дело не в формальном изменении имени. Переменные для него не могут принимать значения true и false. Теперь это 0 – ложно и 1 – истинно. Часто в качестве логического типа используют uint8_t.
Можно вернуть привычный логический тип boolean и значения для него, если подключить заголовочный файл stdbool.h. Переназначение имен будет происходить через макросы.
Я предлагаю отказаться от такого способа и оставить принцип описания логических переменных, заданный разработчиками стандарта языка Си.
Но, в проектах C++ тип _Bool не поддерживается. Давайте использовать для логических переменных тип uint8_t.
Конечно, все это не догма, носит рекомендательный характер. Я выражаю свое мнение. Каждый может использовать типы данных на свое усмотрение. Но в дальнейших уроках я собираюсь придерживаться изложенных выше принципов.
Еще два слова по поводу констант. Они тоже могут иметь знак. К беззнаковой константе добавляется буквы U или u.
int x = 234U; // беззнаковое число
int x = 0x001Eu; // беззнаковое число
В противном случае (без буквы U) константа считается знаковой.
int x = 234; // знаковое число
int x = 0x001E; // знаковое число
В случае использования знаковой константы старший разряд считается знаком, и отрицательные числа воспринимаются в дополнительном коде.
В следующем уроке будем займемся обработкой сигналов кнопок.
uint1_t – целое беззнаковое 1 разряд; бит мне захотелось, Кейл не вкусил моего порыва…
почему не писать так:
int32_t x = 234; // знаковое число
uint32_ x = 234; // беззнаковое число
вместо:
int x = 234; // знаковое число
int x = 234u; // беззнаковое число
и сколько бит выделит компилятор для этого «int» ?
Здравствуйте!
В уроке написано — 4 байта.
Странно, у меня тип _Bool вызывает ошибку. А где они все определены кстати и как?
Здравствуйте!, который определяет макросы true, false и bool. Тогда можно работать с bool, как обычно.
0
Попробуйте включить