Язык_си_для_микроконтроллеров_avr

Язык_си_для_микроконтроллеров_avr

AVR на C — просто?

Введение

Материалы приведенные далее рассчитаны на пользователей знакомых с программированием в целом и языком C (не обязательно) в частности.
В основном излагаемый материал описывает использование микроконтроллеров AVR, особое внимание на ATmega328. Для изучения материалов понадобится Arduino Uno или Arduino Nano 3. Да простят меня ардуино-ненавистники, но в данном случае Arduino буд е т использоваться в качестве макетных плат по доступной цене и с возможность использования без программатора .

1. Подготовка к изучению

Для изучения нам понадобятся:

Стандартные библиотеки C для микроконтроллеров AVR ;

Программа для загрузки микропрограмм в микроконтроллер;

1.1. Среда разработки

При выборе среды разработки можно натолкнутся на «не пробиваемую стену» множества программных оболочек для программирования на разных языках программирования. Но учитывая направление на микроконтроллеры круг поиска сужается до сред разработки адаптированных под конкретный вид микроконтроллеров семейства AVR фирмы Atmel. Кроме того среда разработки язык программирования C.

Из множества вариантов рассмотрим среду разработки С odeBlocks. Будем использовать оригинальную версию С odeBlocks с сайта разработчиков www.codeblocks.org последней версии, на момент написания это версия 16.01. Данная среда разработки интересна наличием версий под популярные операционные системы Linux, Windows и Mac OS.

Вкратце рассмотрим установку под Windows. Скачав файл codeblocks-16.01-setup.exe запускаем его.

Ознакомимся с лицензией и принимаем ее.

Устанавливаем все компоненты без изменений

Путь установки оставляем без изменений.

Пробегают строки установки и появляется предложение запустить программу, соглашаемся. И конечно нажимаем Next в установщике и завершаем установку.

Получаем установленную среду разработки Code::Blocks.

1.2. Стандартные библиотеки C/ C++ для микроконтроллеров AVR

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

Понадобится Atmel AVR 8-bit Toolchain так как использовать собираемся ATmega328 а он 8- bit. После скачивания запускаем полученный само распаковываемый архив и получаем папку (вида avr8-gnu-toolchain) со всем необходимым. Куда ее положить?

Запускаем ранее установленный Code::Blocks идем в меню Settings >> Compiler переходим во вкладку Toolchain executables выбираем интересующий нас компилятор из списка Selected compiler это будет GNU GCC Compiler for AVR. Далее смотрим путь по умолчанию для размещения ранее скачанной и распакованной папки.

Переименовываем нашу папку как в настройках Code::Blocks и перемещаем по указанному пути.

1.3. Программа для загрузки микропрограмм в микроконтроллер

Теперь все готово для программирования, но не хватает программы для облегчения прошивки микроконтроллера. Для изучения микроконтроллера ATmega328 будем использовать платформу Arduino UNO или Arduino Nano v3. Это дает возможность изучать микроконтроллер без паяльника и программатора. Для Arduino есть хорошая программа ArduinoBuilder и оболочка из проекта CodeBlocks Arduino IDE ( среда разработки Code::Blocks с добавлением библиотек ардуино ). Использовать микроконтроллер без ардуино гораздо интересней поэтому скачиваем только ArduinoBuilder. Его будем использовать для экспериментов с микроконтроллером на плате Arduino. Распаковываем архив, например в корень диска c: в папку ну скажем ArduinoBuilder, из нее делаем ссылку на рабочий стол и получаем два ярлыка:

Все программное обеспечение готово. Приступим к «железным» вопросам

1.4. Микроконтроллер

В своих изысканиях будем рассматривать микроконтроллер ATmega328 программы будем писать именно для него. «Знатоки» сразу нас пошлют к DataSheet но это не для нас. Мы пойдем своим путем и будем изучать его анатомию практически — методом «Тыка» : ).

Первое что необходимо, это приобрести минимальное оборудование. Ограничимся для начала покупкой ардуины или аналога. Главное, чтобы на ней был установлен микроконтроллер ATmega328.

Arduino Pro (на ATmega328 );

и конечно клоны от китайских товарищей.

Любой из перечисленных вариантов подойдет с теми или иными ограничениями или изменениями.

Рассмотрим подробнее вариант Arduino Nano v3 . Здесь установлен микроконтроллер ATmega328P, есть возможность подключать через USB, а также существует несколько клонов по приемлемой цене. Описания в интернете можно найти массу, поэтому рассмотрим только схематичное описание найденное на просторах интернет.

На схеме темно-серым выделены соответствия физическим выводам микроконтроллера, на них и будем опираться при программировании.

Краткая справка по языку Си (для микроконтроллеров)

Язык Си (без ++) — один из основных языков для программирования микроконтроллеров, поскольку здесь требуется высокая скорость, а оперативной памяти не бывает много.

Пример простой программы на Си для микроконтроллера AVR

Это текст программы компиляторов типа AvrStudio, CodeVisionAVR и т.п.

Функция main — это точка входа в программу, с которой компьютер начинает выполнение программы.

Допускается из main возвращать void, хотя это не по стандарту, так что лучше int.

В функцию main можно передавать аргументы командной строки:

Вообще говоря, мы можем писать программу для MK AVR также на языке Processing/Wiring. Это тот же Си, но упрощенный. Но компилироваться это будет только в Arduino IDE или т.п., а потом можно загружать полученный hex в наш микроконтроллер. При этом не обязательно, чтобы МК стоял на плате Arduino. Разницы то нет.

Вот так выглядит аналогичная программа на Processing/Wiring:

Здесь не надо подключать хеддеры для МК, т.к. они подключатся автоматом. Но для внешних модулей могут понадобится. Короче, про Ардуино подробнее читайте здесь

а пока мы вернемся к языку Си.

Общая структура памяти программы на Си

— куча — для динамического выделения памяти

Читайте также:  Как_правильно_посадить_саженец_вишни_осенью

— стек — локальные переменные класса памяти auto (включая аргументы функций)

— CODE — исполняемый код, инструкции процессора

Типы данных в Си

-Базовые типы данных: char, int, float, double.

-Модификаторы знака: signed, unsigned.

-Модификаторы знака: long, short.

void — тип без значения

При этом следущие типы равны:

В Си логический тип реализован неявно (с помощью int): false = нуль, true = не нуль.

Введение псевдонимов для ранее описанных типов данных:

typedef тип имя

где тип — любой существующий тип данных, имя — новое имя для этого типа.

Пример: typedef unsigned char byte;

Преобразование типов:

Если операнды операции имеют разные типы, то происходит неявное приведение типов:

(чтобы здесь получить 0.4 нужно было бы написать x=2.0/5 или 2/5.0)

Явное приведение типов:

Принудительное преобразование типов:

(желательно вообще избегать преобразования типов)

Переменные и константы

Переменная представляет собой блок памяти, на который мы ссылаемся по её имени (идентификатору).

Декларация переменных (вместе с инициализацией):

[класс памяти] [квалификаторы] [модификаторы] тип идентификатор = инициатор;

Здесь ";" — составляющая часть конструкции, завершающая часть.

Допустима (хотя и редко используется) запись: const x = 100; (по умолчанию int).

Квалификаторы (или "модификаторы доступа"): const, volatile.

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

volatile — содержимое переменной может измениться само собой (используется в многопоточных программах при взаимодействии процессов)

Возможен вариант const volatile, когда писать могут только снаружи.

Спецификторы хранения (описатель класса памяти): auto, register, extern, static.

auto — локальные переменных (по умолчанию) — программный стек.

register — просьба компилятору положить переменную в регистр ЦПУ (но он эту просьбу редко выполняет);

extern — объявление (declaration) переменных, но не определение (definition) (определение где-то в другом месте); определение может идти ниже по файлу (но как глобальная) или в другом файле.

static — статические локальные переменные, которые хранят своё значение между вызовами функций (они предпочтильнее, чем глобальные переменные). Статические глобальные переменные видны только в пределах данного файла.

Внешние и статические объекты существуют и сохраняют свои значения на протяжении всего времени выполнения программы.

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

Описание области действия идентификаторов (имен):

— внутреннее (локальное) — внутри блока

— внешнее (глобальное) — вне всех блоков

Идентификатор, описанный внутри блока, известен только в этом блоке (локальный идентификатор).

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

Стоит избегать использования глобальных имен.

Переменные с классом памяти static видны только в пределах текущего блока (для локальных) или в пределах файла (для объявленных глобально).

Статические переменные хранятся в сегменте данных (data) и по умолчанию инициализируются нулем. Т.е. память под static-переменные выделяется при старте программы и существует до конца программы.

Замечание: Инициализация выполняется одни раз при выделении памяти!

Статическими могут быть также функции. Такая ф-ция может исп-ся только внутри данного файла.

Следует различать присваивание и инициализацию:

— Присваивание: имя_переменной = выражение;

— Многочисленное присваивание: x = y = z = 0;

— Инициализация переменных: тип имя_переменной = константа;

Константы

Константы являются частью машинных команд и под них память не выделяется.

10-я система: 127; -127; +127;

8-я система: 0127; (начинается с нуля — значит 8-ричная!)

16-я система: 0x7F; (x или X, f или F — регистр не влияет)

— вещественные: 3.14; 2. ; .25 (0 можно опускать); 2E3; 2e3; 2E-3; 2.0E+3;

— символьные: 8-битные ASCII: ‘A’, ‘=’, ‘
‘, ‘ ‘, ‘370’, ‘xF8’ (символ градуса);

— строковые литералы (в двойных кавычках): "Hello, world!
". Строки заканчиваются нулевым байтом — ‘’.

Операции и операторы

Оператор (инструкция, англ. statement) — это единица выполнения программы.

В языке Си любое выражение, заканчивающееся символом "точка с запятой" (;), является оператором.

Фигурные скобки — это составной оператор.

Кроме того является отдельным блоком и в нем можно определять локальные переменные.

Операции:

— Инкрименты и декрименты: ++a, —a, a++, a— (могут выполняться быстрее)

— Операторы сравнения (отн-ний): > >=

— Логические операторы: && || ! (возвращают 1 или 0)

— Оператор ?: x ? y : z, напр.: r = 10>9 ? 100 : 200

sizeof — унарный оператор для вычисления размера переменной или типа

, — оператор запятая (последовательное вычисление): a = (b=3, b+2);

Порядок выполнения операторов:

— Унарные операторы выполняются справа-налево.

— Бинарные выполняются слева-направо.

— Присваивание выполняется справа-налево.

Порядок можно менять с помощью скобок!

Выражение а + b + c интерпретируется как (а + b) + с.

sizeof() — возвращает длину в байтах переменной или типа; sizeof(int); sizeof(a);

sizeof выражение; — само выражение не вычисляется.

Оператор запятая:

левая сторона оператора вычисляется как void и не выдаёт значения, переменной x присвается значение выражения в правой стороне, т.е. y+1.

Указатели и ссылки в Си

* — доступ к значению объекта по указанному адресу;

Указатели:

Указатель — такая переменная, которая хранить адрес некоторого объекта и связана с типом этого объекта.

класс_памяти квалификатор тип * квалификатор идентификатор = инициатор;

Основные операции над указателями:

p = q; — копирование адреса. Обычно одно типа. Если разного типа, то это не безопасно!

Читайте также:  Сварка_из_аккумуляторов_видео

Указатель p может ссылаться на тип void (используется в C для обобщенных алгоритмов).

p = NULL; — нулевой указатель — это признак отсутствия значения у указателя. Такой указатель нельзя использовать для доступа к памяти, т. к. это приведет к сбою программы во время выполнения.

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

Унарные операции * и ++ имеют одинаковый приоритет и выполняются справа налево, т. е.

Примеры на Си для микроконтроллеров Atmel AVR

Здесь представлены примеры различных программ на языке Си для микроконтроллеров Atmel AVR. Все примеры написаны под микроконтроллер ATmega16, поэтому при переносе на другие МК семейства AVR это нужно учитывать. Тактовая частота микроконтроллера во всех примерах 8 МГц (используется тактирование от внутреннего генератора). Код примеров разбит на блоки и снабжен комментариями. Проекты написаны в среде Eclipse (инструкция по установке и настройке Eclipse для AVR) и легко могут быть импортированы в Eclipse. Также можно использовать данные проекты и в среде AVR studio (изменится только структура файлов проекта). При обнаружении ошибок просьба сообщить на почту.

Blink – Самый простой пример. К порту C подключены 8 светодиодов. Светодиоды зажигаются логической единицей на линии порта. В цикле светодиоды порта включаются и выключаются. Свеобразный аналог Hello World в мире встраиваемых систем.

IO Ports – В данном примере рассматривается работа с портами ввода-вывода. К порту C подключены 8 светодиодов (линии 0-7). К линии 2 порта D подключена кнопка, с подтяжкой на землю. При нажатии кнопка выдает на линию 0 порта С уровень логической единицы. Цикл программы организован следующим образом: при запуске включается бегущий огонь, сначала загорается светодиод на линии 0 порта C, затем на линии 1 и т.д. По достижении линии 7 направление бегущего огня меняется (от 7 к 0). При нажатии на кнопку бегущий огонь останавливается и загораются одновременно все светодиоды. После повторного нажатия на кнопку бегущий огонь продолжает перемещаться с места остановки.

Dynamic Indication – В данном примере рассматривается работа с 7-сегментным индикатором. В моём случае он имеет 4 разряда (цифры). Поскольку у меня на плате установлены транзисторы для управления разрядами, то управление осуществляется выводом логической единицы и на разряды и на сегменты. Схема подключения следующая: к линиям 0-7 порта C подключены сегменты индикатора, а к линиям 0-3 порта В разряды индикатора. При запуске на индикатор выводятся цифры 1 2 3 4.

UART – В данном примере рассматривается периферийного модуля UART (универсальный асинхронный приёмопередатчик). Модуль UART можно настроить как на работу с прерываниями, так и без них (вручную, путём работы с флагами). Пример работает следующим образом: при получении байта, МК переходит в обработчик прерывания (используется только прерывание по приёму данных) и разбирает численное значение байта (0-255) на цифры, которые и выводятся на 7-сегментный индикатор. Схема подключения аналогична предыдущему примеру. Передача осуществляется по двум линиям UART (порт D линии 0-1), к которым необходимо подключить линии RX и TX преобразователя USB-UART. Для настройкки без прерываний необходимо обнулить бит RXCIE в регистре UCSRB и вручную опрашивать интерфейс в основном цикле программы.

Clock – В данном примере рассматривается реализация простых часов с 7-сегментным индикатором и парой кнопок. Только здесь уже требуется 6 разрядов, хотя секунды можно опустить. Кнопки с подтяжкой на землю. При нажатии кнопка выдает на линию высокий логический уровень. Индикатор подключается как и в предыдущих примерах (сегменты к порту C, разряды к порту B), а кнопки к линиям 2-3 порта D. Кнопка используется PD2 для установки минут, а PD3 для установки часов. По нажатию каждой из кнопок увеличивается значение соответствующего разряда (минуты или часы).

DS18B20 – В данном примере рассматривается работа с цифровым датчиком температуры DS18B20. Показания температуры выводятся на 7-сегментный индикатор. Вывод DQ датчика поключен к ноге (пину) PD5. Линия должна быть подтянута к плюсу питания резистором на 4.7-10 кОм (согласно документации). Датчик опрашивается каждые 5 секунд. Температура выводится на 4-разрядный индикатор: знак, два разряда на целуюю часть и один на вещественную. Документация к датчику здесь.

DHT11 – В данном примере рассматривается работа с датчиком температуры и влажности DHT11. Показания температуры выводятся на 7-сегментный индикатор. Вывод DATA (также SDA) датчика поключен к ноге (пину) PD5. Линия должна быть подтянута к плюсу питания резистором на 4.7-10 кОм (согласно документации). Датчик опрашивается каждые 5 секунд. Измеряются температура и влажность, но на дисплей выводится только влажность (целое двухзначное число). Документация к датчику здесь.

DHT22 – В данном примере рассматривается работа с датчиком температуры и влажности DHT22. По сравнению с DHT11 данный датчик обладает большей точностью и более широким диапазоном измерений. Показания температуры выводятся на 7-сегментный индикатор. Вывод DATA (также SDA) датчика поключен к ноге (пину) PD5. Линия должна быть подтянута к плюсу питания резистором на 4.7-10 кОм (хотя согласно документации это и необязательно). Датчик опрашивается каждые 5 секунд. Измеряются температура и влажность, но на дисплей выводится только влажность (вещественное двухзначное число с одним знаком после запятой). Документация к датчику здесь.

BMP180 – В данном примере рассматривается работа с цифровым датчиком температуры и атмосферного давления BMP180. Показания атмосферного давления выводятся на 7-сегментный индикатор. Датчик подключаетсяпо интерфейсу I2C. Линии SDA и SCL должны быть подтянуты к плюсу питания резисторами на 4.7-10 кОм. Датчик опрашивается каждые 10 секунд. Измеряются температура и давление, но на дисплей выводится только атмосферное давление в мм. ртутного столба (целое число). Документация к датчику здесь.

Читайте также:  Эффективная_приманка_для_мышей

BH1750 – В данном примере рассматривается работа с цифровым датчиком освещенности BH1750. Показания освещенности выводятся на 7-сегментный индикатор. Датчик подключается по интерфейсу I2C. Линии SDA и SCL должны быть подтянуты к плюсу питания резисторами на 4.7-10 кОм. Датчик опрашивается каждые 5 секунд. Документация к датчику здесь.

ADC Indication – Данный пример аналогичен примеру с UART. Отличие в том, что байт берется с линии 0 порта А (линия 0 АЦП, ADC0). Микроконтроллер по таймеру производит аналого-цифровое преобразование напряжения на линии 0 порта А, (младшие 2 бита отбрасываются как шум). При измерении используется внутренняя опора 5 В. К линии PD2 порта D подключена кнопка, которая определяет режим вывода показаний. При нажатии на кнопку выводится результат измерений в виде числа от 0 до 255. Если кнопка не нажата, то результат измерений переводится в вольты и выводится на индикатор (с точностью до десятых).

Fast PWM – В данном примере показана настройка аппаратного ШИМ (широтно-импульсная модуляция, англ. PWM). К линиям 4 и 5 порта D подключены светодиоды, а к линиям 2-3 и 6-7 порта D – кнопки каналов A и B соответственно. Кнопки с подтяжкой на землю (при нажатии кнопка выдает на линию порта уровень логической единицы) Кнопки на линях 2 и 3 соответственно увеличивают и уменьшают коэффициент заполнения ШИМ (меняется яркость светодиода) канала А. Кнопки на линях 6 и 7 соответственно увеличивают и уменьшают коэффициент заполнения ШИМ канала B. Число сравнения для каждого из каналов меняется в диапазоне от 0 до 255. Для канала А шаг изменения равен 10, для канала В шаг равен 5.

HCSR04 – В данном примере рассматривается работа с ультразвуковым датчиком расстояния HCSR04. К линии PD3 подключен вывод Trigger датчика, а к линии PD2 вывод Echo. Поключение 7-сегментного индикатора аналогично предыдущим примерам. МК периодически опрашивает датчик и определяет расстояние до препятсвия в сантиметрах. После этого число разбивается на цифры и выводится на дисплей. Документация к датчику здесь.

Matrix Keyboard – В данном примере показана работа с матричной клавиатурой. Микроконтроллер динамически опрашивает клавиатуру, а затем определяет номер нажатой клавиатуры. Размер поля 3 на 3 – получаем 9 кнопок. Нажатие первых 8-ми приводит к зажиганию светодиода на соответствующей линии порта А, нажатие 9-ой кнопки зажигает все светодиоды порта А. Матричная клавиатура подключается к линиям 0-5 порта С (три столбца и три строки). В архиве схема и печатная плата матричной клавиатуры (Diptrace).

Shift Register – В данном примере рассматривается работа с модулем SPI на примере сдвигового регистра 74HC595. К регистру подключены светодиоды, в качестве линии CS используется линия 4 порта B (вывод not SS). Линия DS (14 нога) регистра идет к MOSI (PB5), линия SHCP (11 нога) к линии SCK (PB7), линия STCP (12 нога) к линии SS (PB4). Линии MR (10 нога) и OE (13 нога) должны быть подтянуты к высокому и низкому логическим уровням соответственно. По таймеру микроконтроллер меняет состояние светодиодов: поочерёдно горят то чётные светодиоды, то нечётные. Если при этом передать байт по UART’у, то он будет выведен в порт на светодиоды. Чтобы обратно переключиться в режим мигания необходимо послать по UART’у 0x00 (ноль). Документация к микросхеме 74HC595 здесь.

SG-90 Servo – В данном примере рассматривается работа с сервоприводом SG-90. Используется аппаратный ШИМ. Линия ШИМ сервпопривода подключена к каналу А аппаратного ШИМ. Кнопки поворота подключены к линиям PD2 и PD3. Кнопка на линии PD2 увеличивает длительность импульса, кнопка на линии PD3 уменьшает длительность импульса. Длительность импульса меняется от 1 до 2 мс. Описание сервомотора здесь.

RGB Lamp – В данном примере рассматривается работа с трехцветным RGB-светодиодом. Реализовано плавное переливание цветов с использованием программного ШИМ. Линии красного, зеленого и синего цветов подключаются соответственно к линиям 2, 3 и 4 порта D.

TSOP4836 NEC – В данном примере рассматривается работа с фотоприемником TSOP4836 и протоколом передачи NEC, который широко используется в инфракрасных пультах дистанционного управления. При получении команды на дисплей выводится ее код. Поключение 7-сегментного индикатора аналогично предыдущим примерам. Описание фотоприемника здесь.

WS2812 Ring – В данном примере рассматривается работа со светодиодами WS2812 с встроенным ШИМ-контроллером. К контроллеру подключено такое кольцо из 16 светодиодов (количество светодиодов в кольце можно указать в коде). Библиотека для работы с WS2812 не моя (взята на гитхабе и немного допилена, копирайт сохранён). В программе сначала задается массив цветов (красный, зеленый, синий), а затем в цикле реализуется их сдвиг и плавным изменением интенсивности. Линия IN первого светодиода подключается к линии PD2 порта D. Описание светодиодов здесь.

MFRC522 RFID – В данном примере рассматривается работа со считывателем RFID карточек MFRC522. Cчитыватель подключён к контроллеру по стандартной схеме. Библиотека для работы с MFRC522 не моя (взята на гитхабе и немного допилена, копирайт сохранён). При запуске контроллер определяет тип ридера и отправляет данные в UART. Затем идет непрерывная проверка обнаружения RFID устройств. При поднесении карточки или брелка считывается его адрес и отправляется в UART (адрес 32 бита, 4 байта). Описание считывателя здесь.

Ссылка на основную публикацию
Яблочное_пюре_на_терке_на_зиму