AVR123:Глава 5
Содержание
Язык Си для AVR.
Как раз то, что необходимо и достаточно для микроконтроллеров.
По умолчанию компилятор CVAVR
В других компиляторах могут быть незначительные отклонения, нюансы не связанные с языком Си, а обусловленные стараниями и предпочтениями разработчиков этих компиляторов.
Минимальная программа на Си может быть такой: <source lang="c">main(){}</source> Эта программа не делает ни чего полезного — но это уже программа и она показывает что в программе на языке Си — должна быть главная функция main — обязательно !
Скачайте и Распечатайте.Памятка Си для МК на ОДНОЙ странице.
Рассказывая про МК я говорил вам, что: Задача программы МК:
- читать числа из регистров и памяти МК,
- делать что-то с числами, данными и
- записывать числа в регистры и память.
Только так программа может общаться с МК.
Как это делать на языке Си
- Регистры МК
- ( регистры - это ячейки-байты в памяти МК AVR ) в программе на Си имеют названия как и в ДШ и так как числа в большинстве из них можно менять - для программы регистры являются по сути переменными.
- Переменная
- - это набор ячеек в памяти в которых можно хранить число или числа и менять их. Переменная имеет адрес и имя.
- Константа
- - это как переменная но менять содержимое нельзя.
Подробней о переменных и константах написано ниже.
1) Чтобы поместить число в переменную (в регистр) в языке Си есть оператор присваивания
это знак "=" ( называемый в математике "равно" ) "=" в Си означает вычислить результат того что справа от оператора присваивания и поместить этот результат в переменную находящуюся левее оператора присваивания.
<source lang="c"> PORTB = PINB + 34;/* Эта строчка на Си означает взять (прочитать, считать) значение переменной (регистра) PINB, затем прибавить к нему число 34 и поместить результат в переменную PORTB */
ПЕРЕМЕННАЯ = PINC; /* Эта строчка на Си означает взять (прочитать, считать) значение переменной (регистра) PINC и поместить результат в переменную с именем ПЕРЕМЕННАЯ */ </source> Чтобы в Си взять (прочитать) число из регистра или значение переменной нужно написать его название НЕ непосредственно с лева от оператора присваивания !
Примеры :
- a) Строка где переменная стоит слева от = но через знак &
<source lang="c">PORTB & = 0x23;</source>
на Си означает - прочитать содержимое переменной PORTB, затем выполнить "поразрядное (побитное) логическое И" между прочитанным значением и числом 0x23 и поместить (записать, присвоить) результат в переменную PORTB
- b) Строка где переменная стоит непосредственно слева от =
<source lang="c">PORTB = 0x23;</source>
на Си означает - не читая содержимое переменной PORTB присвоить ей значение 0x23 уничтожив то что было там раньше.
:Вместо & "И" (AND - только 1 и 1 дают 1) могут быть и другие побитные логические операции: • | "ИЛИ" (OR только 0 и 0 дают 0) • ^ "Исключающее ИЛИ" (XOR изменить бит напротив "1") • ~ "инвертирование битов" (INV изменить биты регистра) • арифметические операции: + - * / %
С оператором присваивания используются вот такие сокращения:
ДЛИННАЯ ЗАПИСЬ | СМЫСЛ | СОКРАЩАЕТСЯ ДО |
---|---|---|
x = x + 1; | добавить 1 | x++; или ++x; |
x = x - 1; | вычесть 1 | x--; или --x; |
x = x + y; | прибавить y | x += y; |
x = x - y; | вычесть y | x -= y; |
x = x * y; | умножить на y | x *= y; |
x = x / y; | поделить на y | x /= y; |
x = x % y; | остаток от деления | x %= y; |
x--; | вычесть 1 | x -= 1; |
x++; | добавить 1 | x += 1; |
Примеры :
<source lang="c"> 00010010 | 01001111 // "ИЛИ" - только 0 и 0 дают 0 // англ. название OR
01011111 // это результат
// только биты_5 в обоих числах были нули
00010010 & 01001111 // "И" - только 1 и 1 дают 1 // англ. название AND
00000010 // это результат
// только биты_2 в обоих числах были единицы
00010010 ^ 01001111/* "исключающее ИЛИ" - результат любое из пары чисел в котором инвертированы (изменены) биты напротив битов равных "1" в другом числе. англ. название XOR */ 01011101 // это результат /* изменились биты во втором числе напротив установленных битов 4 и 1 первого числа. */
~ 01001111 /* инвертировать биты те что были "1" станут "0" и наоборот */ 10110000 // это результат</source>
Запомните ! |
---|
Результатом поразрядных (побитных)
логических операций : & | ^ ~ является число ! Которое может быть интерпретировано компилятором как "истина" если оно не ноль и "ложно" если число ноль. |
Числа
В компиляторе можно записывать в виде указанном в его Help ! Раздел - константы - Constants.
например - Целые числа могут быть записаны : <source lang="c"> - в десятичной форме - 1234
- в двоичной форме с префиксом 0b так: 0b101001
- в шестнадцатеричной форме с префиксом 0x так: 0x5А
- в восьмеричной форме с префиксом 0 так: 0775</source>
Числа с плавающей точкой имеют в записи эту точку и какое либо число после этой точки, так: <source lang="c">61.234 или так: 73.0 и так: .786
и могут иметь в конце F вот так: 61.234F</source> ТОЧКА ОБЯЗАТЕЛЬНА !
Различные представления числа D3h равно 0xD3 равно 0b1101 0011 равно 211 | |||||||||
---|---|---|---|---|---|---|---|---|---|
шестнадцатеричное число 0xD3 | |||||||||
0 | x | D | 3 | ||||||
двоичное представление - число 0b1101 0011 | |||||||||
0 | b | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 |
номера бита | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
два в степени равной номеру бита | |||||||||
128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | ||
число 211 в десятичном виде это сумма степеней двойки где биты равны "1" | |||||||||
Сложите | +128 | +64 | +16 | +2 | +1 |
Четыре бита это 1 "нибл" (полубайт) или 1 символ в 16-ричной системе или десятичное число от 0 до 15.
"В уме" удобно оперировать ниблами:двоичный десятичный 16-ричный
двоичный | десятичный | 16-ричный |
---|---|---|
0000 | 0 | |
0001 | 1 | |
0010 | 2 | |
0011 | 3 | |
0100 | 4 | |
0101 | 5 | |
0110 | 6 | |
0111 | 7 | |
1000 | 8 | |
1001 | 9 | |
1010 | 10 | A |
1011 | 11 | B |
1100 | 12 | C |
1101 | 13 | D |
1110 | 14 | E |
1111 | 15 | F |
Для перевода чисел из одного вида в другой можно использовать калькулятор Windows в инженерном виде.
Есть в Си операции которые изменяют значение переменной и без оператора присваивания : <source lang="c"> PORTA++; /* Эта строчка на Си означает взять значение переменной PORTA добавить к ней 1 и записать результат обратно в PORTA говорят: Инкрементировать регистр PORTA */
PORTC--; /* Эта строчка на Си означает обратное действие! Декрементировать - вычесть 1 из значения регистра PORTC */ </source>
Инкремент и декремент удобно использовать для изменения значения различных переменных счетчиков.
Важно помнить что они имеют очень низкий приоритет - поэтому чтобы быть уверенными в порядке выполнения желательно писать их отдельной строчкой программы !
Длинные выражения можно писать в несколько строк. <source lang="c"> /* ЗЕЛЕНЫМ я пишу комментарий к программе в Си он может быть написан в несколько строк
и пустых строк тоже */
// или в одну после двух черточек </source> Компилятор игнорирует все что написано в комментариях !
Вы не компилятор !
Не игнорируйте, пишите комментарии и читайте !
Когда инкремент или декремент используется в выражении то важно где стоят два знака + или - перед переменной или после переменной : <source lang="c"> a=4; b=7;
a = b++; /* Эта строчка на Си означает Взять значение переменной b присвоить его переменной a затем добавить 1 к переменной b и сохранить результат в b
Теперь a будет содержать число 7 b будет содержать число 8 */
a=4; b=7;
a = ++b; /* Эта строчка на Си означает Взять значение переменной b затем добавить к нему 1 и сохранить результат в b и этот же результат присвоить переменной a
Теперь a будет содержать число 8 и b будет содержать число 8 */ </source>
2) Арифметические операции в Си
<source lang="c"> x + y // сложение x - y // вычитание x * y // умножение
x / y /* деление.
Если числа целые результат - целое число с отброшенной дробной частью - не округленное !
т.е. если в результате деления на калькуляторе получается 6.23411 или 6.94 то результат будет просто целое число 6 - запомните !
Если числа с плавающей точкой, то есть float или double и записываются с точкой и числом после точки, то и результат будет число с плавающей точкой без отбрасывания дробной части 131.9739 / 6.18 даст 21.355 */
x % y // вычислить остаток от деления нацело
// примеры:
5 / 2 // даст 2
5 % 2 // даст 1
75 / 29 // даст 2
75 % 29 // даст 17 </source>
3) Операторы сравнения (или отношения):
<source lang="c"> используются для сравнения переменных, чисел (констант) и выражений. x < y // X меньше Y x > y // больше x <= y // меньше или равно x >= y // больше или равно x == y // равно x != y /* не равно
Результат выполнения этих операторов:
"истина" это "1" (точнее "не ноль")
"ложно" это "0"
Значения хранимые в переменных (в регистрах) х и у НЕ изменяются!
Берутся (считываются) значения хранящиеся (или содержащиеся) в переменных и сравниваются */
! /* "НЕ" - логическое отрицание */ </source>
4) Логические операции :
<source lang="c"> | | // "ИЛИ" - только "ложь" и "ложь" // дают "ложь"
&& // "И" - только "истина" и "истина" // дают "истина"
! // "НЕ" - логическое отрицание
/* Правило - в Си считается:
"Ложь" (False) только ноль.
"Истина"(True)- не ноль. или так: (!0)
- /
!(истина) // дает "ложь"
!(ложь) // дает "истина" </source> В результате логической операции вы получаете НЕ ЧИСЛО, а логическое значение "истина" или "ложь"
Для логических операций && и || берутся результаты выражений слева и справа от знака операции преобразованные в "истину" или "ложь" и определяется логический результат операции.
Компилятор, для определенности наверно, результат "истина" превращает в 1 а не в любое отличное от 0 число.
Логические операции могут объединять несколько проверяемых условий.
Пример:
<source lang="c"> if((выражение1)&&((выражение2) || (выражение3))) {/* Код программы здесь будет выполняться если: Выражение1 "Истина" (значит не ноль) и хотя бы одно из выражений 2 и 3 тоже "Истина" (значит не ноль).
- /};</source>
Подробнее о логических операциях обязательно прочитайте по в низу этой страницы !
Приоритет операций в языке Си перечислены в порядке убывания приоритета. Операции, приведённые на одной строчке, имеют одинаковый приоритет. Операции, помеченные как R->L, исполняются справа налево.
- () [] -> .
- Унарные (R->L): ! ~ - * & sizeof (type) ++ --
- Бинарные арифметические: * / %
- Бинарные арифметические + -
- Сдвиг: << >>
- Сравнение: < <= > >=
- Сравнение: == !=
- Битовая: &
- Битовая: ^
- Битовая: |
- Логическая: &&
- Логическая: ||
- Тернарная (R->L): ?:
- Операции с присваиванием (R->L):
= | += | -= | = | /= | &= | |= | ^= | <<= | >>= |
{
{InfoBlock|Чтобы точно знать порядок выполнения операций программой используйте скобки ( )
( () + ( () * () ) ) Ведь скобки ( ) имеют наивысший приоритет.|Совет:}}
Самое интересное !
Ходовые конструкции на Си В компиляторе CVAVR заготовки этих конструкций находятся под ярлыком "Code Templates" слева вверху. Вы можете выбирать нужные заготовки и вставлять их в свою программу.
5) if(){ }else{ }; идеальная конструкция если вам нужно выполнить какую то часть программы при наличии каких либо
условий или при их отсутствии :
<source lang="c"> if (выражение) { код на Си /* делать этот код если выражение "истина" - т.е. результат его вычисления не ноль */ } else { код на Си /* делать этот код если выражение "ложь" - т.е. результат его вычисления равен нулю */ };
// } else { это не обязательный элемент конструкции, без него так :
if (выражение) { код на Си /* делать этот код если выражение "истина" - т.е. результат его вычисления не ноль */ }; </source>
6)while(){ }; условный цикл ( цикл с условием ) - используйте если вам
нужно выполнять какой то код программы пока выполняется (существует,
справедливо, "истино" - значит "не ноль") некоторое условие, результат вычисления выражения :
<source lang="c"> while (выражение) { код на Си /* делать этот код если выражение "истина" - т.е. результат его вычисления не ноль. Пока выполняется этот код выражение не проверяется на истинность ! После выполнения кода происходит переход к строке while снова проверять истинность выражения */ }; </source> Цикл while имеет вариант
do - while при котором код в { } выполняется по меньшей мере один раз не зависимо от истинности условия в скобках : <source lang="c"> do { код на Си /* сделать этот код один раз
затем, если выражение есть "истина" - т.е. результат его вычисления не ноль - опять делать код с начала, и так до тех пор пока выражение истина */ } while (выражение); </source> 7) for(;;){ }; - этот цикл позволяет выполнить часть программы нужное число раз: <source lang="c"> char i; /* объявление переменной для for это обычная переменная Си и значит может иметь любое допустимое имя по вашему желанию и тип */ for (i=5; i i = 5 это начальное выражение, то что в начале будет в переменной i
Число 5 просто для примера, может быть таким, как позволяет объявление типа переменной i, в нашем случае это char в большинстве компиляторов по-умолчанию это без знаковый символьный тип - он может хранить числа от 0 до 255 i < 20 - контрольное выражение Может быть с разными операторами отношения, важно лишь чтобы по ходу цикла оно становилось когда-то "ложью" - иначе цикл "зациклится" т.е. ни когда не кончится.
i += 4 - это счетчик или изменение переменной цикла. Обычно это i++ т.е.к переменной добавляется 1 каждый "прогон" цикла. Но опять же может быть таким какое вам требуется.
- Начальным условием
- - может быть любое допустимое в Си выражение результатом которого является целое число.
- Контрольное выражение
- - определяет до каких пор будет выполнятся цикл.
- Счетчик
- - показывает как изменяется начальное выражение перед каждом новом выполнении цикла .
- Выражение
- - значит это может быть не просто переменная, а что-то посложней, например:
i =(7 + i*4) или i = (функция других переменных)
<source lang="c"> Циклы for(;;) и while()
часто используют вот так:
while(1);
for (;;);
/* Так написанные эти циклы означают :
МК выполнять эту строчку пока есть питание, нет сброса и нет прерывания. Когда возникает прерывание, программа переходит на обработчик прерывания и (если в обработчике нет перехода в другое место программы) по завершении кода обработчика опять возвращается в такой цикл. */
while(1){ код программы };
for (;;){ код программы };
/* Так написанные эти циклы означают :
МК выполнять код программы пока есть питание, нет сброса и нет прерывания. Когда возникает прерывание, программа переходит на обработчик прерывания и (если в обработчике нет перехода в другое место программы) по завершении кода обработчика опять возвращается сюда и продолжает выполнять код программы */ </source>
8)switch(){ }; - оператор множественного выбора,
позволяет вам сделать выбор из нескольких вариантов. <source lang="c"> switch (выражение) { case 5: код на Си /* этот код будет выполняться если результат вычисления выражения равен числу 5
на этом работа оператора switch закончится */ break;
case -32: код на Си /* этот код будет выполняться если результат вычисления выражения равен отрицательномц числу -32
на этом работа оператора switch закончится */ break;
case 'G': код на Си /* этот код будет выполняться если результат вычисления выражения равен числу соответствующему символу G в таблице ASCII
на этом работа оператора switch закончится */ break;
default: код на Си /* этот код будет выполняться если результат вычисления выражения не равен ни 5 ни -32 ни 'G'
А так же после выполнения кода не имеющего в конце break;
на этом работа оператора switch закончится */ };
/* switch закончен - выполняется дальнейший код программы */ </source>
- case
- - может быть столько сколько вам нужно, чтобы программа работала быстрее старайтесь наиболее вероятные варианты располагать выше!
- default
- - не обязателен. Его можно расположить и не в конце.
- break;
- - если его не использовать то найдя нужный вариант программа будет выполнять и следующие ниже условия case
Прочитайтеподробней о switch с примерами.
Скачайте и распечатайте таблицу символов ASCII на ОДНОЙ странице!