Учимся говорить с электроникой на одном языке
Не лишь люди друг с другом общаются на языке, но и люди с компьютерами (а микроконтроллеры можно тоже назвать микрокомпьютером) общаются на языке, называемом языком программирования. Как и у людей существует множество языков, русский, английский, немецкий, китайский и т.п., также существуют и различные языки программирования, такие как С, Pascal, Basic, Fortran, Java, PHP и прочие.
Каждый язык программирования имеет свои особенности и в связи с этим для использования в различных применениях предпочтение отдается разным языкам. Так, например, скриптовый язык программирования PHP имеющий богатые возможности по работе со строковыми данными, и функциями связанными с работой с текстом, совершено не подходит для написания программ на МК, поскольку, как и любой другой скриптовый язык, он требует для своей работы специального установленного ПО, исполняющего написанный на этом языке код. Таким образом для нас подходят лишь компилируемые языки, такие как например С, Pascal, Basic и т.п.. Наиболее простым в освоении считается Basic, но в связи с его упрощением он создает далеко не идеальный программный код, в связи с чем, и без того не особо богатые ресурсы микроконтроллера расходуются слишком расточительно. Pascal, среди названных 3-х языков, является средним языком. Самым лучшим по оптимальности получаемого кода считается язык программирования С. Но даже он не всегда обеспечивает нужного результата, поэтому также порой используется Assembler, данный язык представляет ни что иное как непосредственная работа с микроконтроллером на низком уровне. С точки зрения электроники, написание программ на нем можно сравнить с разработкой и сборкой усилителя на транзисторах, а написание программ на языках высокого уровня со сборкой усилителя на микросхемах. Написание программ на ассемблере является более трудоемким процессом, но при должном умении он дает возможность получить более лучшие результаты по быстродействию и занимаемым программой ресурсам. Также как и усилитель, собранный на транзисторах, может дать лучшие параметры звучания, но лишь в том случае если этот усилитель собирается по хорошо «вылизанной» схеме с правильной разводкой платы и при соблюдении всех необходимый требований. Именно по этим причинам, наиболее часто применяемым языком программирования, для написания программ для МК является язык программирования Си, с которым я и предлагаю начать наше знакомство. Те, кто знаком с данным языком, могут пропустить данную часть и приступить к изучению следующей части, поскольку в данном материале отображены лишь базовые знания, необходимые для написания программ, описанные максимально доступным для начинающих языком.
Комментарии
Поскольку наиболее понятное изучение нового материала происходит с использованием примеров с комментариями, первым делом необходимо запомнить, как же на языке Си создаются комментарии в исходном тексте программы.
// Комментарии в программе это заметки, которые игнорируются языком Си
//и не считаются частью программного кода.
// Они записываются в одной и более строках, и заключаются между символами /* и */
// или в одной строке, начинающейся с последовательности //
// Так может быть записан лишь однострочный комментарий,
//этот комментарий правильный
А это уже не является комментарием
/* Так записываются многострочные комментарии,
он заканчивается там где встречается комбинация символов */
/* многострочные комментарии могут вставляться в часть кода*/
Это какой-то код /* это комментарий */ а это снова код
Структура программ
Любая программа, как и предложение в нашем языке, состоит из различных частей «речи», таких как константы, операторы и переменные. К примеру, в предложении «Если я прийду домой в 18 часов, то успею посмотреть фильм, иначе он закончится» имеются оператор условия «Если…, то успею…, иначе…», константы – «я» и переменная «18 часов». Примерно вот так эта запись будет выглядеть, если её записать на языке Си
// Здесь оператор условия «if», в скобках указывается само условие,
//по выполнению, которого будет выполнено действие следующее далее, если действий несколько, то они объединяются фигурными скобками.
if (я прийду домой в 18часов) успею посмотреть фильм;
// Если условие не выполнилось, то программа выполнит условие идущее после «else»,
//else не является обязательным и может отсутствовать
else фильм закончится;
Условие состоит из 3-х частей, это константа, знак сравнения, и переменная. В данном случае «я» является константой, «прийду домой в» знаком сравнения, и «18 часов» переменная. Более подробнее об использовании условных операторов будет рассказано далее.
Переменные
Все константы, операторы и пр. располагаются во flash памяти (ПЗУ, ROM, память программ), содержимое этой памяти не может быть изменено программой. Для хранения данных, которые изменяются во время выполнения программы, используется оперативная память (ОЗУ, RAM, память данных). Все переменные располагаются в RAM памяти, для создания переменной используются ключевые слова:
char – создает переменную размером 1 байт (8 бит), данная переменная может содержать 28=256 значений;
int – размер создаваемой переменой зависит от используемой архитектуры, так например для МК AVR Atmega8 и ему подобных размер переменной будет 16 бит, для STM32 он составит 32 бита;
short — создает переменную размером 16 бит, данная переменная может содержать 65536 значений и занимает в памяти 2 байта;
long – 32 битная переменная, занимает в памяти 4 байта и содержит 232 значений;
float – переменная используемая для чисел с плавающей точкой (дробных чисел), занимает так же 4 байта, но на действия с данным типом переменных необходимо затратить большее число тактов процессора, т.е. больше времени.
Для числовых переменных существуют модификаторы, обозначающие знак переменной:
unsigned – указывает на то, что создаваемая переменная имеет беззнаковый тип, т.е. unsigned char создаст переменную с диапазоном от 0 до 255;
signed – указывает на то, что создаваемая переменная имеет знаковый тип, т.е. signed char создаст переменную с диапазоном от -128 до +127
Для хранения строковых данных, а также для хранения большого количества однотипных данных удобно использовать массивы данных. Ко всему массиву целиком можно обращаться по одному имени. Кроме того, можно выбирать любой элемент массива по индексу элемента. Для этого необходимо задать индекс, который указывает на его относительную позицию. Число элементов массива назначается при его определении и в дальнейшем не изменяется. Если массив объявлен, то к любому его элементу можно обратиться следующим образом: указать имя массива и индекс элемента в квадратных скобках.
unsigned char array_name[10]
Любые переменные, а также функции и константы должны выбираться с учетом следующих правил:
1. Они должны начинаться с буквы латинского алфавита (а,…,z, А,…,Z) или с символа подчеркивания «_».
2. В них могут использоваться буквы латинского алфавита, символ подчеркивания и цифры (0,…,9). Использование других символов запрещено.
3. В языке Си буквы нижнего регистра (а,…,z), применяемые в идентификаторах, отличаются от букв верхнего регистра (А,…,Z). Это означает, что следующие идентификаторы считаются разными: name, NaMe, NAME и т.д.
4. Они могут иметь длину в соответствии со стандартом ANSIC не превышающую 32 символов.
5. Идентификаторы для новых объектов не должны совпадать с ключевыми словами языка и именами стандартных функций из библиотеки.
По окончании объявления переменной необходимо написать точку с запятой «;».
Если перед значением числа добавлено выражение «0х», это означает что данное число записано в шестнадцатеричном виде, например 0х12.
Попробуем создать несколько переменных.
/* К примеру, некая переменная может изменяться в диапазоне от 0 до 100,
она не превышает размерности 1 байта, и имеет лишь положительные значения,
значит, для нее подходит тип unsigned char */
unsigned char imja_peremennaya1;
/*Если мы захотим создать переменную, изменяющуюся в диапазоне, например, от 50 до 1000 нам необходимо объявить ее как unsigned short, не смотря на то, что она также входит и в диапазон unsigned long. Её также возможно объявить типом unsigned long, но это не рационально, поскольку при этом будет зарезервирована бОльшая область памяти, чем требуется для данной переменной*/
unsigned short imja_peremennaya2;
/* Для объявления переменной изменяющейся в диапазоне от -30 до +150 подходит тип signed int */
signed int imja_peremennaya3;
/* Массивы определяются так же, как и переменные, но дополнительно в квадратных скобках указывается размер массива */
/*Данный массив представляет набор из 100 переменных типа unsigned int имеющих имя imja_massiva. При обращении к массиву необходимо в квадратных скобках указать номер элемента, к которому происходит обращение. */
unsigned int imja_massiva[100];
/* Инициализировать строку можно следующим образом: */
//В квадратных скобках указывается резервируемое в ОЗУ место
unsigned char stroka1[7] = «Строка»;
//Ещё один вариант объявления массива для строк
unsigned char stroka2[ ] = {‘С’, ‘т’, ‘р’, ‘о’, ‘к’, ‘а’, ‘