Порядок программирования микроконтроллеров avr. Программирование на си - микроконтроллеры и технологии. Установка отдельного бита

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

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

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

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

В языке Си гармонично сочетаются возможности программирования низкого уровня со свойствами языка высокого уровня. Возможность низкоуровневого программирования позволяет легко оперировать непосредственно аппаратными средствами, а свойства языка высокого уровня позволяют создавать легко читаемый и модифицируемый программный код. Кроме того, практически все компиляторы Си имеют возможность использовать ассемблерные вставки для написания критичных по времени выполнения и занимаемым ресурсам участков программы.

Одним словом, Си - наиболее удобный язык как для начинающих знакомиться с микроконтроллерами AVR, так и для серьезных разработчиков.

Чтобы преобразовать исходный текст программы в файл прошивки микроконтроллера, применяют компиляторы.

Фирма Atmel поставляет мощный компилятор ассемблера, который входит в среду разработки Atmel Studio, работающую под Windows. Наряду с компилятором, среда разработки содержит отладчик и эмулятор.
Atmel Studio совершенно бесплатна и доступна на сайте Atmel .

В настоящее время представлено достаточно много компиляторов Си для AVR. Самым мощным из них считается компилятор фирмы IAR Systems из Стокгольма. Именно ее сотрудники в середине 90-х годов участвовали в разработке системы команд AVR. IAR C Compiler имеет широкие возможности по оптимизации кода и поставляется в составе интегрированной среды разработки IAR Embedded Workbench (EWB), включающей в себя также компилятор ассемблера, линкер, менеджер проектов и библиотек, а также отладчик. Цена полной версии пакета составляет 2820 EUR. На сайте компании можно бесплатно скачать оценочную версию на 30 дней или бессрочную с ограничением размера кода в 4 Кбайта.

Американской фирмой Image Craft из калифорнийского Пало-Альто выпускается компилятор языка Си, получивший достаточно широкую популярность. JumpStart C for AVR имеет приемлемую оптимизацию кода и не слишком высокую цену (от $50 до $499 в зависимости от версии). Демо-версия JumpStart C for AVR полностью функциональна в течение 45 дней.

Не меньшую популярность завоевал румынский Code Vision AVR C Compiler , цена полной версии этого компилятора относительно невысока и составляет 150 EUR. Компилятор поставляется вместе с интегрированной средой разработки, в которую, помимо стандартных возможностей, включена достаточно интересная функция - CodeWizardAVR Automatic Program Generator. Наличие в среде разработки последовательного терминала позволяет производить отладку программ с использованием последовательного порта микроконтроллера. У разработчиков можно скачать бесплатную оценочную версию с ограничением размера кода в 4 Кбайта и отключенным сохранением сгенерированного исходного кода на Си.

Компанией MikroElektronika , расположенной в сербском городе Белграде, выпускается целое семейство компиляторов для AVR-микроконтроллеров. Компилятор для языка Си под названием mikroC PRO for AVR стоит $249. Есть также mikroBasic и mikroPascal за ту же цену. На сайте разработчиков имеются демоверсии с ограничением размера кода в 4096 bytes. Плюсом этого семейства компиляторов является единая платформа и единая идеология, что может обеспечивать легкий переход не только между языками, но и между микроконтроллерами (есть версии компиляторов для PIC, STM32, 8051 ...).

Поистине культовой стала интегрированная среда разработки . Она включает мощные компиляторы Си и ассемблера, программатор AVRDUDE, отладчик, симулятор и множество других вспомогательных программ и утилит. WinAVR прекрасно интегрируется со средой разработки AVR Studio от Atmel. Ассемблер идентичен по входному коду ассемблеру AVR Studio. Компиляторы Си и ассемблера имеют возможность создания отладочных файлов в формате COFF, что позволяет применять не только встроенные средства, но и использовать мощный симулятор AVR Studio. Еще одним немаловажным плюсом является то, что WinAVR распространяется бесплатно без ограничений (производители поддерживают GNU General Public License).

В качестве резюме стоит сказать, что WinAVR является идеальным выбором для тех, кто начинает осваивать микроконтроллеры AVR. Именно эта среда разработки и рассматривается в качестве основной в данном курсе.

Министерство образования и науки Российской Федерации

Государственное образовательное учреждение

высшего профессионального образования

«САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ

МОРСКОЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ»

Е. В. Коротицкий, Ю. Е. Коротицкая

Основы языка си для микроконтроллеров avr

Учебное пособие

Санкт-Петербург

1. Основы языка Си для микроконтроллеров avr

Универсальный язык С был разработан как инструмент для написания операционной среды UNIX.

Язык С поддерживает процедурно-ориентированную парадигму программирования, т.е. парадигма – взаимосвязанный набор процедур.

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

    1. Препроцессор языка Cи его команды

Препроцессор (макропроцессор) - это составная часть языка Си, которая обрабатывает исходный текст программы до того, как он пройдет через компилятор. Препроцессор читает строки текста и выполняет действия, определяемые командными строками. Если первым символом в строке, отличным от пробела, является символ #, то такая строка рассматривается препроцессором как командная. Командные строки называются директивами препроцессора.

Препроцессор компилятора CodeVisionAVRимеет несколько директив. В Табл. 1 даётся их краткое описание.

Табл. 1 –Директивы препроцессора компилятора CodeVisionAVR

Директива

Назначение

Используется для включения в программу

другого файла

Используется для замены одних лексических единиц языка Си на другие, а также для генерации макросов

Используется для отмены действия директивы #define

Используются для условной компиляции

Используется для изменения встроенных макросов _LINE_и_FILE_

Позволяет остановить компиляцию и отобразить сообщение об ошибках

Используются для включения в исходную программу ассемблерного кода

Разрешает специальные директивы компилятора

ВСЕ директивы препроцессора начинаются со знака #. После директив препроцессора точка с запятой НЕ СТАВИТСЯ.

      1. Директива #include

Пример:

Директива # include

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

Имя_файла состоит из имени файла.

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

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

      1. Директивы #define, #undef

Директива # define служит для замены часто использующихся одних лексических единиц языка Си (констант, ключевых слов, операторов или выражений) на другие, так называемыеидентификаторы. Идентификаторы, заменяющие текстовые или числовые константы, называютименованными константами. Идентификаторы, заменяющие фрагменты программ, называютмакроопределениями, причём макроопределения могут иметь аргументы.

Директива # define имеет две синтаксические формы:

#define идентификатор текст

#define идентификатор (список параметров) текст

Перед компиляцией программы препроцессор в соответствии с директивой # define заменит все идентификаторы, встречающиеся в программе, на соответствующий им текст.

Пример:

#define А 15 #define В (А+20) // Эти директивы заменят в тексте программы

каждый идентификатор А на число 15, а каждый идентификатор В на выражение (15+20) вместе с окружающими его скобками.

Пример:

#define X(a,b,c) ((а)*(b)-(с)) // Препроцессор в соответствии с этой директивой заменит фрагмент Y=X(k+m,k-m,n); на фрагмент

Побитовые операции основаны на логических операциях, которые мы уже рассмотрели ранее. Они играют ключевую роль при программировании микроконтроллеров AVR и других типов. Практически ни одна программа не обходится без применения побитовых операций. До этого мы намеренно избегали их, чтобы облегчить процесс изучения программирования МК.

Во всех предыдущих статьях мы программировали только порты ввода-вывода а и не задействовали дополнительные встроенные узлы, например, такие как таймеры, аналогово-цифровые преобразователи, прерывания и другие внутренние устройства без которых МК теряет всю свою мощь.

Прежде, чем перейти к освоению встроенных устройств МК, необходимо научится управлять или проверять отдельные биты регистров МК AVR. Ранее же мы выполняли проверку или устанавливали разряды сразу всего регистра. Давайте разберемся, в чем состоит отличие, а затем продолжим далее.

Побитовые операции

Чаще всего при программировании микроконтроллеров AVR мы пользовались , поскольку она имеет большую наглядность по сравнению с и хорошо понятна для начинающих программистов МК. Например, нам нужно установить только 3-й бит порта D. Для этого, как мы уже знаем, можно воспользуемся следующим двоичным кодом:

PORTD = 0b00001000;

Однако этой командой мы устанавливаем 3-й разряд в единицу, а все остальные (0, 1, 2, 4, 5, 6 и 7-й) мы сбрасываем в ноль. А теперь давайте представим ситуацию, что 6-й и 7-й разряды задействованы как входы АЦП и в это время на соответствующие выводы МК поступает сигнал от какого-либо устройства, а мы, применяемой выше командой, обнуляем эти сигналы. В результате чего микроконтроллер их не видит и считает, что сигналы не приходили. Поэтому вместо такой команды нам следует применить другую, которая бы установила только 3-й бит в единицу, при этом не влияя на остальные биты. Для это обычно применяется следующая побитовая операция:

PORTD |= (1<<3);

Синтаксис ее мы подробно разберем далее. А сейчас еще один пример. Допустим нам нужно проверить состояние 3-го разряда регистра PIND, тем самым проверяя состояние кнопки. Если данный разряд сброшен в ноль, то мы знаем, что кнопка нажата и далее выполняется код команды, который соответствует состоянию нажатой кнопки. Ранее мы бы воспользовались следующей записью:

if (PIND == 0b00000000)

{ какой-либо код}

Однако с помощью нее мы проверяем не отдельный, – 3-й, а сразу все биты регистра PIND. Поэтому даже если кнопка нажат и нужный разряд сброшен, но в это время на какой-либо другой вывод порта D поступит сигнал, то соответствующий быт установится в единицу, и условие в круглых скобках будет ложным. В результате код, находящийся в фигурных скобках, не будет выполняться даже при нажатой кнопке. Поэтому для проверки состояния отдельного 3-го бита регистра PIND следует применять побитовую операцию:

if (~PIND & (1<<3))

{ какой-либо код}

Для работы с отдельными битами микроконтроллера в арсенале языка программирования C имеются , с помощью которых можно изменять или проверять состояние одного или нескольких отдельных бит сразу.

Установка отдельного бита

Для установки отдельного бита, например порта D, применяется побитовая операция ИЛИ. Именно ее мы применяли в начале статьи.

PORTD = 0b00011100; // начальное значение

PORTD = PORTD | (1<<0); применяем побитовую ИЛИ

PORTD |= (1<<0); // сокращенная форма записи

PORTD == 0b00011101; // результат

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

Для примера установим еще 6-й разряд порта D.

PORTD = 0b00011100; // начальное состояние порта

PORTD |= (1<<6); //

PORTD == 0b01011100; // результат

Чтобы записать единицу сразу в несколько отдельных бит, например нулевой, шестой и седьмой порта B применяется следующая запись.

PORTB = 0b00011100; // начальное значение

PORTB |= (1<<0) | (1<<6) | (1<<7); //

PORTB == 0b1011101; // результат

Сброс (обнуление) отдельных битов

Для сброса отдельного бита применяются сразу три ранее рассмотренные команды: .

Давайте сбросим 3-й разряд регистра PORTC и оставим без изменений остальные.

PORTC = 0b00011100;

PORTC &= ~(1<<3);

PORTC == 0b00010100;

Выполним подобные действия для 2-го и 4-го разрядов:

PORTC = 0b00111110;

PORTC &= ~((1<<2) | (1<<4));

PORTC == 0b00101010;

Переключение бита

Кроме установки и сброса также применяется полезная команда, которая переключает отдельный бит на противоположное состояние: единицу в ноль и наоборот. Данная логическая операция находит широкое применение при построении различных световых эффектов, например, таких как новогодняя гирлянда. Рассмотрим на примере PORTA

PORTA = 0b00011111;

PORTA ^= (1<<2);

PORTA == 0b00011011;

Изменим состояние нулевого, второго и шестого битов:

PORTA = 0b00011111;

PORTA ^= (1<<0) | (1<<2) | (1<<6);

PORTA == 0b01011010;

Проверка состояния отдельного бита. Напомню, что проверка (в отличии от записи) порта ввода-вывода осуществляется с помощью чтения данных из регистра PIN.

Наиболее часто проверка выполняется одним из двух операторов цикла: if и while. С этими операторами мы уже знакомы ранее.

Проверка разряда на наличие логического нуля (сброса) с if

if (0==(PIND & (1<<3)))

Если третий разряд порта D сброшен, то выполняется Код1. В противном случае, выполняется Код2.

Аналогичные действия выполняются при и такой форме записи:

if (~PIND & (1<<3))

Проверка разряда на наличие логической единицы (установки) с if

if (0 != (PIND & (1<<3)))

if (PIND & (1<<3))

Приведенные выше два цикла работаю аналогично, но могут, благодаря гибкости языка программирования C, иметь разную форму записи. Операция!= обозначает не равно. Если третий разряд порта ввода-вывода PD установлен (единица), то выполняется Код1, если нет ‑ Код2.

Ожидание сброса бита с while

while (PIND & (1<<5))

Код1 будет выполняться пока 5-й разряд регистра PIND установлен. При сбросе его начнет выполняться Код2.

Ожидание установки бита с while

Здесь синтаксис языка С позволяет записать код двумя наиболее распространёнными способами. На практике применяются оба типа записи.

Решил написать небольшую вводную статейку для тех, кто впервые взялся за программирование микроконтроллеров и никогда раньше не был знаком с языком Си. В подробности влезать не будем, обо всем понемногу, чтобы получить общее представление по работе с CodeVisionAVR.

Более подробную информацию можно посмотреть на английском языке в CodeVision User Manual, а также рекомендую сайт http://somecode.ru с видеоуроками по Си для микроконтроллеров и книгу «Как программировать на С» автор Дейтель, это единственная годная книга, с которой я сам начинал.

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

Сама прошивка имеет расширение.hex и представляет собой набор инструкций, в виде единиц и нулей, который понятен микроконтроллеру. Откуда взять прошивку? Ее можно скачать с сайтов по электронике, либо написать самому. Написать ее можно в специальных программах, которые называются средой разработки. Из наиболее известных мне AVR Studio, IAR, CodeVision, WinAVR… Нельзя сказать, что какая из этих сред лучше или хуже, каждому свое. Можно сказать, что различаются эти программы в основном удобством, языком программирования и ценой. В пределах данного сайта, рассматривается только CodeVision.

Со средой разобрались, теперь разберемся с процессом написания прошивки. В CodeVision изначально нужно создать проект. Его можно создать при помощи мастера кода или пустой. В любом случае, нужно выбрать тип используемого микроконтроллера и указать его частоту. При использовании мастера, вам будет предложено выбрать начальные настройки и сгенерировать исходный код с настройками. Далее появится окно, в котором можно редактировать этот код. Хотя вы можете написать свой исходный код, в блокноте и потом прицепить его к проекту в настройках.

Файл с исходным кодом является набором команд на языке программирования, задача CodeVision`а перевести эти команды в двоичный код, ваша задача написать этот исходный код. CodeVision понимает язык Си, файлы с исходным кодом имеют расширение «.c». Но у CodeVision есть некоторые конструкции, которые не используются в Си, за это его многие программисты не любят, а используемый язык называют Си подобным. Однако, это не мешает писать серьезные проекты. Множество примеров, генератор кода, большой набор библиотек дает большой плюс CodeVision`у. Единственный минус, то что он платный, хотя есть бесплатные версии с ограничением кода.

Исходный код должен содержать заголовок с используемым типом микроконтроллера и функцию main. Например, используется ATtiny13

#include void main(void ) { } ;

#include void main(void) { };

До функции main можно подключить необходимые библиотеки, объявить глобальные переменные, константы, настройки. Библиотека это отдельный файл, обычно с расширением «.h», в котором уже есть заранее написанный код. В одних проектах этот код может быть нам нужен, а в других не нужен. Например, в одном проекте мы используем жк дислей, а в другом не используем. Подключить библиотеку для работы с жк дисплеем «alcd.h», можно так:

#include #include void main(void ) { } ;

#include #include void main(void) { };

Переменные это участки памяти, в которые можно поместить некие значения. Например, сложили два числа, результат нужно, где то сохранить, чтобы использовать в дальнейшем. Сначала необходимо объявить переменную, т.е. выделить под нее память, например:
int i=0;
т.е. мы объявили переменную i и поместили в нее значение 0, int – тип переменной, или проще говоря, означает размер выделенной памяти. Каждый тип переменных может хранить только определенный диапазон значений. Например, int можно записать числа от -32768 до 32767. Если нужно использовать числа с дробной частью значит, переменную нужно объявлять как float, для символов используют тип char.

bit, _Bit 0 или 1 char от -128 до 127 unsigned char от 0 до 255 int от -32768 до 32767 unsigned int от 0 до 65535 long int от -2147483648 до 2147483647 unsigned long int от 0 до 4294967295 float от ±1.175e-38 до ±3.402e38

Внутри функции main уже выполняется основная программа. После выполнения функции программа остановится, поэтому делают бесконечный цикл while, который крутит одну и ту же программу постоянно.

void main(void ) { while (1 ) { } ; } ;

void main(void) { while (1) { }; };

В любой части исходного кода можно написать комментарий, на работу программы он влиять никак не будет, но будет помогать сделать пометки к написанному коду. Закомментировать строку можно двумя слешами //после этого компилятор будет игнорировать всю строку, либо несколько строк /**/, например:

/*Основные математические операции:*/ int i= 0 ; //объявляем переменную i и присваиваем ей значение 0 //Сложение: i = 2 + 2 ; //Вычитание: i = 2 - 2 ; //после выполнения данного выражения переменная i будет равна 0 //Умножение: i = 2 * 2 ; //после выполнения данного выражения переменная i будет равна 4 //Деление: i = 2 / 2 ; //после выполнения данного выражения переменная i будет равна 1

/*Основные математические операции:*/ int i=0; //объявляем переменную i и присваиваем ей значение 0 //Сложение: i = 2+2; //после выполнения данного выражения переменная i будет равна 4 //Вычитание: i = 2-2; //после выполнения данного выражения переменная i будет равна 0 //Умножение: i = 2*2; //после выполнения данного выражения переменная i будет равна 4 //Деление: i = 2/2; //после выполнения данного выражения переменная i будет равна 1

Зачастую в программе требуется выполнить переход от одного куска кода к другому, в зависимости от условий, для этого существует условные операции if(), например:

if(i>3) //если i больше 3, то присвоить i значение 0 { i=0; } /*если i меньше 3, то перейти к коду следующему после тела условия, т.е. после скобок {}*/

Также if можно использовать совместно с else – иначе

if(i<3) //если i меньше 3, то присвоить i значение 0 { i=0; } else { i=5; //иначе, т.е. если i больше 3, присвоить значение 5 }

Также имеется операция сравнения «==» ее нельзя путать с «=» присвоить. Обратная операция не равно «!=», допустим

if(i==3)//если i равно 3, присвоить i значение 0 { i=0; } if(i!=5) //если i не равно 5, присвоить i значение 0 { i=0; }

Перейдем к более сложным вещам – функциям. Допустим, у вас есть некий кусок кода, который повторяется несколько раз. Причем этот код довольно большой в размерах. Писать его каждый раз неудобно. Например, в программе, каким то образом изменяется переменная i, при нажатии на кнопку 0 и 3 порта D выполняется одинаковый код, который в зависимости от величины переменной i включает ножки порта B.

void main(void ) { if (PIND.0== 0 ) //проверяем нажата ли кнопка на PD0 { if (i== 0 ) //если i==0 включить PB0 { PORTB.0= 1 ; } if (i== 5 ) // если i==5 включить PB1 { PORTB.1= 1 ; } } … if (PIND.3== 0 ) // выполняем тоже самое, при проверке кнопки PD3 { if (i== 0 ) { PORTB.0= 1 ; } if (i== 5 ) { PORTB.1= 1 ; } } }

void main(void) { if(PIND.0==0) //проверяем нажата ли кнопка на PD0 { if(i==0) //если i==0 включить PB0 { PORTB.0=1; } if(i==5) // если i==5 включить PB1 { PORTB.1=1; } } … if(PIND.3==0)// выполняем тоже самое, при проверке кнопки PD3 { if(i==0) { PORTB.0=1; } if(i==5) { PORTB.1=1; } } }

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

void i_check() { if (i== 0 ) { PORTB.0= 1 ; } if (i== 5 ) { PORTB.1= 1 ; } }

void i_check() { if(i==0) { PORTB.0=1; } if(i==5) { PORTB.1=1; } }

void означает что функция ничего не возвращает, об этом чуть ниже i_check() – это название нашей функции, можете назвать как угодно, я назвал именно так – проверка i. Теперь мы можем переписать наш код:

void i_check() { if(i==0) { PORTB.0=1; } if(i==5) { PORTB.1=1; } } void main(void) { if(PIND.0==0) //проверяем нажата ли кнопка на PD0 { i_check(); } … if(PIND.3==0) { i_check(); } }

Когда код будет доходить до строчки i_check(); то он перепрыгнет внутрь функции и выполнит код внутри. Согласитесь, код компактнее и нагляднее, т.е. функции помогают заменить одинаковый код, всего на одну строчку. Обратите внимание, что функция объявляется вне основного кода, т.е. до функции main. Можно сказать, да зачем мне это надо, но изучая уроки вам часто будут попадаться функции, например очистка жк экрана lcd_clear() — функция не принимает никаких параметров и ничего не возвращает, однако очищает экран. Иногда эта функция используется чуть ли не через строчку, так что экономия кода очевидна.

Намного интереснее выглядит применение функции, когда она принимает значения, например, есть переменная c и есть функция sum, которая принимает два значения типа int. Когда основная программа будет выполнять эту функцию, то в скобках уже указаны аргументы, таким образом «a» станет равной двум, а «b» станет равной 1. Функция выполнится и «с» станет равна 3.

int c= 0 ; void sum(int a, int b) { c= a+ b; } void main(void ) { sum(2 , 1 ) ; }

int c=0; void sum(int a, int b) { c=a+b; } void main(void) { sum(2,1); }

Одна из часто встречаемых подобных функций это перевод курсора у жк дисплея lcd_gotoxy(0,0); которая, кстати, тоже принимает аргументы – координаты по х и у.

Еще один вариант использования функции, когда она возвращает значение, теперь она уже не будет void, усовершенствуем предыдущий пример функции сложения двух чисел:

int c= 0 ; int sum(int a, int b) { return a+ b; } void main(void ) { с= sum(2 , 1 ) ; }

int c=0; int sum(int a, int b) { return a+b; } void main(void) { с=sum(2,1); }

Результат будет такой же как и в прошлый раз c=3, однако обратите внимание, мы переменной «с» присваиваем значение функции, которая уже не void, а возвращает сумму двух чисел типа int. Таким образом мы не привязываемся к конкретной переменной «с», что добавляет гибкости в использовании функций. Простой пример подобной функции — чтение данных АЦП, функция возвращает измеренное значение result=read_adc();. На этом закончим с функциями.

Теперь перейдем к массивам. Массив это связанные переменные. Например, у вас есть таблица синуса с несколькими точками, не будете же вы создавать переменные int sinus1=0; int sinus2=1; и т.д. для этого используют массив. Например, создать массив из трех элементов можно так:
int sinus={0,1,5};
в квадратных скобках указывается общее количество элементов массива. Присвоить переменной «с» значение третьего элемента можно таким образом:
с=sinus;
Обратите внимание, нумерация элементов массива начинается с нуля, т.е. «с» станет равна пяти. У данного массива элемента sinus не существует!!!
Отдельному элементу можно присвоить значение так:
sinus=10;

Возможно, вы уже успели заметить, что в CodeVision нет строковых переменных. Т.е. нельзя создать переменную string hello=”привет”; для этого придется создавать массив из отдельных символов.

lcd_putchar(hello); lcd_putchar(hello); lcd_putchar(hello);

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

while(PINB.0!=0) { }

Пока кнопка не нажата ничего не делать – гонять пустой цикл.

Еще один вариант цикл for

int i; for (i= 0 ; i< 6 ; i++ ) { lcd_putchar(hello[ i] ) ; }

int i; for(i=0;i<6;i++) { lcd_putchar(hello[i]); }

Смысл точно такой же, как и у while только добавлено начальное условие i=0 и условие, выполняемое каждый цикл i++. Код внутри цикла максимально упрощен.

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

Не стоит сразу стараться использовать циклы, массивы и функции в своих прошивках. Ваша главная задача заставить прошивку работать, поэтому делайте так как вам проще не обращайте внимание на размер кода. Придет время когда захочется не просто писать рабочий код, а написать его красиво и компактно. Тогда можно будет углубиться в дебри языка Си. Желающим овладеть всем и сразу еще раз рекомендую книгу «Как программировать на Си», там много примеров и задач. Ставьте Visual Studio, создавайте консольное приложение win32 и там вволю тренируйтесь.

Урок 0.

Итак, сегодня мы открываем цикл уроков программирования микроконтроллеров семейства AVR.

Сегодня будут рассмотрены следующие вопросы:

  1. Что такое микроконтроллер?
  2. Где применяются микроконтроллеры?

Вступление.

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

Так что же такое, микроконтроллер?

Микроконтроллер (Micro Controller Unit, MCU ) - микросхема, предназначенная для управления электронными устройствами.Можно представить его в виде простейшего компьютера, способного взаимодействовать с внешними устройствами.Например, открывать и закрывать транзисторы, получать данные с датчиков температуры, выводить данные на lcd экраны и т. д. . К тому же, микроконтроллер может производить различную обработку входных данных, как и Ваш персональный компьютер.

То есть, микроконтроллеры открывают нам практически безграничные возможности управления какими либо устройствами, благодаря наличию портов I/0(портов ввода(input)/вывода(output)), а так же возможности их программирования.

Где используются микроконтроллеры?

  1. Бытовая техника(Стиральные машины, микроволновые печи и.т.д.).
  2. Мобильная техника(Роботы, робототехнические системы, средства связи и др.).
  3. Промышленное оборудование(Системы управления станками).
  4. Вычислительная техника(Материнские платы,системы управления периферийными устройствами).
  5. Развлекательная техника(Детские игрушки, украшения).
  6. Транспорт(Системы управления двигателем автомобиля, системы безопасности)

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

Начало знакомства с AVR

AVR — семейство микроконтроллеров фирмы Atmel.Обладают достаточной производительностью для большинства любительских устройств. Так же находят широкое применение в промышленности.

Похожие публикации