ARM и специфичный для компиляторов код

Любой разработчик компиляторов расширяет язык программирования и расширяет по своему.

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

Ниже приведен пример кода для некоторых ARM-компиляторов.


#if defined (__CC_ARM)
    /* Код для компилятора Keil */
#elif defined (__ICCARM__)
    /* Код для компилятора IAR */
#elif defined ( __GNUC__ )
    /* Код для компилятора GNU */
#elif defined (__TASKING__)
    /* Код для компилятора TASKING */
#else
    /* Неизвестный компилятор */
    #error Unknown compiler
#endif

Реклама

Начало работы с STM32 в Keil MDK-ARM

Статья посвящается Пановой Ксении.

Все картинки в этой статье кликабельны.

STM32 — это семейство 32-разрядных микроконтроллеров фирмы STMicroelectronics.

Микроконтроллеры содержат микропроцессорное ядро ARM, точнее ARM Cortex-M. Это ядро присуще не только микроконтроллерам STM32, оно существует само по себе, и на его основе выпускается множество микроконтроллеров от разных производителей.

Keil MDK-ARM (произносится «Кеил эм-ди-кей арм») — это среда разработки для микроконтроллеров с ядром ARM Cortex-M.

Читать далее Начало работы с STM32 в Keil MDK-ARM

Такой код по разному воспринимается разными компиляторами:

const int data_size = 7;
int data[data_size] = {1,2,3,4,5,6,7};

Если использовать компилятор из Keil MDK-ARM, то код компилируется и работает нормально. Но компилятор (gcc) из Sourcery Сodebench выдает ошибку:

variable-sized object may not be initialized

При этом, без ошибок компилируется код:

const int data_size = 7;
int data[data_size];

MDK-ARM: замена десятичного разделителя

Чтобы локализовать представление чисел при программировании в среде MDK-ARM требуется выполнить несколько простых шагов:

  1. Скачать ассемблерный файл и добавить в свой проект.
  2. В настройках проекта на вкладке Asm в поле Include Paths указать каталог, в котором расположен файл rt_locale.s. По умолчанию этот файл расположен в «C:\Keil\ARM\ARMCC\include».

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

После этого функции (например printf) преобразующие число в строку и наоборот будут воспринимать запятую в качестве разделителя дробной и целой части.

Подробнее о реализации ассемблерного файла можно почитать в официальной документации на MDK-ARM. Стоит учесть, что в коде, приведенном в документации, есть недочет: отсутствует строчка экспортирующая функцию _get_lc_CATEGORY, в представленном здесь ассемблерном файле эта строчка: «EXPORT _get_lc_numeric». Без неё локализация не заработает.

Привожу код из ассемблерного файла.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Определение русского десятичного разделителя.
;
; Файл предназначен для программирования в среде Keil MDK-ARM.
;
; В настройках проекта на вкладке Asm в поле Include Paths
; требуется указать каталог, в котором расположен файл rt_locale.s.
; По умолчанию этот файл расположен в "C:\Keil\ARM\ARMCC\include".
;
; В программе не требуется вызывать функцию setlocale().

    GET rt_locale.s ; Подключить файл с макросами

    AREA locales, DATA, READONLY
    LC_NUMERIC_begin russian_numeric_locale, "russian"
    LC_NUMERIC_point ","     ; Десятичный разделитель
    LC_NUMERIC_thousands "." ; Разделитель групп цифр
    LC_NUMERIC_grouping "\3" ; Количество цифр в группе
    LC_NUMERIC_end
    AREA locale_func, CODE, READONLY
    EXPORT _get_lc_numeric
_get_lc_numeric FUNCTION
    LDR r0, =russian_numeric_locale_start
    BX lr
    ENDFUNC

    END ; Конец ассемблерного файла

Компилятор Keil Cx51: типы данных и порядок байт

Компилятор Cx51 входит в состав средств разработки Keil С51.

Компилятор поддерживает следующие типы данных:

Тип данных Количество
бит
Количество
байт
Диапазон значений
bit 1 0, 1
signed char 8 1 -128…+127
unsigned char 8 1 0…255
enum 8 или 16 1 или 2 -128…+127 или -32768…+32767
signed short 16 2 -32768…+32767
unsigned short 16 2 0…65535
signed int 16 2 -32768…+32767
unsigned int 16 2 0…65535
signed long 32 4 -2147483648…2147483647
unsigned long 32 4 0…4294967295
float 32 4 ±1.175494E-38…±3.402823E+38
data *, idata *, pdata * 8 1 0x00...0xFF
code *, xdata * 16 2 0x0000...0xFFFF
generic pointer 24 3 Memory type (1 байт); Offset (2 байта) 0...0xFFFF

Многобайтовые переменные располагаются в памяти определенным образом, который называется big-endian (от старшего к младшему). То есть самый старший байт хранится в памяти раньше остальных, самый младший сохраняется самым последним. Например число 0x1234 типа int храниться в памяти следующим образом:

Адрес +0 +1
Содержимое 0x12 0x34