AVR123:Глава 5 — различия между версиями
Nekolex (обсуждение | вклад) |
Nekolex (обсуждение | вклад) |
||
Строка 2: | Строка 2: | ||
[[AVR123 | Вернуться на главную]] | [[AVR123 | Вернуться на главную]] | ||
+ | == Язык Си для AVR. == | ||
− | + | Как раз то, что необходимо и достаточно | |
− | |||
− | Как раз то, что необходимо и достаточно | ||
для микроконтроллеров. | для микроконтроллеров. | ||
Строка 14: | Строка 13: | ||
'''Минимальная программа на Си''' может быть такой: | '''Минимальная программа на Си''' может быть такой: | ||
<source lang="c">main(){}</source> | <source lang="c">main(){}</source> | ||
− | Эта программа не делает ни чего | + | Эта программа не делает ни чего полезного — но это уже программа и она показывает что в программе на языке Си — должна быть главная функция main — обязательно ! |
− | Скачайте и Распечатайте.[http://avr123.nm.ru/csyntax.pdf Памятка Си для МК на ОДНОЙ странице.] | + | Скачайте и Распечатайте.'''[http://avr123.nm.ru/csyntax.pdf Памятка Си для МК на ОДНОЙ странице.]''' |
− | Рассказывая про МК я говорил вам, что: | + | Рассказывая про МК я говорил вам, что: |
Задача программы МК: | Задача программы МК: | ||
+ | |||
* читать числа из регистров и памяти МК, | * читать числа из регистров и памяти МК, | ||
− | * делать что-то с числами, данными | + | * делать что-то с числами, данными и |
− | * записывать числа в регистры и память. | + | * записывать числа в регистры и память. |
Только так программа может общаться с МК. | Только так программа может общаться с МК. | ||
+ | == Как это делать на языке Си == | ||
− | + | ; Регистры МК | |
+ | : ( ''регистры'' - это ячейки-байты в памяти МК AVR ) в программе на Си имеют названия как и в ДШ и так как числа в большинстве из них можно менять - для программы регистры являются по сути переменными. | ||
+ | ; Переменная | ||
+ | : - это набор ячеек в памяти в которых можно хранить число или числа и менять их. Переменная имеет адрес и имя. | ||
+ | ; Константа | ||
+ | : - это как переменная но менять содержимое нельзя. | ||
− | + | === Подробней о переменных и константах написано ниже. === | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | ==== | + | ==== 1) Чтобы поместить число в переменную (в регистр) в языке Си есть оператор присваивания ==== |
− | |||
это знак "=" ( называемый в математике "равно" ) | это знак "=" ( называемый в математике "равно" ) | ||
− | "=" | + | "=" в Си означает вычислить результат того что справа от оператора присваивания и поместить этот результат в переменную находящуюся левее оператора присваивания. |
− | {{InfoBlock|В Си знак <nowiki>"="</nowiki> НЕ означает равенство!|Запомните!}} | + | |
+ | {{InfoBlock|В Си знак <nowiki>"="</nowiki> НЕ означает равенство!|Запомните!}} | ||
+ | |||
<source lang="c"> | <source lang="c"> | ||
− | PORTB = PINB + 34;/* Эта строчка на Си означает взять (прочитать, считать) | + | PORTB = PINB + 34;/* Эта строчка на Си означает взять (прочитать, считать) |
− | + | значение переменной (регистра) PINB, затем прибавить | |
− | + | к нему число 34 и поместить результат в переменную PORTB */ | |
+ | |||
+ | ПЕРЕМЕННАЯ = PINC; /* Эта строчка на Си означает взять (прочитать, считать) | ||
+ | значение переменной (регистра) PINC и поместить результат | ||
+ | в переменную с именем ПЕРЕМЕННАЯ */ | ||
+ | </source> | ||
+ | Чтобы в Си взять (прочитать) число из регистра или значение переменной нужно написать его название НЕ непосредственно с лева от оператора присваивания ! | ||
− | + | ===== Примеры : ===== | |
− | |||
− | |||
− | |||
− | |||
− | + | : a) Строка где переменная стоит слева от = но через знак & | |
− | |||
<source lang="c">PORTB & = 0x23;</source> | <source lang="c">PORTB & = 0x23;</source> | ||
− | на Си означает - прочитать содержимое переменной PORTB, затем выполнить "поразрядное (побитное) логическое И" между прочитанным значением и числом 0x23 | + | на Си означает - прочитать содержимое переменной PORTB, затем выполнить "поразрядное (побитное) логическое И" между прочитанным значением и числом 0x23 и поместить (записать, присвоить) результат в переменную PORTB |
+ | |||
+ | : b) Строка где переменная стоит непосредственно слева от = | ||
− | |||
<source lang="c">PORTB = 0x23;</source> | <source lang="c">PORTB = 0x23;</source> | ||
− | на Си означает - не читая содержимое переменной PORTB присвоить ей значение | + | на Си означает - не читая содержимое переменной PORTB присвоить ей значение 0x23 уничтожив то что было там раньше. |
− | <pre>:Вместо & "И" (AND - только 1 и 1 дают 1) могут быть и другие побитные логические операции: | + | <pre>:Вместо & "И" (AND - только 1 и 1 дают 1) могут быть и другие побитные логические операции: |
− | + | • | "ИЛИ" (OR только 0 и 0 дают 0) | |
− | + | • ^ "Исключающее ИЛИ" (XOR изменить бит напротив "1") | |
− | + | • ~ "инвертирование битов" (INV изменить биты регистра) | |
− | + | • арифметические операции: + - * / %</pre> | |
С оператором присваивания используются вот такие сокращения: | С оператором присваивания используются вот такие сокращения: | ||
− | {|class="wikitable" | + | |
− | !|ДЛИННАЯ ЗАПИСЬ||СМЫСЛ||СОКРАЩАЕТСЯ ДО | + | {| class="wikitable" |
+ | !|ДЛИННАЯ ЗАПИСЬ || СМЫСЛ || СОКРАЩАЕТСЯ ДО | ||
|- | |- | ||
− | ||x = x + 1;||добавить 1||x++; или ++x; | + | | |x = x + 1; || добавить 1 || x++; или ++x; |
|- | |- | ||
− | ||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;||умножить на 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 = x % y; || остаток от деления || x %= y; |
|- | |- | ||
− | ||x--;||вычесть 1||x -= 1; | + | | |x--; || вычесть 1 || x -= 1; |
|- | |- | ||
− | ||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> | ||
+ | |||
+ | {| class=wikitable | ||
+ | !|Запомните ! | ||
+ | |- | ||
+ | | |Результатом поразрядных (побитных) | ||
+ | логических операций : | ||
+ | & | ^ ~ | ||
+ | является число ! Которое может быть интерпретировано компилятором как "истина" если оно не ноль и "ложно" если число ноль. | ||
+ | |} | ||
+ | |||
+ | Числа | ||
+ | |||
+ | В компиляторе можно записывать в виде указанном в | ||
+ | его 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> | ||
+ | ТОЧКА ОБЯЗАТЕЛЬНА ! | ||
+ | |||
+ | {| class=wikitable width=75% | ||
+ | |- | ||
+ | !colspan="10"|Различные представления числа D3h равно 0xD3 равно 0b1101 0011 равно 211 | ||
+ | |- | ||
+ | !colspan="10" |шестнадцатеричное число 0xD3 | ||
+ | |- | ||
+ | | |0 || x | ||
+ | | colspan="4"|D | ||
+ | | colspan="4"|3 | ||
+ | |- | ||
+ | !colspan="10"|двоичное представление - число 0b1101 0011 | ||
+ | |- | ||
+ | | width=10%|0 | ||
+ | | width=10%|b | ||
+ | | width=10%|1 | ||
+ | | width=10%|1 | ||
+ | | width=10%|0 | ||
+ | | width=10%|1 | ||
+ | | width=10%|0 | ||
+ | | width=10%|0 | ||
+ | | width=10%|1 | ||
+ | | width=10%|1 | ||
+ | |- | ||
+ | | colspan="2"|номера бита | ||
+ | | 7 || 6 || 5 || 4 || 3 || 2 || 1 || 0 | ||
+ | |- | ||
+ | !colspan="10"| два в степени равной номеру бита | ||
+ | |- | ||
+ | | | || || 128 || 64 || 32 || 16 || 8 || 4 || 2 || 1 | ||
+ | |- | ||
+ | !colspan="10"|число 211 в десятичном виде это сумма степеней двойки где биты равны "1" | ||
+ | |- | ||
+ | | colspan="2"|Сложите || +128 || +64 || || +16 || || || +2 || +1 | ||
+ | |} | ||
+ | |||
+ | Четыре бита это 1 "нибл" (полубайт) или 1 символ в 16-ричной системе или десятичное число от 0 до 15. | ||
+ | |||
+ | "В уме" удобно оперировать ниблами:двоичный десятичный 16-ричный | ||
+ | |||
+ | {| class = wikitable align=top | ||
+ | ! width="33%" align="center" | двоичный | ||
+ | ! width="33%" align="center" | десятичный | ||
+ | ! width="34%" align="center" | 16-ричный | ||
+ | |- | ||
+ | | width="33%" align="center" | 0000 | ||
+ | | width="67%" align="center" colspan="2" | 0 | ||
+ | |- | ||
+ | | width="33%" align="center" | 0001 | ||
+ | | width="67%" align="center" colspan="2" | 1 | ||
+ | |- | ||
+ | | width="33%" align="center" | 0010 | ||
+ | | width="67%" align="center" colspan="2" | 2 | ||
+ | |- | ||
+ | | width="33%" align="center" | 0011 | ||
+ | | width="67%" align="center" colspan="2" | 3 | ||
+ | |- | ||
+ | | width="33%" align="center" | 0100 | ||
+ | | width="67%" align="center" colspan="2" | 4 | ||
+ | |- | ||
+ | | width="33%" align="center" | 0101 | ||
+ | | width="67%" align="center" colspan="2" | 5 | ||
+ | |- | ||
+ | | width="33%" align="center" | 0110 | ||
+ | | width="67%" align="center" colspan="2" | 6 | ||
+ | |- | ||
+ | | width="33%" align="center" | 0111 | ||
+ | | width="67%" align="center" colspan="2" | 7 | ||
+ | |- | ||
+ | | width="33%" align="center" | 1000 | ||
+ | | width="67%" align="center" colspan="2" | 8 | ||
+ | |- | ||
+ | | width="33%" align="center" | 1001 | ||
+ | | width="67%" align="center" colspan="2" | 9 | ||
+ | |- | ||
+ | | width="33%" align="center" | 1010 | ||
+ | | width="33%" align="center" | 10 | ||
+ | | width="34%" align="center" | A | ||
+ | |- | ||
+ | | width="33%" align="center" | 1011 | ||
+ | | width="33%" align="center" | 11 | ||
+ | | width="34%" align="center" | B | ||
+ | |- | ||
+ | | width="33%" align="center" | 1100 | ||
+ | | width="33%" align="center" | 12 | ||
+ | | width="34%" align="center" | C | ||
+ | |- | ||
+ | | width="33%" align="center" | 1101 | ||
+ | | width="33%" align="center" | 13 | ||
+ | | width="34%" align="center" | D | ||
+ | |- | ||
+ | | width="33%" align="center" | 1110 | ||
+ | | width="33%" align="center" | 14 | ||
+ | | width="34%" align="center" | E | ||
+ | |- | ||
+ | | width="33%" align="center" | 1111 | ||
+ | | width="33%" align="center" | 15 | ||
+ | | width="34%" align="center" | F | ||
+ | |} | ||
+ | |||
+ | Для перевода чисел из одного вида в другой можно использовать калькулятор Windows в инженерном виде. | ||
+ | |||
+ | Есть в Си операции которые изменяют значение | ||
+ | переменной и без оператора присваивания : | ||
+ | <source lang="c"> | ||
+ | PORTA++; /* Эта строчка на Си означает взять значение переменной PORTA | ||
+ | добавить к ней 1 и записать результат обратно в PORTA | ||
+ | говорят: Инкрементировать регистр PORTA */ | ||
+ | |||
+ | PORTC--; /* Эта строчка на Си означает | ||
+ | обратное действие! | ||
+ | Декрементировать - вычесть 1 из значения регистра PORTC */ | ||
+ | </source> | ||
+ | |||
+ | Инкремент и декремент удобно использовать для изменения значения различных переменных счетчиков. | ||
+ | |||
+ | Важно помнить что они имеют очень низкий приоритет - поэтому чтобы быть уверенными в порядке выполнения желательно писать | ||
+ | их отдельной строчкой программы ! | ||
+ | |||
+ | {{InfoBlock|В конце выражения или конструкции в программе на Си ставят точку с запятой. |Обратите внимание !}} | ||
+ | |||
+ | Длинные выражения можно писать в несколько строк. | ||
+ | <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): | ||
+ | |||
+ | {| | ||
+ | | width=5%|= | ||
+ | | width=5%|+= | ||
+ | | width=5%|-= | ||
+ | | width=5%|= | ||
+ | | width=5%|/= | ||
+ | | width=5%|&= | ||
+ | | width=5%| |= | ||
+ | | width=5%|^= | ||
+ | | width=5%|<<= | ||
+ | | width=5%|>>= | ||
+ | |}{ | ||
+ | |||
+ | {InfoBlock|Чтобы точно знать порядок выполнения операций программой используйте скобки ( ) | ||
+ | |||
+ | ( () + ( () * () ) ) | ||
+ | Ведь скобки ( ) имеют наивысший приоритет.|Совет:}} | ||
+ | |||
+ | == Самое интересное ! == | ||
+ | |||
+ | <font color="#3366ff">Ходовые конструкции на Си</font> | ||
+ | В компиляторе '''[http://avr123.nm.ru/CVAVR CVAVR]''' заготовки этих конструкций находятся под ярлыком "'''Code Templates'''" слева вверху. Вы можете выбирать нужные заготовки и вставлять их в свою программу. | ||
+ | |||
+ | [[Image:05 temp.png]] | ||
+ | |||
+ | '''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 | ||
+ | |||
+ | [http://www.citforum.ru/programming/c/h14.shtml#145 Прочитайте]подробней о ''switch'' с примерами. | ||
+ | |||
+ | [http://avr123.nm.ru/ascii.pdf Скачайте и распечатайте таблицу символов ASCII на ОДНОЙ странице!] |
Версия 03:01, 27 сентября 2009
Содержание
Язык Си для 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 на ОДНОЙ странице!