Рис.1 Структура программы на языке Си.
Внутренняя структура программы
Исполняемая программа на Си состоит из 4 частей: область команд, область статических данных, область динамических данных, область стека. см. Рис.2.
1. Область команд содержит машинные команды; инструкции, которые должен выполнить микропроцессор.
2. Область статических данных для хранения переменных, с которыми работает программа;
3. Область динамических данных для размещения дополнительных данных, которые появляются в процессе работы программы (например, временных переменных).
4. Стек используется для временного хранения данных и адресов возврата из функций.
тело функции /*тело функции*/
printf("Hello World!");
1-я строка – директива, подключающая заголовочный файл стандартного ввода-вывода. Операторов в Си мало, но есть библиотека функций. Чтобы их использовать надо их подключить, что и делает директива – 1-я строка программы. Символ # указывает, что строка должна быть обработана препроцессором языка Си.
2-я строка – имя главной функции main () , эта функция не возвращает никаких параметров (об этом буду говорить немного позже). Программа Си всегда имеет функцию main(). С нее начинается выполнение программы.
3-я строка – начало тела функции. {} определяют тело функции (в Паскале - это begin и end)
4-я строка – комментарий, он не компилируется, а только поясняет что делается.
5-я строка – библиотечная функция – печатать на экране, выражение в скобках на этой строке – параметр функции, он всегда берётся в кавычки.
; - это признак оператора Си, это часть оператора, а не разделитель операторов, как в Паскале.
Советы, как сделать программу читаемой:
1) Выбирать осмысленные имена
2) Использовать комментарии
3) Использовать пустые строки для того, чтобы отделить одну часть функции от другой
4) Помещать каждый оператор в другой строке.
БАЗОВЫЕ ЭЛЕМЕНТЫ ЯЗЫКА СИ
Рассмотрим обязательные элементы, с помощью которых должна оформляться программа на Си:
1. Комментарии – используются для документирования программы. Любая программа должна содержать комментарии: какой алгоритм применяется, что делает программа…
Ø 1 способ : /* Текст */ - в любом месте программы.
Как только компилятор встречает /**/, он их пропускает. Компилятор игнорирует /* */, так как он не в состоянии интерпретировать язык, отличающийся от языка Си. То есть, если вы хотите исключить из компиляции какую-то строку, то заключите её в /**/.
Ø 2 способ : если комментарий большой, то используем такой тип
/* Строка 1 - для комментария любой длины
строка 3*/
Ø 3 способ : // - текст до конца строки.
2. Идентификатор - это имя, которое присваивается какому-либо объекту (переменной). Используются строчные и прописные буквы, цифры и знак подчёркивания. Строчные и прописные буквы различаются. (В Бейсике не различаются). Если назвать переменную name, Name или NAME, то это будут разные переменные.
Начинаются идентификаторы с буквы или знака подчеркивания. Например, _name. Но не рекомендуется начинать с _, так как этот знак используется для глобальных имен сомого языка Си.
В современном программировании часто используется для создания идентификаторов Венгерская нотация, где используются определенные символы, характеризующие идентификатор, например:
b – байт; ch – однобайтовый символ;
w – слово; f – флаг;
l – длинное слово; fn – функция;
u – беззнаковое; p – указатель;
с – счетчик; d – разность двух пре-х
cz – строка; и т.д.
3. Служебные слова – это слова, с которыми в языке жестко сопоставлены определённые смысловые значения и которые не могут быть использованы для других целей. Это имена операторов, библиотечных функций, команды препроцессора и так далее. Этим слова нельзя использовать для создания имен своих функций, переменных…
ДАННЫЕ В ПРОГРАММЕ НА СИ
Каждая программа оперирует с данными . Они присутствуют в программе в виде переменных и констант.
Данные, которые могут изменяться или которым может присваиваться значения во время выполнения программы, называются переменными .
Данные, которым устанавливаются определенные значения и они сохраняют свои значения на всем протяжении работы программы, называются константами.
Константы
Константы - это фиксированные значения. Значение, будучи установлено, больше не меняется. Константы бывают различных типов. Типы отличаются по принципу размещения в памяти ЭВМ, а для человека по виду записи. В Си существует 7 ключевых слов, используемых для указания на различные типы данных: int, long, short, unsigned, char, float, double.
Типы констант :
a) Целые и длинные целые . Записываются в десятичной, восьмеричной и шестнадцатеричной системе счисления. Они могут быть знаковые и беззнаковые.
Десятичная система: целые константы занимают 16 бит памяти, и принимают диапазон значений: -32768 до +32767 (2 15) . Если константа беззнаковая, то диапазон удваивается: 0 до 65535 (за счет того, что 15-й разряд – знаковый используется под число). Для обозначения беззнакового числа используют суффикс u (unsigned), например 123u.
Если число больше 40000, то компилятор автоматически преобразует его в отрицательное число, поэтому суффикс u обязателен:40000u. В примере 123u компилятору все равно – есть суффикс или его нет, так как это число входит в диапазон 32767.
Длинное целое занимает 32 бита , диапазон значений
± 2147483648 (знаковое длинное – long). Если вы поставили суффикс l , то, несмотря на число, будет занято 32 бита. Например: -5326l
0 – 4294967295 беззнаковое длинное - (unsigned long). Диапазон увеличивается за счет 31-го бита. Используются суффиксы ul , например, 32659ul.
Если число начинается с цифры 0, оно интерпретируется как восьмиричное число
16 битов 0 ¸ 077777
0100000 ¸ 0177777u
32 бита 0200000 ¸ 01777777777l
020000000000 ¸ 037777777777ul
Если число начинается с символа 0х, то оно интерпретируется как шестнадцатиричное
16 битов 0x0000 ¸ 0x7FFF
0x8000 ¸ 0xEFFFu
32 бита 0x10000 ¸ 0x7FFFFFFFl
0x80000000 ¸ 0xFFFFFFFFul
b) Вещественные константы . Это числа с плавающей точкой. Значение имеет дробную часть. По умолчанию все вещественные константы имеют тип двойной точности double . Занимают в памяти 8 байт (даже если 0,0). Диапазон значений ±1*10 ± 307 , можно записать и в научной форме, например: 0,5е+15 или
1,2е-3=1,2*10 -8 =0,0012.
Принудительно можно задать формат одинарной точности float . Число будет занимать 4 байта , используется суффикс f (5.7 f). Соответсвенно диапазон сужается ±1*10 ± 37
А также расширенной точности – long double – 10 байт . (3.14L)
Знак + можно не писать. Разрешается опускать либо десятичную точку, либо экспоненциальную часть, но не одновременно (.2; 4е16). Можно не писать дробную либо целую часть, но не одновременно (100.; .8е-5)
c) Символьные константы. Это набор символов, используемых в ЭВМ.
Делятся на 2 группы: печатные и не печатные (управляющие коды). Символьная константа включает в себя только 1 символ, который необходимо заключить в апострофы и занимает 1 байт памяти.
Любой символ имеет своё двойное представление в таблице ASCII. В программе символьные константы вводятся в одинарных кавычках, при компиляции в программу подставляется числовое значение символа из ASCII. Один символ занимает 1 байт.
Символ "А" "a" " " "\n"
Его код 65 97 32 10
Как целый тип данных "A"=0101 8 , 01000001 2 , 41 16 , 65 10 . Коды запоминать не надо.
Управляющие коды начинаются с символа \ и тоже заключаются в апострофы. Наиболее распространенные управляющие коды:
\n – переход на новую строку
\t – табуляция (сдвиг курсора на некоторое фиксированное значение)
\b – шаг назад (сдвиг на одну позицию назад)
\r – возврат каретки (возврат к началу строки)
\f – подача бланка (протяжка бумаги на 1 страницу)
\’ - апостроф
\” - кавычки
Последние три знака могут выступать символьными константами, а также применяться в функции printf() , поэтому применение их в качестве символов может привести к ошибке. Например, если мы хотим вывести строку «Символ \ называется слеш», то оператор должен выглядеть так:
рrintf(«Символ \\ называется слеш»);
a) Строковые константы - содержат последовательность из 1 и более символов, заключённых в " ". Расходуется по 1 байту на любой символ + 1байт на так называемый ноль-символ - признак конца строки. Ноль-символ – не цифра ноль, он означает, что количество символов в строке (N) должно быть на 1 байт больше (N+1), чтобы обозначать конец строки (компилятор его прибавляет сам автоматически). Например: «строка текста» занимает (13+1) байт;
«Мир» -
Си , такие, как статические и локальные переменные, массивы, указатели, функции и т.д., максимально приближены к архитектуре реальных компьютеров. Так, указатель - это просто адрес памяти, массив - непрерывная область памяти, локальные переменные - это переменные, расположенные в аппаратном стеке, статические - в статической памяти. Программист, пишущий на Си , всегда достаточно точно представляет себе, как созданная им программа будет работать на любой конкретной архитектуре. Другими словами, язык Си предоставляет программисту полный контроль над компьютером.Первоначально язык Си задумывался как заменитель Ассемблера для написания операционных систем. Поскольку Си - это язык высокого уровня, не зависящий от конкретной архитектуры, текст операционной системы оказывался легко переносимым с одной платформы на другую. Первой операционной системой, написанной практически целиком на Си , была система Unix. В настоящее время почти все используемые операционные системы написаны на Си . Кроме того, средства программирования, которые операционная система предоставляет разработчикам прикладных программ (так называемый API - Application Program Interface ), - это наборы системных функций на языке Си .
Тем не менее, область применения языка Си не ограничилась разработкой операционных систем. Язык Си оказался очень удобен в программах обработки текстов и изображений, в научных и инженерных расчетах. Объектно-ориентированные языки на основе Си отлично подходят для программирования в оконных средах.
В данном разделе будут приведены лишь основные понятия языка Си (и частично C++). Это не заменяет чтения полного учебника по Си или C++, например, книг и .
Мы будем использовать компилятор C++ вместо Cи. Дело в том, что язык Си почти целиком входит в C++, т.е. нормальная программа , написанная на Си , является корректной C++ программой. Слово "нормальная" означает, что она не содержит неудачных конструкций, оставшихся от ранних версий Си и не используемых в настоящее время. Компилятор C++ предпочтительнее, чем компилятор Си , т.к. он имеет более строгий контроль ошибок. Кроме того, некоторые конструкции C++, не связанные с объектно-ориентированным программированием, очень удобны и фактически являются улучшением языка Си . Это, прежде всего, комментарии // , возможность описывать локальные переменные в любой точке программы, а не только в начале блока, и также задание констант без использования оператора #define препроцесора. Мы будем использовать эти возможности C++, оставаясь по существу в рамках языка Си .
Любая достаточно большая программа на Си (программисты используют термин проект ) состоит из файлов. Файлы транслируются Си -компилятором независимо друг от друга и затем объединяются программой-построителем задач, в результате чего создается файл с программой, готовой к выполнению. Файлы, содержащие тексты Си -программы, называются исходными .
В языке Си исходные файлы бывают двух типов:
Имена заголовочных файлов имеют расширение " .h ". Имена файлов реализации имеют расширения " .c " для языка Си и " .cpp ", " .cxx " или " .cc " для языка C++.
К сожалению, в отличие от языка Си , программисты не сумели договориться о едином расширении имен для файлов, содержащих программы на C++. Мы будем использовать расширение " .h " для заголовочных файлов и расширение " .cpp " для файлов реализации.
Заголовочные файлы содержат только описания. Прежде всего, это прототипы функций. Прототип функции описывает имя функции , тип возвращаемого значения, число и типы ее аргументов. Сам текст функции в h-файле не содержится. Также в h-файлах описываются имена и типы внешних переменных, константы , новые типы, структуры и т.п. В общем, h-файлы содержат лишь интерфейсы , т.е. информацию, необходимую для использования программ, уже написанных другими программистами (или тем же программистом раньше). Заголовочные файлы лишь сообщают информацию о других программах. При трансляции заголовочных файлов, как правило, никакие объекты не создаются. Например, в заголовочном файле нельзя определить глобальную переменную. Строка описания
определяющая целочисленную переменную x , является ошибкой. Вместо этого следует использовать описание
означающее, что переменная x определена где-то в файле реализации (в каком - неизвестно). Слово extern (внешняя) лишь сообщает информацию о внешней переменной, но не определяет эту переменную.
Файлы реализации , или Cи-файлы, содержат тексты функций и определения глобальных переменных. Говоря упрощенно, Си -файлы содержат сами программы, а h-файлы - лишь информацию о программах.
Представление исходных текстов в виде заголовочных файлов и файлов реализации необходимо для создания больших проектов, имеющих модульную структуру. Заголовочные файлы служат для передачи информации между модулями. Файлы реализации - это отдельные модули, которые разрабатываются и транслируются независимо друг от друга и объединяются при создании выполняемой программы.
Файлы реализации могут подключать описания, содержащиеся в заголовочных файлах. Сами заголовочные файлы также могут использовать другие заголовочные файлы. Заголовочный файл подключается с помощью директивы препроцессора #include . Например, описания стандартных функций ввода-вывода включаются с помощью строки
#include
(stdio - от слов standard input /output). Имя h-файла записывается в угловых скобках, если этот h-
Для начала стоит понять, что программу нельзя читать и писать как книгу: от корки до корки, сверху вниз, строку за строкой. Любая программа состоит из отдельных блоков. Начало блока кода в C/C++ обозначается левой фигурной скобкой { , его конец - правой фигурной скобкой } .
Блоки бывают разных видов и какой из них когда будет исполняться зависит от внешних условий. В примере минимальной программы вы можете видеть 2 блока. В этом примере блоки называются определением функции . Функция - это просто блок кода с заданным именем, которым кто-то затем может пользоваться из-вне.
В данном случае у нас 2 функции с именами setup и loop . Их присутствие обязательно в любой программе на C++ для Arduino. Они могут ничего и не делать, как в нашем случае, но должны быть написаны. Иначе на стадии компиляции вы получите ошибку.
Давайте теперь дополним нашу программу так, чтобы происходило хоть что-то. На Arduino, к 13-му пину подключён светодиод. Им можно управлять, чем мы и займёмся.
void setup() { pinMode(13 , OUTPUT) ; } void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; digitalWrite(13 , LOW) ; delay(900 ) ; }Скомпилируйте, загрузите программу. Вы увидите, что каждую секунду светодиод на плате помигивает. Разберёмся почему этот код приводит к ежесекундному миганию.
Каждое выражение - это приказ процессору сделать нечто. Выражения в рамках одного блока исполняются одно за другим, строго по порядку без всяких пауз и переключений. То есть, если мы говорим об одном конкретном блоке кода, его можно читать сверху вниз, чтобы понять что делается.
Теперь давайте поймём в каком порядке исполняются сами блоки, т.е. функции setup и loop . Не задумывайтесь пока что значат конкретные выражения, просто понаблюдайте за порядком.
Как только Arduino включается, перепрошивается или нажимается кнопка RESET , «нечто» вызывает функцию setup . То есть заставляет исполняться выражения в ней.
Как только работа setup завершается, сразу же «нечто» вызывает функцию loop .
Как только работа loop завершается, сразу же «нечто» вызывает функцию loop ещё раз и так до бесконечности.
Если пронумеровать выражения по порядку, как они исполняются, получится:
void setup() { pinMode(13 , OUTPUT) ; ❶ } void loop() { digitalWrite(13 , HIGH) ; ❷ ❻ ❿ delay(100 ) ; ❸ ❼ … digitalWrite(13 , LOW) ; ❹ ❽ delay(900 ) ; ❺ ❾ }Ещё раз напомним, что не стоит пытаться воспринимать всю программу, читая сверху вниз. Сверху вниз читается только содержимое блоков. Мы вообще можем поменять порядок объявлений setup и loop .
void loop() { digitalWrite(13 , HIGH) ; ❷ ❻ ❿ delay(100 ) ; ❸ ❼ … digitalWrite(13 , LOW) ; ❹ ❽ delay(900 ) ; ❺ ❾ } void setup() { pinMode(13 , OUTPUT) ; ❶ }Результат от этого не изменится ни на йоту: после компиляции вы получите абсолютно эквивалентный бинарный файл.
Теперь давайте попробуем понять почему написанная программа приводит в итоге к миганию светодиода.
Как известно, пины Arduino могут работать и как выходы и как входы. Когда мы хотим чем-то управлять, то есть выдавать сигнал, нам нужно перевести управляющий пин в состояние работы на выход. В нашем примере мы управляем светодиодом на 13-м пине, поэтому 13-й пин перед использованием нужно сделать выходом.
Это делается выражением в функции setup:
PinMode(13 , OUTPUT) ;
Выражения бывают разными: арифметическими, декларациями, определениями, условными и т.д. В данном случае мы в выражении осуществляем вызов функции . Помните? У нас есть свои функции setup и loop , которые вызываются чем-то, что мы назвали «нечто». Так вот теперь мы вызываем функции, которые уже написаны где-то.
Конкретно в нашем setup мы вызываем функцию с именем pinMode . Она устанавливает заданный по номеру пин в заданный режим: вход или выход. О каком пине и о каком режиме идёт речь указывается нами в круглых скобках, через запятую, сразу после имени функции. В нашем случае мы хотим, чтобы 13-й пин работал как выход. OUTPUT означает выход, INPUT - вход.
Уточняющие значения, такие как 13 и OUTPUT называются аргументами функции . Совершенно не обязательно, что у всех функций должно быть по 2 аргумента. Сколько у функции аргументов зависит от сути функции, от того как её написал автор. Могут быть функции с одним аргументом, тремя, двадцатью; функции могут быть без аргументов вовсе. Тогда для их вызова круглые скобка открывается и тут же закрывается:
NoInterrupts() ;
На самом деле, вы могли заметить, наши функции setup и loop также не принимают никакие аргументы. И загадочное «нечто» точно так же вызывает их с пустыми скобками в нужный момент.
Вернёмся к нашему коду. Итак, поскольку мы планируем вечно мигать светодиодом, управляющий пин должен один раз быть сделан выходом и затем мы не хотим вспоминать об этом. Для этого идеологически и предназначена функция setup: настроить плату как нужно, чтобы затем с ней работать.
Перейдём к функции loop:
void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; digitalWrite(13 , LOW) ; delay(900 ) ; }Она, как говорилось, вызывается сразу после setup . И вызывается снова и снова как только сама заканчивается. Функция loop называется основным циклом программы и идеологически предназначена для выполнения полезной работы. В нашем случае полезная работа - мигание светодиодом.
Пройдёмся по выражениям по порядку. Итак, первое выражение - это вызов встроенной функции digitalWrite . Она предназначена для подачи на заданный пин логического нуля (LOW , 0 вольт) или логической единицы (HIGH , 5 вольт) В функцию digitalWrite передаётся 2 аргумента: номер пина и логическое значение. В итоге, первым делом мы зажигаем светодиод на 13-м пине, подавая на него 5 вольт.
Как только это сделано процессор моментально приступает к следующему выражению. У нас это вызов функции delay . Функция delay - это, опять же, встроенная функция, которая заставляет процессор уснуть на определённое время. Она принимает всего один аргумент: время в миллисекундах, которое следует спать. В нашем случае это 100 мс.
Пока мы спим всё остаётся как есть, т.е. светодиод продолжает гореть. Как только 100 мс истекают, процессор просыпается и тут же переходит к следующему выражению. В нашем примере это снова вызов знакомой нам встроенной функции digitalWrite . Правда на этот раз вторым аргументом мы передаём значение LOW . То есть устанавливаем на 13-м пине логический ноль, то есть подаём 0 вольт, то есть гасим светодиод.
После того, как светодиод погашен мы приступаем к следующему выражению. И снова это вызов функции delay . На этот раз мы засыпаем на 900 мс.
Как только сон окончен, функция loop завершается. По факту завершения «нечто» тут же вызывает её ещё раз и всё происходит снова: светодиод поджигается, горит, гаснет, ждёт и т.д.
Если перевести написанное на русский, получится следующий алгоритм:
Поджигаем светодиод
Спим 100 миллисекунд
Гасим светодиод
Спим 900 миллисекунд
Переходим к пункту 1
Таким образом мы получили Arduino с маячком, мигающим каждые 100 + 900 мс = 1000 мс = 1 сек.
Давайте пользуясь только полученными знаниями сделаем несколько вариаций программы, чтобы лучше понять принцип.
Вы можете подключить внешний светодиод или другое устройство, которым нужно «мигать» на другой пин. Например, на 5-й. Как в этом случае должна измениться программа? Мы должны всюду, где обращались к 13-му пину заменить номер на 5-й:
Компилируйте, загружайте, проверяйте.
Что нужно сделать, чтобы светодиод мигал 2 раза в секунду? Уменьшить время сна так, чтобы в сумме получилось 500 мс:
void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(450 ) ; }Как сделать так, чтобы светодиод при каждом «подмигивании» мерцал дважды? Нужно поджигать его дважды с небольшой паузой между включениями:
void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(50 ) ; digitalWrite(5 , HIGH) ; delay(50 ) ; digitalWrite(5 , LOW) ; delay(350 ) ; }Как сделать так, чтобы в устройстве были 2 светодиода, которые мигали бы каждую секунду поочерёдно? Нужно общаться с двумя пинами и работать в loop то с одним, то с другим:
void setup() { pinMode(5 , OUTPUT) ; pinMode(6 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; digitalWrite(6 , HIGH) ; delay(100 ) ; digitalWrite(6 , LOW) ; delay(900 ) ; }Как сделать так, чтобы в устройстве были 2 светодиода, которые переключались бы на манер железнодорожного светофора: горел бы то один то другой? Нужно просто не выключать горящий светодиод тут же, а дожидаться момента переключения:
void setup() { pinMode(5 , OUTPUT) ; pinMode(6 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; digitalWrite(6 , LOW) ; delay(1000 ) ; digitalWrite(5 , LOW) ; digitalWrite(6 , HIGH) ; delay(1000 ) ; }Можете проверить другие идеи самостоятельно. Как видите, всё просто!
В языке C++ пробелы, переносы строк, символы табуляции не имеют большого значения для компилятора. Там где стоит пробел, может быть перенос строки и наоборот. На самом деле 10 пробелов подряд, 2 переноса строки и ещё 5 пробелов - это всё эквивалент одного пробела.
Пустое пространство - это инструмент программиста, с помощью которого можно или сделать программу понятной и наглядной, или изуродовать до неузнаваемости. Например, вспомним программу для мигания светодиодом:
void setup() { pinMode(5 , OUTPUT) ; } void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }Мы можем изменить её так:
void setup( ) { pinMode(5 , OUTPUT) ; } void loop () { digitalWrite(5 ,HIGH) ; delay(100 ) ; digitalWrite(5 ,LOW) ; delay(900 ) ; }Всё, что мы сделали - немного «поработали» с пустым пространством. Теперь можно наглядно видеть разницу между стройным кодом и нечитаемым.
Чтобы следовать негласному закону оформления программ, который уважается на форумах, при чтении другими людьми, легко воспринимается вами же, следуйте нескольким простым правилам:
1. Всегда, при начале нового блока между { и } увеличивайте отступ. Обычно используют 2 или 4 пробела. Выберите одно из значений и придерживайтесь его всюду.
Плохо:
void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }Хорошо:
void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }2. Как и в естественном языке: ставьте пробел после запятых и не ставьте до.
Плохо:
DigitalWrite(5 ,HIGH) ; digitalWrite(5 , HIGH) ; digitalWrite(5 ,HIGH) ;
Хорошо:
DigitalWrite(5 , HIGH) ;
3. Размещайте символ начала блока { на новой строке на текущем уровне отступа или в конце предыдущей. А символ конца блока } на отдельной строке на текущем уровне отступа:
Плохо:
void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; }Хорошо:
void setup() { pinMode(5 , OUTPUT) ; } void setup() { pinMode(5 , OUTPUT) ; }4. Используйте пустые строки для разделения смысловых блоков:
Хорошо:
Ещё лучше:
void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; digitalWrite(6 , HIGH) ; delay(100 ) ; digitalWrite(6 , LOW) ; delay(900 ) ; }Вы могли заинтересоваться: зачем в конце каждого выражения ставится точка с запятой? Таковы правила C++. Подобные правила называются синтаксисом языка . По символу; компилятор понимает где заканчивается выражение.
Как уже говорилось, переносы строк для него - пустой звук, поэтому ориентируется он на этот знак препинания. Это позволяет записывать сразу несколько выражений в одной строке:
void loop() { digitalWrite(5 , HIGH) ; delay(100 ) ; digitalWrite(5 , LOW) ; delay(900 ) ; }Программа корректна и эквивалентна тому, что мы уже видели. Однако писать так - это дурной тон. Код гораздо сложнее читается. Поэтому если у вас нет 100% веских причин писать в одной строке несколько выражений, не делайте этого.
Одно из правил качественного программирования: «пишите код так, чтобы он был настолько понятным, что не нуждался бы в пояснениях». Это возможно, но не всегда. Для того, чтобы пояснить какие-то не очевидные моменты в коде его читателям: вашим коллегам или вам самому через месяц, существуют так называемые комментарии.
Это конструкции в программном коде, которые полностью игнорируются компилятором и имеют значение только для читателя. Комментарии могут быть многострочными или однострочными:
/* Функция setup вызывается самой первой, при подаче питания на Arduino А это многострочный комментарий */ void setup() { // устанавливаем 13-й пин в режим вывода pinMode(13 , OUTPUT) ; } void loop() { digitalWrite(13 , HIGH) ; delay(100 ) ; // спим 100 мс digitalWrite(13 , LOW) ; delay(900 ) ; }Как видите, между символами /* и */ можно писать сколько угодно строк комментариев. А после последовательности / / комментарием считается всё, что следует до конца строки.
Итак, надеемся самые основные принципы составления написания программ стали понятны. Полученные знания позволяют программно управлять подачей питания на пины Arduino по определённым временны́м схемам. Это не так уж много, но всё же достаточно для первых экспериментов.
Состав языкаВ тексте на любом естественном языке можно выделить четыре
основных элемента: символы, слова, словосочетания и предложения.
Подобные элементы содержит и алгоритмический язык:
Алфавит языка, или его символы - это основные неделимые знаки, с
помощью которых пишутся все тексты на языке.
Лексема- минимальная единица языка, имеющая самостоятельный
смысл.
Выражение задает правило вычисления некоторого значения.
Оператор задает законченное описание некоторого действия.
Для описания сложного действия требуется последовательность
операторов. Операторы могут быть объединены в составной
оператор, или блок (блоком в языке С++ считается
последовательность операторов, заключенная в фигурные скобки { }).
В этом случае они рассматриваются как один оператор.
Каждый элемент языка определяется синтаксисом и семантикой.
Синтаксические определения устанавливают правила построения
элементов языка, а семантика определяет их смысл и правила
использования.
Объединенная единым алгоритмом совокупность описаний и
операторов образует программу на алгоритмическом языке.
В программах на языке си - существует некая последовательность:
Для начала мы добавляем нужные нам библиотеки #include Если файл находится в текущем каталоге проекта, он указывается в кавычках. Для файла, находящегося в другом каталоге необходимо в кавычках указать полный путь.
#include
#include «math.h»
После чего Мы можем добавить нужные нам константы #define A 3
После этого начинается функция, командой Main ()
После того как всё выполнено можно ввести getchar ()
2. Для чего в языке Си служит точка с запятой?
Для обозначения конца оператора в языке Си используется точка с запятой
3. Все ли компиляторы Си требуют использования в программе инструкции return?
Для возврата целочисленного значения перед завершением функции дописывается строка
Также в большенстве случаев return означает выход из фуннкции
Операторы тела функции выполняются до первого оператора return. Если в теле функции нет такого оператора (т.е. функция не возвращает никакого результата), то выполняются все операторы до закрывающейся операторной скобки.
Функция вывода элементов массива на печать не возвращает никакого результата, т.е. в теле функции оператор return отсутствует.
4. С какой целью в текст программы вводятся комментарии?
Коментарии вводятся для пояснения того или иного действия
например Printf (‘’Hello World’’) ; // выведем на экран надпись Hello World
Так же коментарии можно ввести символами /* - в начале */ - в конце коментария
5. Для чего при вызове функции используются параметры?
Ссылка - это по сути второе имя того же самого объекта. Когда в функцию передаётся объект по ссылке, то передаётся фактически этот объект. Когда же мы передаём объект по значению, то в функцию передаётся его копия.
void func_1(int a) // передача по значению
6. Все ли функции требуют передачи параметров при вызове?
На мой взгляд совершенно не все, ведь мы можем с лёгкостью записать функцию типа main() без передчи параметров по значению
1. Что такое тип данных char?
Тип данных char - это целочисленный тип данных, который используется для представления символов. То есть, каждому символу соответствует определённое число из диапазона . Тип данных char также ещё называют символьным типом данных, так как графическое представление символов в С++ возможно благодаря char. Для представления символов в C++ типу данных char отводится один байт, в одном байте - 8 бит, тогда возведем двойку в степень 8 и получим значение 256 - количество символов, которое можно закодировать. Таким образом, используя тип данных char можно отобразить любой из 256 символов. Все закодированные символы представлены в таблице ASCII.
2. Чем символ "3" отличается от числа 3?
символ 3 отличается от целого числа 3 тем, что символ не может быть использован в арифметических операциях
3. В чем заключается различие между константой и переменной?
Различие между переменной и константой довольно очевидно: во время выполнения программы значение переменной может быть изменено (например, с помощью присваивания), а значение константы - нет
4. Как определить константу?
Константы в С++ аналогичны константам в Си. Для представления константы в Си использовалась только директива препроцессора #define:
const тип ИмяПеременной = НачальноеЗначение;
Область видимости константы такая же, как у обычной переменной. С помощью ключевого слова const можно объявить указатель на константу
5. Поддерживает ли Си строковый тип данных?
Язык Си не поддерживает отдельный строковый тип данных, но он позволяет определить строки двумя различными способами. В первом используется массив символов, а во втором - указатель на первый символ массива.
6. Сохраняет ли переменная свое значение в ходе выполнения всей программы?
во время выполнения программы значение переменной может быть изменено (например, с помощью присваивания), а значение константы - нет
7. Как изменить значение константы?
1. В чем заключаются различия между escape-последовательностями \n и \r?
Грубо говоря, предполагалось, что \r обнулит номер символа. оставляя неизменным номер строки (т.е. сдвинет каретку пишущей машинки к началу строки, не трогая бумагу), а \n - наоборот, сделает переход к следующей строке, оставляя текущую позицию печати неизменной (прокрутит бумагу, не трогая каретку).
2. Как вывести на экран символ «кавычка»?
printf("My text is: \"my text\"\n");
3. Из каких двух частей состоит список параметров функции printf()?
При печати какого либо числа или выражения сначала пишется Printf ()
В скобках, в начале в кавычках пишем нужные нам данные, а именно
%с – одиночный символ
%d – десятичное целое число со знаком
%f – число с плавающей точкой (десятичное представление)
%s – строка символов (для строковых переменных)
%u – десятичное целое без знака
%% - печать знака процента
Например:
printf ("x=%5i\ty=%f\tz=%7.3f\n",x, y, z);
4. Какие преимущества имеет функция printf() по сравнению с puts()?
5. Что такое указатель формата?
Читает значение с плавающей точкой (только C99)
Аналогично коду %a (только C99)
Читает один символ
Читает десятичное целое
Читает целое в любом формате (десятичное, восьмеричное или шестнадцатеричное)
Аналогично коду %e
Читает число с плавающей точкой
Аналогично коду %f (только С99)
Читает число с плавающей точкой
Аналогично коду %g
Читает восьмеричное число
Читает строку
Читает шестнадцатеричное число
Аналогично коду %x
Читает указатель
Принимает целое значение, равное количеству прочитанных до сих пор символов
Читает десятичное целое без знака
Просматривает набор символов
Читает знак процента
6. Как вывести на экран значение числовой переменной?
Вывести её значение можно с помощью функции Printf()
printf("%7.3f\t%7.3f\n",x,y);
%<количество_позиций_под_значение>.<количество_позиций_под_дробную_часть>f
%<количество_позиций_под_значение>i