Си для avr циклы

Си для avr циклы thumbnail

В данной статье будут рассмотрены циклы в языке программирования Си для микроконтроллеров AVR. Будут рассмотрены циклы типа “для” (for) и циклы типа “пока” (while), будет показано как осуществить принудительное прерывание цикла и организовать бесконечный цикл. Рассмотрены вопросы вложенных циклов и формирования длительных временных задержек.

Структура цикла с предусловием

Для того чтобы несколько раз повторить какую-либо последовательность действий, применяют алгоритмические конструкции, называемые циклами. Саму последовательность действий при этом называют телом цикла.

В языке С есть две разновидности циклов: циклы со счетчиком (типа “для” или for) и цикл с условием (типа “пока” или while). В других языках программирования, например Pascal, циклы с условием разделялись на циклы с предусловием (типа while) и циклы с пост условием (типа repeat until), но в современных языках программирования циклы с пост условием постепенно отмирают.

Циклы типа “для” (for)

Циклы типа “для” (for) применяются в ситуациях, в которых заранее известно количество повторений цикла. Поэтому в составе подобного цикла всегда есть так называемый “счетчик повторений” или “переменная цикла”. Пример использования цикла for в языке представлен на следующем рисунке.

Си для avr циклы

В данном примере тело цикла повторится столько раз, сколько значений “пробежит” переменная цикла i от своего начального значения, задаваемого операцией присваивания i = a, до конечного значения, задаваемого условием i < b. Изменение переменной i определяется условием присваивания вида i = i + c. Но чаще всего в циклах типа for в языке С переменная цикла изменяется за одно повторение цикла на +1 или -1, поэтому используется запись вида i++ (инкремент переменной цикла) или i– (декремент переменной цикла). В рассмотренном примере при i = b цикл завершается и выполняется оператор, следующий за закрывающей скобкой цикла.

Рассмотрим пример цикла for, приведенный на следующем рисунке.

Си для avr циклы

В этом примере на первом шаге цикла переменная i будет равна 1, перед вторым шагом произойдет ее увеличение на 1 в результате инкремента (i++) и она станет равной 2. На третьем шаге значение переменной цикла i будет равно 3. И так до тех пор, пока на пятом шаге цикла она не станет равной 5. В результате следующей операции инкрементирования (i++) переменная цикла получит значение 6, но условие i <= 5 уже не будет истинным, поэтому цикл завершится. Таким образом, тело цикла будет выполнено 5 раз.

Язык С допускает инициализацию переменной цикла в его оглавлении как показано на следующем рисунке.

Си для avr циклы

Но начинающим лучше производить инициализацию переменной цикла в начале функции вместе с остальными инициализируемыми переменными – более подробно читайте об этом в статье про переменные в языке С.

Усовершенствуем программу управления миганием светодиода, рассмотренную в статье про программирование портов микроконтроллеров AVR, с помощью цикла типа “для” (for). Заставим светодиод мигать 10 раз.

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

Программа для мигания светодиодом 10 раз

Циклы типа “пока” (while)

Цикл типа while (“пока”) повторяется до тех пор, пока истинно условие цикла. Поэтому часто его называют циклом с условием. В простейшем виде запись данного цикла выглядит следующим образом:

while (условие)

{

// тело_цикла

}

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

Чтобы цикл завершился, внутри него (в его теле) должно происходить изменение какой-либо переменной, которая входит в условие цикла.

Пример:

int y;

y = 50;

while (y > 0)

{

y = y – 1;

}

В этом примере тело цикла будет повторено (выполнится) 50 раз, до тех пор пока переменная y будет больше нуля. На каждом шаге цикла значение переменной y будет уменьшаться на 1. И когда оно станет равным 0, цикл завершится.

Оператор break

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

В большинстве случаев он используется следующим образом:

if (условие1) break;

Данную последовательность операторов можно записать в любом месте цикла. Но опытные программисты стараются все таки избегать использования данного оператора – для улучшения читаемости и отладки программы желательно в условии цикла прописывать все ситуации, при которых будет нужен выход из цикла.

Бесконечные циклы

Бесконечный цикл в языке программирования С можно осуществить как с помощью цикла “для” (for), так и с помощью цикла “пока” (while). Синтаксис подобных циклов выглядит следующим образом.

for(;;)

{

// тело_цикла

}

или

while (1)

{

// тело_цикла

}

Чаще применяется способ с циклом типа while – он более нагляден. Выйти из подобных циклов можно единственным образом – применив рассмотренный в предыдущем разделе оператор break.

Бесконечные циклы находят широкое распространение в программах для микроконтроллеров, потому что данные программы должны, как правило, работать постоянно до тех пор, пока устройство не обесточат. Много примеров подобных программ вы можете найти на нашем сайте в рубрике “схемы и устройства на микроконтроллерах AVR”.

Вложенные циклы

В большинстве известных в настоящее время языках программирования (и язык Си этому не исключение) допускается использование вложенных циклов – то есть когда один цикл выполняется в теле другого. Пример использования такой конструкции приведен на следующем рисунке:

Пример вложенного цикла в языке С

Рассмотрим пример двух вложенных друг в друга циклов “для”. Тело вложенного цикла в общей сложности будет повторено 200 раз.

В этом примере тело вложенного цикла будет выполнено 200 раз.

Формирование задержки

Аппаратные средства микроконтроллеров AVR не могут формировать длительные задержки – но это, собственно говоря, не очень и нужно потому что сколь угодно длительную задержку можно организовать с помощью циклов (лишь бы имелась возможность формирования хотя бы небольшой задержки). Пример организации задержки длительностью 10 минут с помощью цикла и функции _delay_ms() представлен на следующем рисунке:

Читайте также:  Циклы борьбы за мировое лидерство

Пример организации длительной задержки для микроконтроллеров AVR

Источник

При реализации многих алгоритмов бывает необходимо повторить некую последовательность действий несколько раз. Такое повторение получило наименование цикла, а оператор, для соответствующего действия – оператором цикла.

В Си имеется несколько операторов цикла, один из которых -оператор for. Шаблон описания оператора следующий:

for ([список операторов1]; [условие продолжения]; [список операторов 2]) [тело цикла];

Здесь список операторов1 – перечень операторов, разделенных запятыми, которые должны быть выполнены перед началом цикла; условие продолжения – логическое выражение, истинное значение которого есть непременное условие очередной итерации цикла; список операторов2 – перечень операторов, разделенных запятыми, выполняемых после каждой итерации цикла; тело цикла – это один оператор или ограниченная фигурными скобками последовательность операторов, выполняемых на каждой итерации.

Самое важное, что любая из этих частей оператора for может отсутствовать, о чем свидетельствуют квадратные скобки в шаблоне.

Пример некоторых вариантов оператора цикла for:

for (i = 0, s = 0; i < 10; s += i++);

for (;;);

for (;i < 10;);

for (i = 0, j = 9, s = 0; i < 10; i++, j-) s += arr[i][j];

Первый цикл примера вычисляет сумму всех чисел от 0 до 9 и помещает результат в переменной s. Рассмотрим более подробно, как это происходит.

Сначала выполняются операторы i=0 и s = 0, которые инициализируют (ранее объявленные) переменные i и s. Если в момент объявления эти переменные уже проинициализированы, эта часть оператора for может отсутствовать. Затем происходит проверка условия выполнения итерации цикла, т.е. проверка i < 10. Разумеется, это истинное выражение, и, значит, происходит выполнение тела цикла – очередная (первая) итерация. В рассматриваемом примере тело цикла отсутствует, поэтому просто выполняется завершающая часть, которая состоит из оператора s += i++, который одновременно выполняет 2 действия: накапливает в переменной s сумму значений переменной i, а затем увеличивает значение i на 1. После этих действий снова осуществляется проверка условия, затем очередная итерация и т.д. до тех пор, пока значение i не станет равным 10. В этот момент условие i < 10 станет ложным, и выполнение оператора for закончится.

Продолжим рассмотрение примеров операторов for. Второй цикл, единожды начавшись, никогда не закончится, т.е. это бесконечный оператор, или бесконечный цикл. В этом случае отсутствие выражения проверки условия трактуется как истинное выражение, т.е. «нет требований к условию – значит, любые варианты подходят».

Третий пример показывает оператор цикла, который может быть бесконечным, если переменная i < 10. Т.е. для того, чтобы этот цикл не смог «завесить» программу, необходимо, чтобы либо к началу цикла переменная i уже содержала значение 10 или более, либо каким-то образом во время выполнения цикла значение i должно быть изменено.

Наконец, четвертый пример показывает, как вычислить сумму «правой» диагонали матрицы агг размером 10×10.

Следует отметить, что допускается (1) внутри списка операторов! использовать определение переменных, однако, определенные таким образом переменные, считаются существующими только пока цикл выполняется, и «исчезают» после его завершения:

for (int i=0; i < 10; i++) a += i;

Оператор for имеет довольно много вариантов и возможностей, однако не стоит увлекаться предоставляемой гибкостью. Чем более простая форма оператора будет избрана, тем меньше вероятность ошибки программирования:

// первый способ

for (int i, j=9, s; i < 10; s += arr[i++][j-]);

// второй способ

int i=0, s=0, î = 9;

for (; i<10; i++) {

s += arr[i][j];

j-;

}

В этом примере приведены два варианта ранее рассмотренного подсчета суммы «правой» диагонали матрицы, однако первый способ требует гораздо больше умственных усилий для понимания написанного, чем второй.

Источник

По сложившейся до меня традиции программирование микроконтроллеров начинается с программы управляющей светодиодом. И я в свое время наморгался светодиодами на старом добром AVRовском ките STK200. Это было несколько лет назад, и я до сих пор помню восторг от первых работающих программ, пускай и примитивно простых. Я начинал изучение микроконтроллеров с ассемблера и только спустя пару-тройку лет постепенно перешел на Си. К этому времени я уже хорошо знал всю периферию AVR микроконтроллеров, поэтому больших затруднений этот переход не вызвал.

На интернет форумах время от времени возникают религиозные войны ассемблерных и сишных программистов. По правде говоря, я и сам принимаю в них участие, но не для того чтобы отстоять какую-либо точку зрения, а просто шутки ради. Лично я считаю, что ассемблер полезно знать, но программировать нужно на Си. Знание ассемблера позволят лучше понимать работу микроконтроллера, писать более компактный код на Си. В некоторых случаях к ассемблеру нужно прибегать для написания критичных по времени исполнения или по объему кода кусков программы. Писать же полностью программу на ассемблере… увольте, это слишком утомительно.

Тема у нас сегодня – написание первой программы на Си для AVR микроконтроллера. И для начала нам нужно определиться с компилятором. На данный момент существует довольно много Си компиляторов для AVR микроконтроллеров. Наиболее популярные из них: CodeVision, WIR, ICC ImageCraft, IAR AVR. Какой из них использовать – личное дело каждого. Я немного пользовался всеми, но в конце концов отдал предпочтение IAR AVR. Это платный компилятор, он не так прост в освоении как ICC или CodeVision, для него нет такого количества библиотек как для WIR и по нему мало информации на русском языке. Ммм.. сплошные недостатки. За что же я его тогда так люблю? За его мощь. Мало какой из компиляторов может сравниться с IARом по качеству компиляции сишного кода. И это неудивительно, ведь система команд и внутреннее устройство микроконтроллеров AVR разрабатывались совместно с фирмой IAR Systems. Если вы разделяется мой энтузиазм по поводу этого компилятора или просто решили довериться моему мнению, то эта и последующие статьи по программированию на Си для AVR микроконтроллеров в среде IAR AVR для вас.

Читайте также:  Выделения при менструационного цикла

Итак, первое что вы должны сделать – найти и установить на свой компьютер компилятор IAR AVR. Есть несколько путей решения этой проблемы. Можно скачать программу с официального сайта IAR Systems – iar.com. В разделе Download есть две версии – 30-day evaluation edition и Kickstart edition. Первый вариант – полнофункциональная 30-ти дневная версия без ограничений по коду, второй – полнофункциональная версия без ограничения по времени, но с ограничением по коду 4к. Можно найти программу на просторах сети – поискать на торрентах, на форумах по электронике. Я использую полнофункциональную программу без ограничений версии 5.11. До сих пор никаких нареканий эта версия у меня не вызывала.

Надеюсь, программу вы поставили. Дальше я опишу последовательность действий для создания первого проекта в IARе. Возможно, чересчур подробное описание вызовет у некоторых читателей изрядную степень раздражения. Спокойно, без пены. Люди разные. Кому-то просто необходимо разжевать материал.

Итак, запускаем программу. Откроется диалоговое окно Embedded Workbench Startup. Выбираем пункт Create new project in current workspace (создать новый проект в текущем рабочем пространстве).

Откроется окно Create New Project. IAR предложит вам выбрать тип шаблона проекта (Project templates). Выбираем C > main.

В стандартном Save As диалоге указываем название проекта (led1) и папку, в которой хотим его сохранить.

Сохраняем workspace – File > Save Workspace

Проект создан.

Приглядимся к IARу. Верхняя строка – почти стандартный bar. Ниже – bar с кнопками. С левой стороны – рабочее пространство (workspace), в котором отображается структура нашего проекта. С правой стороны находится редактор кода. Сейчас там открыт файл main.c, но в нем ничего нет, кроме функции main().

IAR позволяет объединять несколько проектов в одном workspace. Это очень удобно для быстрой навигации между проектами. Каждый workspace может содержать один или несколько проектов, а каждый проект должен быть частью, по крайней мере, одного workspace.

Каждый проект имеет так называемые build configuration. По умолчанию их две – Debug и Release. Эти конфигурации отличаются настройками проекта. В простейшем случае это опции оптимизации, формат выходного файла. Это позволяет быстро менять настройки, не залезая в меню Project > Options… При желании можно создать свои build configurations, но сейчас нам это не понадобится. Подробнее об организации проектов в IARе.

Зададим настройки проекта для конфигурации Release.

Кликаем на название проекта и в строке меню выбираем Project > Options… Откроется диалоговое окно с множеством настроек.

Выбираем тип микроконтроллера.

General Options > Target > Processor configuration

У меня это ATmega8535.

Меняем тип выходного файла.

er > Output.

B поле Output file cтавим галочку Override default и заменяем расширение d90 на hex

В поле Format выбираем Other и в выпадающем меню Output format выбираем тип файла intel-standart

Жмем ОК.

Теперь дело за программой. Сформулируем нашу задачу: заставить микроконтроллер моргать светодиодом с частотой видимой человеческому глазу.

Схема для нашего примера.

Алгоритм программы следующий:

1. конфигурируем порт, к которому подключен светодиод, в режим выхода

2. выставляем в порту ноль – то есть, зажигаем светодиод

3. ждем

4. выставляем в порту единицу – то есть, гасим светодиод

5. ждем

6. возвращаемся на шаг номер 2

Самая простая для понимания вещь в любых языках программирования – это комментарии. Назначение комментариев – помогать разбираться в программе. Ну то есть пояснять трудные участки кода, назначение функций и тому подобное. Иногда бывает, откроешь свою старую программу и не можешь вспомнить, как она работает. А все почему? Да потому что впопыхах не написал комментариев к ней.

_____________________синтаксис комментариев_______________________

// однострочный комментарий

/* длинный

многострочный

комментарий */

_________________________________________________________________

Комментарии игнорируются компилятором и не включаются в текст конечной программы. Часто символы комментариев используются, когда нужно исключить часть кода из программы, не удаляя его при этом.

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

//первая прога на Си для AVR

В нашей программе мы будем использовать имена регистров микроконтроллера и для того чтобы компилятор их понимал, мы должны подключить к нашей программе заголовочный файл (хедер файл или просто хедер), который содержит описание адресов регистров, адресов векторов прерываний, имен битов регистров микроконтроллера ATMega8535. Это делается с помощью директивы препроцессора #include

Препроцессор это специальная часть компилятора, обрабатывающая текст программы перед началом процесса компиляции кода. Все директивы препроцессора начинаются с символа #.

_______________синтаксис директивы include__________________

#include <имя_файла.h>

#include “имя_файла.h”

Угловые скобки указывают компилятору, что подключаемые файлы нужно сначала искать в стандартной папке IARа с именем INC. Двойные кавычки ” и ” указывают компилятору начинать поиск с директории, в которой хранится проект.

________________________________________________________

Для каждого типа микроконтроллера есть свой заголовочный файл. Для ATMega8535 этот файл называется iom8535.h, для ATMega16 – iom16.h. По идее мы должны в начале каждой программы подключать заголовочный файл того микроконтроллера, который мы используем. Умные люди немного облегчили нам жизнь и написали заголовочный файл ioavr.h. Препроцессор обрабатывает этот файл и в зависимости от настроек проекта включает в нашу программу нужный заголовочный файл.

Итак, следущая строчка программы

#include <ioavr.h>

В нашей программе мы будем использовать задержку. Задержку можно реализовать программно и аппаратно. Сейчас нас интересует программная задержка. IAR содержит библиотеку, в которой уже есть готовая функция задержки. Нам нужно подключить к нашей программе эту библиотеку. Как это сделать? Каждая библиотека имеет свой заголовочный файл в котором описано какие фукции она содержит. Этот файл мы и должны включить в программу. Делается это, как вы догадались с помощью директивы #include.

Читайте также:  Комплекс витаминов при нарушении менструального цикла

#include <intrinsics.h>

Основу любой сишной программы составляют функции, и любая программа на Си имеет хотя бы одну функцию – main().Вообще-то на примере main() не хотелось бы объяснять синтаксис функций, потому что main() хоть и является функцией, но вызывается не как обычно, а автоматически. С этой функции микроконтроллер начинает выполнение написанной нами программы. Вызовы всех других функций, наших или библиотечных, должны быть записаны в коде. Как вызывается функция, мы увидим дальше.

У функции есть заголовок – int main(void) и тело – оно ограниченно фигурными скобками {}. В тело функции мы и будем добавлять наш код.

______________________пояснения к функции main() _______________________

Перед именем функции указывается тип возвращаемого значения. Если функция не возвращает значение – используется ключевое void.

int – это целое 2-ух байтное число, диапазон значений от – 32768 до 32767

После имени функции в скобках () указываются параметры, которые передаются функции при ее вызове. Если функция без параметров – используется ключевое слово void

Для того чтобы завершить выполнение функции используется ключевое слово return. Если функция возвращает значение, то оно пишется после слова return.

_____________________________________________________________________

Сейчас нам нужно настроить порт С на выход. Режим работы порта определяется содержимым регистра DDRC. Ничего кроме светодиода на данный момент к порту C не подключенно, поэтому можно весь порт конфигурировать на выход. Это делается записью в регистр DDRC числа 255 (0b11111111 – в двоичном виде. В языке Си нет поддержки двоичных чисел, но это можно обойти с помощью макроопределений. Об этом мы поговорим позже)

Дополнительную информацию по портам ввода-вывода микроконтроллеров AVR вы можете почерпнуть здесь.

Добавляем после фигурной скобки

DDRC = 255;

В языке Си знак равно = это оператор присваивания. Обратите внимание на точку с запятой, этим символом должно оканчиваться любое выражение на Си.

Теперь нам нужно выставить в порту ноль, то есть зажечь светодиод.

PORTC = 0;

Дошли до задержки. Как я говорил, мы будем использовать готовую библиотечную функцию. Она называется __delay_cycles(uned long int). Она ничего не возвращает и содержит один параметр – сколько тактов микроконтроллера должна длиться задержка. Значение этого параметра мы должны передать функции при ее вызове. Здесь мы сталкиваемся с новым типом данных.

_____________________________________________________________________

uned long int – это беззнаковое длинное целое число, его размер 4 байта, а диапазон значений от 0 до 232 -1 (4294967295 – вот такое вот здоровенное число)

_____________________________________________________________________

Мы хотим, чтобы светодиод моргал с частотой видимой нашему глазу. Это единицы, десятки герц. Допустим, мы выбрали 1 Гц. Мой микроконтроллер работает на частоте 8 МГц, длительность одного такта =1/8000000 Гц = 125 нс. Сигнал частотой 1 Гц имеет период повторения 1 c. Светодиод будет гореть только половину периода – 0,5с. Делим 0,5 с на 125 нс и получаем искомое число тактов – 4000000. Это число укладывается в диапазон типа uned long int.

Следующая строчка нашей программы – вызов функции:

__delay_cycles(4000000);

Далее – гасим светодиод и снова вызываем функцию задержки:

PORTC = 255;

__delay_cycles(4000000);

5 шаг алгоритма – вернуться на шаг 2. По сути дела нам нужно повторить кусок программы, зациклить его. Для этих целей в Си существуют три типа циклов: for, while и do. Мы используем while.

__________________синтаксис цикла while_____________________________

while(condition){

ement1;

ement2;

ement3;

}

while – имеет условие выполнения (condition), оно записано в скобках () и тело цикла, оно заключено между фигурными скобками {}. В качестве условия цикла может выступать переменная, константа, выражение или функция, возвращающая значение. Перед каждым выполнением цикла происходит проверка условия, если условие истинно, цикл выполняется, если условие ложно, цикл не выполняется. Любое ненулевое значение в скобках оператор воспримет как истину, и цикл будет выполняться.

while(1){ //этот цикл будет выполняться бесконечно

ement1;

ement2;

ement3;

}

____________________________________________________________________

Нам нужен бесконечный цикл. Помещаем наши строчки

PORTC = 0;

__delay_cycles(4000000);

PORTC = 255;

__delay_cycles(4000000);

внутрь бесконечного цикла, и вот что в итоге должно получиться:

//первая прога на Си для AVR

#include <ioavr.h>

#include <intrinsics.h>

int main(void)

{

DDRC = 255;

while(1){

PORTC = 0;

__delay_cycles(4000000);

PORTC = 255;

__delay_cycles(4000000);

}

return 0;

}

Если у вас другой результат – пройдитесь снова по тексту. Может, я что-то полохо объяснил, может, вы что-то плохо поняли.

Кликаем Make на панели с кнопками (можно нажать F7). Если все сделано правильно, IAR откомпилирует и соберет проект, а внизу откроется окно Messages, в котором будет написано:

…..

Total number of errors: 0

Total number of warnings: 1

Все прошло без ошибок, но компилер выдал warning – ement is unreachable. Ничего страшного – он просто сообщает нам, что функция main() никогда не возвратит значение. Просто у нас в программе бесконечный цикл и микроконтроллер при работе никогда не дойдет до строчки return 0.

Ищем папку проекта на жестком диске. Там, в директории Release лежит файл прошивки led.hex. Грузим в микроконтроллер… Светодиод заморгал? Отлично. А теперь легко проверить правильно ли работает наша программа. Берем механические часы и смотрим, моргает ли светодиод в такт с секундной стрелкой. У меня моргает, а у вас?

Схема для нашего примера.

Проект для IAR AVR. Первая программа на Си для AVR

Проект для WIR

Проект для CodeVision

Источник