Как программа работает с аппаратным устройством - PullRequest
0 голосов
/ 27 сентября 2018

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

Все программные коды имеют следующее.

  • Переменные типа int, float, short и т. Д.
  • Функции и вызов функции
  • Выражения, как если бы это было так *
  • вычисления
  • Циклы, подобные циклу и т. Д.

Я хочу, чтобы при загрузке программного обеспечения на оборудование данные передавались в память программирования (ПЗУ).Когда мы запускаем программу, все вышеперечисленные вещи попадают в ОЗУ или это специфическая область, например, только данные функций?

Когда мы рассматриваем 8-битную шину, как использовать более 8-битные данные, такие как 10-битный символ, потому что шина маленькая?

Что такое стек и как с ним программировать?

Почему важна функция void main?Как аппаратно идентифицировать это?

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

Ответы [ 2 ]

0 голосов
/ 03 октября 2018

У вас там много вопросов.Для начала давайте предположим простую ситуацию, такую ​​как Arduino, которая представляет собой комбинацию программного и аппаратного обеспечения.Программная часть начинается с написания вами простого кода на C ++, например:

byte ledPin = 13;
void setup(){
pinMode (ledPin, OUTPUT);
}
void loop(){
digitalWrite (ledPin, HIGH);
digitalWrite (ledPin, LOW);
}

Затем вы должны скомпилировать код.Arduino IDE (интегрированная среда разработки) выполняет некоторые вещи (в фоновом режиме, например, добавляя main (), который будет вызывать функцию setup () один раз, и функцию loop () повторно), чтобы превратить этот C ++ в код ассемблера, которыйможет выглядеть так (не фактический вывод из приведенного выше):

; Define pull-ups and set outputs high
; Define directions for port pins
ldi r16,(1<<PB7)|(1<<PB6)|(1<<PB1)|(1<<PB0)
ldi r17,(1<<DDB3)|(1<<DDB2)|(1<<DDB1)|(1<<DDB0)
out PORTB,r16
out DDRB,r17
; Insert nop for synchronization
nop
; Read port pins
in r16,PINB

Ассемблер, который берет этот код и преобразует его в шестнадцатеричный формат информации, которую программист может поместить в ПЗУ на микроконтроллере Atmega328P.В основном, строки данных в файле, каждая строка содержит начальный адрес строки, возможно, 16 байтов данных, и контрольную сумму, чтобы убедиться, что данные не были повреждены во время их обработки:

000100005673495a6b4f5e205673495a6b4f5e24465

Это не реальные данные.0001000 может быть начальным адресом в ПЗУ, следующие 32 символа - это 16 байтов данных, которые должны быть запрограммированы, а последние 4 могут быть контрольной суммой, которая создается путем манипулирования данными каким-либо образом.Программист получает данные, выполняет те же манипуляции и, если контрольная сумма верна, записывает их в память.

Шестнадцатеричный код может быть помещен в ПЗУ несколькими способами - программист может получить контроль над чипом.и поместите код в память напрямую, и после сброса чип просто запустит код; или загрузчик может быть запущен из области ПЗУ на чипе после сброса, и он будет общаться с ПК по последовательным линиям(Rx, Tx), чтобы получить данные, а затем записать их в другую область ПЗУ.Если код загрузки не обнаружил ПК, пытающийся с ним поговорить, он перешел бы к адресу ПЗУ, с которого код запускался и запускался оттуда.

8-битные микроконтроллеры могут иметь 16-битные регистры, которые он может использовать длятакие вещи, как захват результатов преобразования АЦП или сохранение результатов в виде двух 8-битных байтов с данными старшего и младшего разрядов.

Стек может быть выделенным аппаратным регистром или областьюSRAM, который используется для хранения таких вещей, как результаты математических операций.Код заботится о том, чтобы поместить вещи в стек и прочитать их обратно, обычно вы не будете заниматься программированием.С '328P, имеется 2048 байтов SRAM, поэтому вам нужно всего лишь убедиться, что у вас не слишком много объявленных переменных в коде (например, байт ledPin = 13;), который использовал все это и не оставлял местадля кода.Зачастую, например, в 328P это вызвано попыткой доступа к массиву за его пределами, поэтому либо возвращаются бессмысленные результаты, либо происходит сбой программы, когда запись после конца массива перезаписывает что-то другое.Гибкость C ++ великолепна, но она также позволит вам столкнуться с проблемами, если не позаботиться о ней.

0 голосов
/ 03 октября 2018

Как говорит @nos, требуются большие книги, чтобы объяснить это.

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

Когда программа переводится в сборку, она загружается в память.В зависимости от архитектуры, она идет в общей памяти (фон Неймана) или памяти программ (в отличие от памяти данных с архитектурой Гарварда).

Когда речь идет о стеке, у вас также есть указатели.Указатель указывает на (да, указатель, который указывает, круто да) «уровень» стека.Например, у вас есть «текущий» указатель, который указывает на текущую инструкцию.Как только текущая инструкция завершена, указатель увеличивается и, следовательно, указывает на следующий уровень.Другой указатель используется при вызове подфункции и указывает на уровень, на котором вы остановили родительскую функцию.Как только подфункция выполнена, вы возвращаетесь туда, где остановились.

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

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

Итак ... когда вы программируете некоторый код, скажем, на C:

int main ()
{
    int a = 0;
    printf("a = %d", a);
    return 0;
}

Содержимое main переведено на ассемблер и является вашей "обычной" программой.Во-первых, он помещает 0 в ячейку регистра.Затем он помещает его в режим ожидания, чтобы выполнить printf (который использует значения в ячейке, в которой мы сохранили 0), и сохраняет там, где он остановился в указателе.Как только он закончится, текущий указатель возвращает значение нашего сохраненного указателя и продолжает.

О том, что идет в оперативной памяти: у вас есть разные уровни памяти.Диск, жесткий или твердотельный, медленный, но большой и дешевый.Таран, быстрее, но дороже и меньше.Кеш, встроенный в процессор, очень быстрый, меньше и дороже.Регистры, также встроенные, даже быстрее, но меньше.Когда процессор использует переменную, он входит в регистры.Но современные процессоры «угадывают» (или предварительную выборку), какая переменная может понадобиться в ближайшем будущем (например, если вы прочитаете две первые ячейки таблицы, она, вероятно, загрузит третью перед тем, как вы спросите), и поместите ее в кеш.В противном случае, это в оперативной памяти.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...