Вы еще не программируете микроконтроллеры? Тогда мы идем к вам!
Здравствуйте, уважаемые Хабражители!
В этой статье я хочу рассказать о том, как однажды решил начать программировать микроконтроллеры, что для этого понадобилось и что в итоге получилось.
Тема микроконтроллеров меня заинтересовала очень давно, году этак в 2001. Но тогда достать программатор по месту жительства оказалось проблематично, а о покупке через Интернет и речи не было. Пришлось отложить это дело до лучших времен. И вот, в один прекрасный день я обнаружил, что лучшие времена пришли не выходя из дома можно купить все, что мне было нужно. Решил попробовать. Итак, что нам понадобится:
1. Программатор
На рынке предлагается много вариантов — от самых дешевых ISP (In-System Programming) программаторов за несколько долларов, до мощных программаторов-отладчиков за пару сотен. Не имея большого опыта в этом деле, для начала я решил попробовать один из самых простых и дешевых — USBasp. Купил в свое время на eBay за $12, сейчас можно найти даже за $3-4. На самом деле это китайская версия программатора от Thomas Fischl. Что могу сказать про него? Только одно — он работает. К тому же поддерживает достаточно много AVR контроллеров серий ATmega и ATtiny. Под Linux не требует драйвера.
Для прошивки надо соединить выходы программатора VCC, GND, RESET, SCK, MOSI, MISO с соответствующими выходами микроконтроллера. Для простоты я собрал вспомогательную схему прямо на макетной плате:
Слева на плате — тот самый микроконтроллер, который мы собираемся прошивать.
2. Микроконтроллер
С выбором микроконтроллера я особо не заморачивался и взял ATmega8 от Atmel — 23 пина ввода/вывода, два 8-битных таймера, один 16-битный, частота — до 16 Мгц, маленькое потребление (1-3.6 мА), дешевый ($2). В общем, для начала — более чем достаточно.
Под Linux для компиляции и загрузки прошивки на контроллер отлично работает связка avr-gcc + avrdude. Установка тривиальная. Следуя инструкции, можно за несколько минут установить все необходимое ПО. Единственный ньюанс, на который следует обратить внимание — avrdude (ПО для записи на контроллер) может потребовать права супер-пользователя для доступа к программатору. Выход — запустить через sudo (не очень хорошая идея), либо прописать специальные udev права. Синтаксис может отличаться в разных версиях ОС, но в моем случае (Linux Mint 15) сработало добавление следующего правила в файл /etc/udev/rules.d/41-atmega.rules :
После этого, естественно, необходим перезапуск сервиса
Компилировать и прошивать без проблем можно прямо из командной строки (кто бы сомневался), но если проектов много, то удобнее поставить плагин AVR Eclipse и делать все прямо из среды Eclipse.
Под Windows придется поставить драйвер. В остальном проблем нет. Ради научного интереса попробовал связку AVR Studio + eXtreme Burner в Windows. Опять-таки, все работает на ура.
Начинаем программировать
Программировать AVR контроллеры можно как на ассемблере (AVR assembler), так и на Си. Тут, думаю, каждый должен сделать свой выбор сам в зависимости от конкретной задачи и своих предпочтений. Лично я в первую очередь начал ковырять ассемблер. При программировании на ассемблере архитектура устройства становится понятнее и появляется ощущение, что копаешься непосредственно во внутренностях контроллера. К тому же полагаю, что в особенно критических по размеру и производительности программах знание ассемблера может очень пригодиться. После ознакомления с AVR ассемблером я переполз на Си.
После знакомства с архитектурой и основными принципами, решил собрать что-то полезное и интересное. Тут мне помогла дочурка, она занимается шахматами и в один прекрасный вечер заявила, что хочет иметь часы-таймер для партий на время. БАЦ! Вот она — идея первого проекта! Можно было конечно заказать их на том же eBay, но захотелось сделать свои собственные часы, с блэк… эээ… с индикаторами и кнопочками. Сказано — сделано!
В качестве дисплея решено было использовать два 7-сегментных диодных индикатора. Для управления достаточно было 5 кнопок — “Игрок 1” , “Игрок 2” , “Сброс” , “Настройка” и “Пауза” . Ну и не забываем про звуковую индикацию окончания игры. Вроде все. На рисунке ниже представлена общая схема подключения микроконтроллера к индикаторам и кнопкам. Она понадобится нам при разборе исходного кода программы:
Разбор полета
Начнем, как и положено, с точки входа программы — функции main . На самом деле ничего примечательного в ней нет — настройка портов, инициализация данных и бесконечный цикл обработки нажатий кнопок. Ну и вызов sei() — разрешение обработки прерываний, о них немного позже.
Рассмотрим каждую функцию в отдельности.
Настройка портов ввода/вывода происходит очень просто — в регистр DDRx (где x — буква, обозначающая порт) записивается число, каждый бит которого означает, будет ли соответствующий пин устройством ввода (соответствует 0) либо вывода (соответствует 1). Таким образом, заслав в DDRB и DDRD число 0xFF, мы сделали B и D портами вывода. Соответственно, команда DDRC = 0b11100000; превращает первые 5 пинов порта C во входные пины, а оставшиеся — в выходные. Команда PORTC |= 0b00011111; включает внутренние подтягивающие резисторы на 5 входах контроллера. Согласно схеме, к этим входам подключены кнопки, которые при нажатии замкнут их на землю. Таким образом контроллер понимает, что кнопка нажата.
Далее следует настройка двух таймеров, Timer0 и Timer1. Первый мы используем для обновления индикаторов, а второй — для обратного отсчета времени, предварительно настроив его на срабатывание каждую секунду. Подробное описание всех констант и метода настройки таймера на определенноый интервал можно найти в документации к ATmega8.
Обработка прерываний
При срабатывании таймера управление передается соответствующему обработчику прерывания. В нашем случае это обработчик TIMER0_OVF_vect, который вызывает процедуру вывода времени на индикаторы, и TIMER1_COMPA_vect, который обрабатывает обратный отсчет.
Вывод на индикаторы
Функция display использует метод динамической индикации. Дело в том, что каждый отдельно взятый индикатор имеет 9 контактов (7 для управления сегментами, 1 для точки и 1 для питания). Для управления 4 цифрами понадобилось бы 36 контактов. Слишком расточительно. Поэтому вывод разрядов на индикатор с несколькими цифрами организован по следующему принципу:
Напряжение поочередно подается на каждый из общих контактов, что позволяет высветить на соответствующем индикаторе нужную цифру при помощи одних и тех же 8 управляющих контактов. При достаточно высокой частоте вывода это выглядит для глаза как статическая картинка. Именно поэтому все 8 питающих контактов обоих индикаторов на схеме подключены к 8 выходам порта D, а 16 управляющих сегментами контактов соединены попарно и подключены к 8 выходам порта B. Таким образом, функция display с задержкой в 0.25 мс попеременно выводит нужную цифру на каждый из индикаторов. Под конец отключаются все выходы, подающие напряжение на индикаторы (команда PORTD = 0; ). Если этого не сделать, то последняя выводимая цифра будет продолжать гореть до следующего вызова функции display, что приведет к ее более яркому свечению по сравнению с остальными.
Обработка нажатий
Эта функция по очереди опрашивает все 5 кнопок и обрабатывает нажатие, если таковое случилось. Нажатие регистрируется проверкой bit_is_clear(BUTTON_PIN, bit) , т.е. кнопка нажата в том случае, если соответствующий ей вход соединен с землей, что и произойдет, согласно схеме, при нажатии кнопки. Задержка длительностью DEBOUNCE_TIME и повторная проверка нужна во избежание множественных лишних срабатываний из-за дребезга контактов. Сохранение статуса нажатия в соответствующих битах переменной _pressed используется для исключения повторного срабатывания при длительном нажатии на кнопку.
Функции обработки нажатий достаточно тривиальны и полагаю, что в дополнительных комментариях не нуждаются.
Прототип был собран на макетной плате:
После тестирования прототипа пришло время все это добро разместить в корпусе, обеспечить питание и т.д.
Ниже показан окончательный вид устройства. Часы питаются от 9-вольтовой батарейки типа “Крона”. Потребление тока — 55 мА.
Заключение
Потратив $20-25 на оборудование и пару вечеров на начальное ознакомление с архитектурой микроконтроллера и основными принципами работы, можно начать делать интересные DIY проекты. Статья посвящается тем, кто, как и я в свое время, думает, что начать программировать микроконтроллеры — это сложно, долго или дорого. Поверьте, начать намного проще, чем может показаться. Если есть интерес и желание — пробуйте, не пожалете!
Программирование микроконтроллеров. С чего начать?
Достаточно часто в личке ко мне обращаются люди с просьбой дать ссылки на полезные сайты, нужную информацию по программированию микроконтроллеров, необходимые программы и т.п. находясь при этом в самом начале своего познания микроконтроллеров. Сам я проходил через это буквально полтора года назад, имея нулевые знания и знаю, насколько это сложно, дать себе первоначального пинка, разобраться в лавине информации по микроконтроллерам, которую выдают поисковики, когда на тебя обрушивается куча непонятной информации и т. п.
Постараюсь объяснить на простом языке, для людей, умеющих держать паяльник, знающих, что такое цифровая микросхема логики, умеющих читать схемы и пользоваться мультиметром.
Микроконтроллеры бывают разных фирм, которые делают одно и тоже дело, но разными методами. Сравнить это можно с человеческими расами: европейцы, китайцы и африканцы например. Я лично работаю с микроконтроллерами фирмы Атмел, про них и буду говорить. Ну уж пошло сравнение с расами, пускай это будут европейцы.) Программы для микроконтроллеров пишут на языках программирования. Я рекомендую начать с языка Си. Это древний и простой язык. Для написания текста програмы используют программы компиляторы. Они позволяют создавать, редактировать и переваривать написанный программистом текст программы в код (прошивку), который можно загрузить (прошить) в микроконтроллер. Таких программ есть множество. Пример для Атмел: Code VisionAVR, родная от Атмел AVR Studio, Bascom-avr и ещё.
Эти программы делают одно и тоже дело, но своими методами, особенностями достоинствами и недостатками. При это текст Си в тих программах компиляторах немного отличается, но в общем похож. Можно сравнить с различием украинского, русского и белорусского языка. Я использую Code VisionAVR, что и советую начинающим.
Далее я приведу простой текст программы, написанный на языке Си в компиляторе Code VisionAVR для микроконтроллера ATTiny13A. В конце темы есть проект, прошивка и проект для эмулятора протеуса. Микроконтроллер в этой программе умеет делать простую вещь: при помощи кнопки менять логическое состояние на двух выходах, при этом короткое нажатие меняет состояние первого выхода а длинное — второго. В автомобиле например эту схему можно применить для управления одной кнопкой обогревом заднего стекла (которая есть у многих штатно) и добавленным обогревом зеркал. Нажал коротко на кнопку — сработал обогрев стекла, нажал ещё — обогрев стекла выключился. Если нажать и удерживать кнопку, то через какое-то время включиться обогрев зеркал. Если нажать и удерживать кнопку повторно — обогрев зеркал отключится.
Для понятия текста нужно знать грамматику, правила писанины языка Си, этого материала в интернете предостаточно. Так же желательно ознакомиться хотя бы с материалом, по использованию мастера создания проектов в CodeVisionAVR.
/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
www.hpinfotech.com
Project :
Version :
Date : 28.01.2012
Author :
Company :
Comments:
Chip type : ATtiny13A
AVR Core Clock frequency: 9,600000 MHz
Memory model : Tiny
External RAM size : 0
Data Stack size : 16
*****************************************************/
#include <tiny13a.h>
#include <delay.h>
unsigned char b, trig;
void main(void)
// Declare your local variables here
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
PORTB=0x01;
DDRB=0x06;
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
GIMSK=0x00;
MCUCR=0x00;
ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;
А теперь поподробнее.
/*****************************************************
This program was produced by the
CodeWizardAVR V2.05.0 Professional
Automatic Program Generator
© Copyright 1998-2010 Pavel Haiduc, HP InfoTech s.r.l.
www.hpinfotech.com
Project :
Version :
Date : 28.01.2012
Author :
Company :
Comments:
Chip type : ATtiny13A
AVR Core Clock frequency: 9,600000 MHz
Memory model : Tiny
External RAM size : 0
Data Stack size : 16
*****************************************************/
Это шапка, в которой содержится описание проекта, необходимые данные. Текст закомментирован знаками комментария /* в начале и */ в конце. Все, что находится между этими знаками программой не выполняется. Самое полезное здесь это указание типа микроконтроллера и его частота.
#include <tiny13a.h>
#include <delay.h>
Это ссылка на библиотеку. Если какая либо библиотека необходима, то она должна быть здесь указана. У нас есть библиотека самого микроконтроллера tiny13a.h, и библиотека задержек времени.
unsigned char a, b, trig;
Объявление трех переменных. unsigned char . Что это такое можно посмотреть здесь Вообще всё непонятное копируем в буфер и ищем в поисковике.
void main(void)
// Declare your local variables here
void main(void) — это оператор, говорящий что началась основная часть программы на Cи и микроконтроллер будет её с этого места выполнять. Все что начинается с // — это комментарий. Старайтесь чаще ими пользоваться. Вообще конкретный комментарий генерирует сам компилятор, как и во многих других местах. Большинство комментариев я удалил, что уменьшить текст.
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
В комментарии по английски написано, что это такое. Это первая команда микроконтроллеру, одна из команд, которая настраивает нужные функции, порты и необходимые части микроконтроллера, необходимые для его работы и запуска.
Конкретно это настройка частоты делителя тактовой частоты микроконтроллера. Теперь подробнее:
Микроконтроллер имеет тактовый генератор, который задается в мастере и который потом можно изменить в свойствах проекта если что. У нас эта частота 9.6 мегагерца, как видно в шапке.
При прошивке микроконтроллера эту же частоту нужно указать во фьюзах.
CLKPR=0x80; и CLKPR=0x00; это команды настройки регистра внутреннего делителя этой частоты. Задается оно в мастере в первом окне "CHIP". Если у нас выбран делитель 1, то тактовая частота делиться на 1, то есть остается без изменений. Если указать например делитель 128, то соответственно тактовая частота делиться на это число. 9.6Мгц / 128 = 75кГц. и значения регистра делителя будет выглядеть:
CLKPR=0x80;
CLKPR=0x07;
Особо внимательные заметили, в регистр делителя CLKPR сначала пишется число 0x80 а затем сразу 0x00. Нафига пишется сначала одно значение а потом сразу другое? Если у вас возникают какие либо вопросы по регистрам и не только, приучайтесь сразу читать даташиты. Там все подробные ответы на чистом английском языке. Открываете даташит, вставляете в поисковик текста название регистра (CLKPR ) и ищете его описание, за что какие биты данного регистра отвечают. Конкретно у этого регистра для изменения делителя необходимо записать единичку в седьмой бит, после чего микроконтроллер даст изменить и выбрать необходимый делитель в первых четырех битах этого регистра. После того, как пройдет четыре такта выполнения команд процессора, изменить регистр будет уже нельзя. Нужно снова сначала изменить седьмой бит CLKPR=0x80 а затем указать делитель CLKPR=нужный делитель
PORTB=0x01;
DDRB=0x06;
Команды управления и настройкой портов микроконтроллеров — ножек чипа. Задается тоже в мастере. В этих регистрах задается работа на вход порта PB0 и подключается к нему внутренний Pull-up резистор. Порты PB1 и PB2 настраиваются "на выход" с логическим нулем на выходе в их состоянии.
В колонке DataDitection мы указывает тип порта: вход или выход (in или out)
В колонке PullUp/Output Value указываем подключение подтягивающего резистора pullup если порт настроен на вход (P — подключен, Т — неподключен) Если порт настроен на выход, то можно указать его логическое состояние 0 или 1. У нас нули. Строчки Bit0 — Bit5 это порты микроконтроллера PORTB0 — PORTB5
Если посмотреть сгенерированный компилятором комментарий, то можно увидеть соответствие пинов и их настройку:
// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=In
// State5=T State4=T State3=T State2=0 State1=0 State0=P
Если перевести из 16-тиричного в двоичный значение регистров, то можно понять даже без даташита назначение битов в регистре:
PORTB=0x01 PORTB=0b00000001
DDRB=0x06 DDRB=0b00000110
Напоминаю, что при разложении в двоичный код младшие значения справа а старшие слева.
Незначащие нули слева можно не писать:
PORTB=0b1;
DDRB=0b110;
А можно вообще написать в десятичной системе:
PORTB=1;
DDRB=6;
Далее по тексту кода идет:
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
TCCR0A=0x00;
TCCR0B=0x00;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;
GIMSK=0x00;
MCUCR=0x00;
TIMSK0=0x00;
ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;
ADCSRA=0x00;
Настройка таймера микроконтроллера, прерываний, АЦП, компаратора и всего такого пока сложного. Пока его не используем — рановато. У всех этих регистров стоят в значениях нули, это значит, что они отключены. А особо внимательные заметили, что какой-то регистр ACSR имеет значение =0x80; Лезем в даташит и читаем:
Analog Comparator Control and Status Register – ACSR
Вообще, как правило название всех регистров это сокращение от первых букв или части их полного названия.
Если стоит значение данного регистра 0x80, значит в двоичной системе это число 10000000, значит стоит единичка в 7 бите этого регистра, значит читаем в даташите, что он означает:
• Bit 7 – ACD: Analog Comparator Disable
When this bit is written logic one, the power to the Analog Comparator is switched off.
This bit can be set at any time to turn off the Analog Comparator. This will reduce power
consumption in Active and Idle mode. When changing the ACD bit, the Analog Comparator
Interrupt must be disabled by clearing the ACIE bit in ACSR. Otherwise an interrupt
can occur when the bit is changed.
По-русски это означает, что установка единицы в этом бите отключает аналоговый компаратор, что его можно выключить в любой момент, что это приводит к снижению потребления электричества, и в конце текста написано про зависимости и что нужно соблюдать, если нужно изменять этот бит.
После того, как микроконтроллер настроен запущен и выполнена инициализация необходимых частей и выполнены необходимые первоначальные команды в void main(void) в дело вступает его величество главный цикл. Все что находиться внутри этого главного цикла while (1) и заключено в скобки начала и конца > будет крутиться, команды выполняться по кругу от начал до конца. А у нас в нашем коде будет крутиться алгоритм опроса кнопки, подключенной к порту PB0, от состояния которой (нажата кнопка или нет) будет меняться состояние выходных портов PB1 и PB2
На картинке видна схема собранную в эмуляторе Протеус схему, которая позволяет видеть работу кода программы.
Теперь про сами основные команды, которые находятся внутри цикла. Все команды используют один оператор if Это условие ЕСЛИ.
Если в регистре PINB в бите, отвечающем за порт PB0 микроконтроллера.0 содержится значение равное нулю ==0, то выполняем кучку кода, которая находится далее в границах скобок и >
Короче, если нажата кнопка то выполняется следующий код в границах последующих скобок и >
Далее после кучки кода в скобках видим оператор else и ещё кучку кода за ним в скобках и >
Оператор else переводится не как ещё а как иначе
Оператор if и else всегда работают в паре, сначала идет if затем else. Оператор else можно не использовать совсем, если он не нужен.
В нашей ситуации алгоритм можно описать так:
если (нажата кнопка подключенная к порту PB0)
то выполняем кучку кода;
>
иначе (кнопка не нажата)
выполняем эту кучку кода;
>
Так как это все находится внутри главного цикла, то этот код будет выполняться по кругу, будет постоянно опрашиваться кнопка и будет выполняться нужная кучка кода
Теперь рассмотрим кучку кода, которая выполняется, если кнопка нажата:
Операторы можно вкладывать друг в друга, как матрешку. то есть выполняется одно условие, потом если условие сработало, то другое внутри первого условия и т.д.
Если переменное значение trig равняется нулю, то выполняем инкремент переменной b Инкремент — операция увеличения значения, хранящегося в переменной, на 1. То есть при проходе выполнения кода, если процессор натыкается на команду инкремента b++, то процессор прибавляет единичку в число, которое находится в переменной b
Так же здесь применяется упрощенная "орфография" написания условия и команды, без скобок и >:
Такое представление используют, если после условия всего одна команда.
Немного отвлеклись, возвращаемся:
if (trig==0) b++; — если значение переменной равно нулю (а оно у нас равно нулю) то выполняем инкремент переменной b — переменная в была равна нулю, теперь стало единице.
Если переменная b больше ста, то выполняем кучку кода внутри скобок.
Переменная b за каждый круг цикла прибавляется на единичку и в итоге через сто "кругов" главного цикла выполниться условие, которая находится далее внутри скобок и >
Теперь рассмотрим что же там делается, если нажата кнопка, если прошло сто кругов цикла:
if (PINB.2==0)PORTB.2=1;
else PORTB.2=0;
trig=1;
b=0;
Здесь мы видим ещё одно условие (жирная такая матрешка получилась))
if (PINB.2==0)PORTB.2=1;
Если регистр состояния выходного порта PB, а точнее PB2 равен нулю, то меняем его состояние на единичку PORTB.2=1.
else PORTB.2=0;
Иначе пишем в регистр нолик. Или если по-другому: если регистр состояния выходного порта PB2 равен единице, то меняем его на ноль.
Короче если происходит выполнение этих условий и команд, то меняется логическое состояние выхода 2 (PB2) на схеме.
Если полностью описать: если нажата кнопка, если прошло сто кругов главного цикла, то меняем логическое состояние выхода 2 — PORTB.2 в коде он же порт PB2 на схеме.
Как уже стало понятно этот кусок кода отрабатывает длительное нажатие кнопки.
Но этого мало, дальше ещё есть две выполняемые команды присвоения:
trig=1; присвоение единице этой переменной необходимо, что бы описанное выше условие работы инкремента b++ перестало работать
b=0; обнуляем переменную b.
В итоге при длительном нажатии кнопки, условие при котором меняется состояние порта PB2 выполняется единожды, до тех пор, пока кнопка не будет отжата кнопка, ибо инкремент не будет работать и условие if (b>100) больше не сработает, если тупо нажать кнопку и не отпускать совсем.
Теперь вторая часть кучки кода, которая следует за первым условием:
else
if (b>4)
if (PINB.1==0)PORTB.1=1;
else PORTB.1=0;
b=0;
>
b=0;
trig=0;
>
Если кнопка отжата:
Опишем её с конца:
trig=0; присваиваем переменной trig значение ноль. Необходимо, что бы после длительного нажатия, когда наступит последующее отжатие кнопки микроконтроллер снова был готов к нажатиям кнопки ( срабатывало условие инкремента if (trig==0) b++;)
b=0; При не нажатой кнопке значение переменной b равняется нулю.
if (b>4)
if (PINB.1==0)PORTB.1=1;
else PORTB.1=0;
b=0;
>
Подробнее:
if (b>4)
Если значение переменной b больше четырех, то выполняем следующий код:
if (PINB.1==0)PORTB.1=1;
else PORTB.1=0;
Если состояние порта BP1 равно нулю, то делаем единицу, если нет, то ноль.
Это условие и команда отрабатывает кроткое нажатие кнопки. Если нажата кнопка, то начинает работать инкремент b++; значение которого начинает увеличиваться. Если отжать кнопку и при этом значение переменной b будет больше четырех ( но меньше ста — а то сработает длинное нажатие) то состояние выходного порта PB1 (он же выход 1 на схеме, он же PORTB.1 в коде) поменяется, сработает алгоритм короткого нажатия кнопки.
Если значение переменной b при отжатии меньше четырех, то условие не срабатывает и ничего не происходит. необходимо для работы "дребезга контактов" и ложных срабатываний.
И последнее это присвоение переменной b нулевого значения, что бы обработка алгоритма короткого нажатия происходило единожды.
В оконцовке главного цикла виднеется команда:
Это задержка в главном цикле. То есть, выполняется пошагово команды, затем процессор натыкается на команду delay_ms(10); и начинает её выполнять. В итоге процессор будет 10 миллисекунд ждать и ничего не делать в этой строчке, затем опять приступит к выполнению команд.
Находясь в одном общем цикле, скорость нарастания значения инкремента b++ зависит от времени задержки, указанной в delay_ms.
Команда delay_ms находится в библиотеке задержек #include <delay.h>, которую мы для этого и включили в начале кода.
Как видно из описания, длинное нажатие срабатывает от фронта сигнала нажатия кнопки ( начинает работать инкремент) а короткое нажатие кнопки — по спаду, то есть срабатывает по отжатию кнопки.
Вообще выполняемая здесь последовательность: условие + инкремент достаточно часто используемая команда и в языке Си присутствует отдельный оператор для этого for
Программирование микроконтроллеров PIC. Часть 1. Необходимые инструменты и программы. Основы MPLAB
Итак, вы решили научиться программировать pic-контроллеры. Для начала поговорим о том, что вам для работы с этими контроллерами понадобится.
Контроллер работает по определённой программе, которая должна как-то в него попасть. Обычно программу в машинных кодах, готовую для записи в контроллер, называют прошивкой. Следовательно нужно какое-то устройство, которое будет записывать (на сленге обычно говорят заливать или прошивать) программу в контроллер. Такое устройство называется программатор. Подробнее о программаторах и заливке программы мы поговорим позднее, в последней части нашей эпопеи (когда уже будет что заливать), а пока давайте по-порядку — как нам эту программу написать.
Программа для контроллера — это, как я уже сказал, набор машинных кодов, записанный в файле с расширением «hex» (здесь можно почитать про формат *.hex), который и нужно заливать в контроллер с помощью программатора. Никакого другого языка контроллер не понимает. Следовательно, нужна специальная программа, которая будет переводить текст программы, написанный на каком-либо языке программирования, в машинные коды. Наиболее удобными в этом плане являются интегрированные среды разработки (IDE — integrated development environment), поскольку они могут не только осуществлять перевод текста программы в машинный код, но и производить симуляцию её работы. Причём симуляцию можно проводить пошагово, при этом можно наблюдать состояние регистров или даже менять их состояние по своему желанию. Короче, интегрированные среды помимо, собственно, компиляции (перевода в машинные коды) предоставляют отличные возможности для отладки программы.
IDE, как и программаторов, существует много. Лично я пользуюсь MPLAB и вам рекомендую, по той простой причине, что MPLAB — это IDE от самого производителя PIC-контроллеров — фирмы Microchip, поэтому имеет отличную поддержку (в том числе на русском языке, что особенно приятно). С официального сайта Microchip можно скачать и сам этот пакет, и подробное описание по работе с ним. Если не нашли или ломает искать — ссылки для скачивания здесь, правда это уже не самая свежая версия.
В описании на русском языке про всё рассказано: от установки и настройки до удаления. В большинстве случаев вся установка заключается в том, чтобы запустить setup и ответить на пару вопросов, типа куда ставить драйверы и тому подобное, от себя лишь добавлю, что во избежание глюков ставить пакет надо в такую папку, чтобы в пути были только английские буквы (а не в какую-нибудь, типа C:\Программы\PIC\MPLAB). Вообще, кириллицу в путях к файлам или в названиях файлов лучше не использовать, иначе возможны глюки.
MPLAB позволяет писать программы на двух языках: СИ и Ассемблер. Интернет просто ломится от разборок СИ-шников и ассемблерщиков, которые с пеной у рта доказывают друг другу, какой язык лучше. Я отношу себя к ассемблерщикам, поэтому, естественно, расскажу почему лучше именно Ассемблер.
Ассемблер представляет собой набор элементарных команд, выполняемых контроллером. Каждая команда трактуется в машинный код совершенно однозначно, а результат её выполнения и время выполнения всегда одинаковы. То есть, если вы имеете листинг на ассемблере, то вы можете совершенно точно сказать, что делает контроллер в каждый момент времени и каким именно образом достигается нужный результат.
Программа на языке СИ (да и вообще на любом языке высокого уровня) — это уже набор команд не контроллера, а соответствующего языка. При компиляции каждая такая команда заменяется набором команд для контроллера, но каким именно набором команд она заменяется, — этого вы уже не знаете, это знает только разработчик языка программирования. Соответственно, невозможно понять, каким именно образом контроллер выполняет желаемое действие.
Короче говоря, в случае с языком высокого уровня вы изучаете как какой-то дядя обозвал свои способы реализации необходимых вам функций и по каким правилам их надо записывать. В данном случае можно провести следующую аналогию: вы хотите поговорить с китайцем, но вам говорят: "Китайский слишком сложный язык, но есть один дядя в Болгарии, который 20 лет жил в Китае и отлично его выучил. А болгарский язык с русским очень похожи и русскому человеку он интуитивно понятен, так что выучите болгарский, а уж дядя переведёт."
В случае с ассемблером, вы изучаете сам контроллер и правила, по которым надо разговаривать с контроллером. При этом контроллер имеет всего-то несколько десятков команд, которые умещаются на одном листке и их легко можно окинуть одним взглядом.
Надеюсь, к этому моменту вы уже сделали выбор языка программирования, так что пойдём дальше.
Что нужно сделать в MPLAB, чтобы получить желанную прошивку? Как я уже сказал — подробности читайте в руководстве к IDE MPLAB, оно на русском и там всё понятно (если не понятно — идём на форум), я же только кратко перечислю самое основное и дам некоторые рекомендации.
Итак, мы установили MPLAB, хотим написать в нём программу для контроллера и получить готовую прошивку.
Сначала нужно создать проект. Для каждого проекта рекомендую заводить отдельную папку, потому что, во-первых, в проект может входить несколько файлов, а, во-вторых, сам MPLAB создаст ещё несколько вспомогательных файлов (*.lst, *.err, *.cod, *.bkx). Если несколько проектов будут в одной папке, то легко можно запутаться какие файлы к какому проекту относятся. Короче, создаём для проекта новую папку, потом запускаем MPLAB и выбираем меню Project -> New Project…
В появившемся окошке, в проводнике справа, выбираем нашу папку, в левой части (в поле под надписью File Name) пишем название будущего проекта, например my1.pjt (не забываем указать расширение), и жмём ОК.
Появляется окно с названием Edit Project. Это менеджер проекта, в котором указываются параметры проекта (какие файлы и библиотеки нужно подключить к проекту, какой будет использоваться камень, будет ли использоваться симуляция и многое другое). Находим поле ввода с названием Development Mode. Справа от этого поля есть кнопочка Change… Нажимаем.
Открывается окошко с названием Development Mode, в котором мы видим кучу вкладок. На вкладке Tools ставим галочку рядом с MPLAB SIM Simulator (грех для отладки симулятором не пользоваться), в поле ввода Processor выбираем контроллер, с которым мы будем работать. На вкладке Clock указываем какая у нас будет частота генератора. Жмём ОК. На ошибку и предупреждение не обращаем внимания, это просто нам говорят, что пока не могут создать .hex (ну правильно, у нас пока и программы нет) и что при изменении настроек надо заново перекомпилировать проект (так мы ещё вообще ни разу не компилировали).
В поле ввода Language Tool Suite выбираем Microchip.
Нажимаем кнопку с названием Add Node… В появившемся окне, в проводнике справа выбираем папку проекта, в поле ввода слева пишем как будет называться файл с текстом программы на ассемблере, например my1.asm (не забываем указывать расширение), и жмём ОК. Всё, теперь мы подключили к проекту файл my1.asm (указали, что текст программы будет в этом файле).
На этом с Edit project заканчиваем, — нажимаем ОК.
Теперь нужно, собственно, создать файл с текстом программы (в менеджере проекта мы просто указали, что текст будет в таком-то файле, но фактически этот файл ещё не создан). Для этого идём в меню File и выбираем пункт New. Откроется окошко редактора с названием Untitled1. Выбираем меню File -> Save As…, в проводнике справа указываем папку проекта, в поле ввода File Name пишем название файла, которое мы указали в менеджере проекта, то есть в нашем примере это будет my1.asm. Если всё сделано правильно, то название окошка редактора поменяется с Untitled1 на \путь\my1.asm.
Вот и всё! Теперь осталось только набрать в окошке редактора текст программы, скомпилировать проект (меню Project->Build All) и, если в программе нет ошибок (что с первого раза бывает очень редко), то в папке проекта появится готовая прошивка (файл с расширением hex), которую можно заливать в контроллер.
Программатор CH341A + прошивка микросхем памяти
Инженерам-электронщикам, радиолюбителям, — каждому, кто занимается эксплуатацией, обслуживанием, ремонтом электроники, необходим программатор в принципе. Починка телевизоров, компьютеров, спутниковых ресиверов и прочей аппаратуры, как правило, требует прошить микросхему памяти без выпаивания из платы. Так вот для этих целей разработан программатор CH341A микросхем памяти универсальный.
Программатор микросхем памяти еепром/флеш — CH341A
Небольшой по размерам электронный прибор для прошивки подключается к порту USB компьютера. Прошивальщик позволяет быстро программировать микросхемы памяти 24хх, 25хх серий и аналогичных. Рассмотрим электронику для лучшего представления, понимания, применения на практике.
Микросхемы памяти серий 24хх (eeprom), 25хх (serial flash) используются в схемах электронной техники повсеместно.
Такого рода чипы присутствуют в составе практически любой конструкции современной бытовой / промышленной аппаратуры, управляемой через микроконтроллеры.
Для электронщиков, работающих с такой аппаратурой нужным инструментом является программатор, в частности, модель CH341A, позволяющая выполнять программирование чипов памяти без выпаивания из состава печатной платы.
Полное представления на программатор CH341A даёт описание (datasheet), дополненное стандартными техническими характеристиками. Тем не менее, рассмотрим девайс электронщика глазами обывателя, что часто воспринимается потенциальным пользователем проще и легче официальных документов.
Универсальный программатор CH341A для работы с широко распространёнными микросхемами памяти типа EEPROM и FLASH. Обзавестись таким девайсом обязан каждый уважающий себя электронщик
Сборка устройства выполнена на базе микроконтроллера «USB Bus Convert Chip» серии CH341A. Программатор рассчитан на физическое подключение к порту USB компьютеров, работающих под управлением современных ОС Windows. Модуль программирования микросхем памяти собран на печатной плате размерами 45х25 мм (см. картинку ниже).
Внешний вид монтажной платы программатора с нижней стороны. На площади размерами 45х25 мм расположился сам микропроцессор и сопутствующая обвязка электронными микроэлементами
На одной стороне печатной платы размещены электронные компоненты программатора CH341A. На второй стороне электронной платы установлена механическая панель (ZIF) под временное крепление программируемых микросхем.
Механическая ZIF-панель прошивальщика поддерживает чипы в корпусах DIP. Обеспечивает удобство работы пользователя, когда выполняется считывание или «прошивка» чипов памяти.
Универсальный программатор CH341A — применение в работе
Подключение микросхем флэш-памяти 25хх серии с корпусным исполнением SOP8/SOP16 на программаторе осуществляется через соответствующие контактные площадки. Две таких площадки располагаются непосредственно на монтажной плате программатора CH341A рядом с ZIF-панелью.
Программатор универсальный CH431A и комплект дополнительных элементов. Миниатюрная плата с отверстиями для штырьков, на обратной стороне имеет площадки под чипы SOP
Также в комплекте с программатором CH341A поставляется дополнительная монтажная печатная плата. Этот аксессуар применяется на случай программирования микросхем памяти с архитектурным исполнением корпусов SOP8/SOP16. Под внутрисхемное программирование на печатной плате программатора CH341A выведены контакт питания под напряжение 3.3 вольта и соответствующие контакты ISP интерфейса:
- MOSI;
- MISO;
- CLK;
- CS;
- GND.
Вместе с тем есть возможность работать с периферией по интерфейсу RS232 (выводы на плате RX, TX, GND). Схема программатора CH341A рассчитана под питание постоянным напряжением 5 вольт от внешнего источника. Это напряжение, при подключении программатора к персональному компьютеру, поступает по шине USB.
Подключенный к USB порту компьютера программатор CH341A для микросхем памяти . Свечение красного индикатора свидетельствует о наличии питания в схеме устройства
На печатной плате программатора встроен индикатор наличия питания – светодиод красного цвета. Режим внешнего или внутреннего программирования включается съёмом или установкой перемычки на контактах P/S (parallel/serial), также внедрённых в схему программатора CH341A. По умолчанию перемычка установлена.
Положению установленной перемычки на контактах P/S (parallel/serial) программатора CH341A соответствует режим внутреннего программирования. В этом случае:
- чтение,
- верификация,
- запись чипов памяти,
осуществляются непосредственно через ZIF-панель программатора CH341A. Между тем на плате программатора универсального CH341A перемычка может быть снята с контактов P/S (parallel/serial). Программирование в таком режиме допускает непосредственное подключение к программируемой микросхеме памяти без выпаивания из платы.
Программатор CH341A — программное обеспечение прошивки/считывания
Действие универсального физического модуля CH341A на программном уровне поддерживается «родительским» программным обеспечением — «CH341A Programmer» (здесь версия 1.4).
Используемые драйверы для операционных систем и интерфейсов:
- и ранее на IIC / I2C, SPI и другие; и ранние на последовательный интерфейс;
- под Linux;
- под Mac;
бесплатно распространяется по сети Интернет.
Интерфейс рабочего программного окна ПО версии 1.30 прост для восприятия и понимания как начинающим электронщикам, так и профессионалам. Все основные обозначения программного интерфейса версии 1.30 переведены на русский язык. В целом программой поддерживается несколько региональных языков интерфейса. Однако выше представлена также версия 1.4 (английский интерфейс).
Таким выглядит окно программного обеспечения для программатора CH341A. Удобный лёгкий для восприятия и понимания интерфейс, поддерживающий обозначения на русском языке
Конечно же, чтобы программное обеспечение удачно состыковать с устройством, корректно и эффективно программировать, требуется установка системных драйверов. Это компоненты, дополняющие ПО, как правило, включены в установочный пакет программного софта.
При подключении программатора на порт USB, система автоматически выдаёт (только старые версии Windows) сообщение о необходимости установки драйверов устройства. Нужно просто указать путь к папке, где находятся требуемые файлы. Последние версии (например, Windows 10) требуют файлы с цифровой подписью. Здесь выше можно скачать официальные драйверы, наделённые цифровой подписью.
Тонкости программирования микросхем памяти через интерфейс CH341A
Логичный вопрос начинающих электронщиков: как прошить микросхему памяти eeprom в корпусе DIP с помощью этого устройства? Так вот, работа с чипами памяти EEPROM (24хх, 25хх) в корпусном исполнении DIP, осуществляется, примерно, следующим образом (при условии предварительно установленных драйверов):
- На ZIF-панели рукоятку установить перпендикулярно корпусу.
- Вставить микросхему в ячейку согласно обозначению на плате 24хх или 25хх (1 ножка ближе к рукоятке).
- Опустить рукоятку в положение параллельно корпусу панели.
- Подключить программатор CH341A на USB порт.
- Подключить устройство в диспетчере Windows.
- Запустить Programmer и выполнить требуемые действия (считывание, прошивка, сравнение контрольных сумм и т.д.).
Видеоролик выше показывает последовательность работы с микросхемами памяти через программную среду сопровождения. В частности, показаны примеры работы с ПО «Programmer CH341A» двух версий (1.30 и 1.4, соответственно).После завершения работы с ПО, устройство в списке диспетчера Windows рекомендуется отключать (не удалять, но деактивировать).
Программирование чипов из серии флэш-памяти 25хх с корпусным исполнением SOP делается несколько иначе. Контактная ZIF-панель в этом случае может также использоваться, но при условии, если микросхема монтируется на дополнительной печатной плате.
Дополнительную печатную плату необходимо оснастить контактными электродами, впаяв электроды в соответствующие отверстия платы. Операционную (программируемую) микросхему также придётся подпаивать на контактные площадки.
Между тем существует упрощённый способ коммуникации. На основной плате программатора CH341A имеются площадки под конфигурацию SOP. На такую площадку аккуратно накладывают программируемый чип с тем расчётом, чтобы ножки микросхемы точно попадали на контактные дорожки.
Контактные площадки под размещение микросхем памяти в корпусном исполнении типа SOP. Две площадки под серию 25хх и одна под серию 24хх
Следует проконтролировать соответствие расположения микросхемы по ключу на корпусе и на плате. Там есть указатель контакта первой ножки чипа. Затем чип аккуратно прижимают миниатюрной прищепкой. Дальше всё делается стандартным образом – подключение к порту компьютера и программирование микросхемы.
Программатор CH341A: где купить и какая цена
Купить устройство выгоднее на известном портале Aliexpress. Цена, заявленная китайскими продавцами, чисто символическая (не более 200 руб. вместе с пересылкой). Быстрее и проще покупка производится через федеральный Маркет Яндекса. Предложения ниже:
Единственное неудобство для покупателя в случае запроса через китайский shop-портал AliExpress – приходится ожидать прибытия посылки в Россию примерно месяц-полтора. Но если учитывать открывающиеся возможности с приобретением этого товара, можно подождать и 3 месяца. Однако немного доплатив, проще купить в России.
Страница одного из продавцов Aliexpress, предлагающего программатор CH341A купить за 112 руб. Это предложение проверено — можно смело покупать, к примеру, за яндекс-деньги
Читать и «шить» программатором CH341A доступно чипы памяти следующих производителей:
- Atmel;
- Amic;
- EON;
- ST;
- Excel Semiconductor Inc;
- NexFlash;
- MXIC;
- Chingis Technology Corporation;
- WINBOND;
- Saifun Semiconductors.
Таблица поддерживаемых микросхем программатором CH341A
ATMEL | AT25DF041A, AT25DF321, AT25F004, AT25F512A, AT25F2048, AT25F4096, AT25F1024A, AT25FS010, AT25FS040, AT26DF081A,AT26DF161A, AT26DF321, AT26F004 |
AMIC | A25L05P, A25L10P, A25L20P, A25L40P, A25L80P, A25L16P |
EON | EN25B05, EN25P05, EN25B10, EN25P10, EN25BF20, EN25P20, EN25F20, EN25B40, EN25P40, EN25F40, EN25B80, EN25P80, EN25F80, EN25T80, EN25B16, EN25P16, EN25B32, EN25P32, EN25B64, EN25P64 |
ST | M25P05A, M25P10A, M25P20, M25P40, M25P80, M25P16, M25P32, M25P64, M25PE10, M25PE20, M25PE40, M25PE80, M25PE16, M25PE32, M45PE10, M45PE20, M45PE40, M45PE80, M45PE16, M45PE32 |
EXCEL SEMICONDUCTOR INC | ES25P10, ES25P20, ES25P40, ES25P80, ES25P16, ES25P32 |
NEXFLASH | NX25P80, NX25P16, NX25P32 |
MXIC | MX25L512, MX25L1005, MX25L2005, MX25L4005, MX25L8005, MX25L1605, MX25L3205, MX25L6405, MX25L6445, MX25L6405 |
CHINGIS TECHNOLOGY CORPORATION | Pm25LV512, Pm25LV010, Pm25LV020, Pm25LV040, Pm25LV080, Pm25LV016, Pm25LV032, Pm25LV064 |
WINBOND | W25P10, W25X10, W25Q10, W25P20, W25X20, W25Q20, W25P40, W25X40, W25Q40, W25P80, W25X80, W25Q80, W25P16, W25X16, W25Q16, W25P32, W25X32, W25Q32, W25P64, W25X64, W25Q64 |
SAIFUN | SA25F005, SA25F010, SA25F020, SA25F040, SA25F080, SA25F160, SA25F320 |
Таблица выше представляет далеко не полный список фирм, микросхемы памяти которых доступны для чтения и записи кода программатором CH341A.
После чтения содержимого чипа устройством, программа сохраняет файлы в указанную папку с присвоением расширения *.bin (бинарный). Этот момент процесса программирования нужно учитывать.
Например, когда для новой прошивки микросхемы используются файлы дампов, полученные из других источников, наделённые другими типами расширения. Перед загрузкой программатором таким файлам нужно заменить расширение на используемое по умолчанию (*.bin).
Как прошить микросхему памяти без выпаивания
Программатор микросхем памяти проверялся на чтении дампа eeprom-памяти контроллера Pixel (2 шт. ATMLH132). Работа на чтение информации, которую не удавалось сделать с помощью других конструкций программаторов, потребовала не более 3-4 секунд времени. При этом читаемые микросхемы памяти из платы контроллера не выпаивались.
На интерфейс программатора CH341A подключался непосредственно модуль памяти контроллера Pixel, состоящий из двух чипов памяти 24 серии. Подключение производилось через стандартный 4-контактный разъём. Опыт — как читать дамп с микросхемы серии 24С04 без выпаивания чипа из платы, описан далее.
Чтение дампа микросхем памяти программатором CH341A
Чтобы иметь возможность подключаться к микросхемам в DIP корпусах непосредственно на плате, нужно обзавестись контактной «прищепкой». Этот инструмент также можно купить недорого на упомянутом ранее сайте.
Набор аксессуаров для программатора, куда входит прищепка-контактор под микросхемы в корпусе DIP и переходная плата, с помощью которой осуществляется контакт с ZIF-панелью
Прищепка устанавливается на корпус микросхемы с таким расчётом, чтобы все контакты точно «сели» на ножки программируемого чипа. Первая контактная ножка рабочей микросхемы должна соответствовать контакту «прищепки» с подведённым красным проводом.
Плата с рабочим чипом, на который пишется или с которого снимается дамп, должна отключаться от любых источников питания,
включая литий-ионные батареи (актуально для компьютерных материнских плат). На программаторе CH341A перемычка на контактах «P/S» снимается.
Пример подсоединения кабеля с прищепкой к программируемой микросхеме памяти. Проводник, помеченный красным цветом, соответствует контакту с первой ножкой чипа
Ответный конец кабеля с «прищепкой» подключается на переходник (мини-плата) через штыревое соединение, и далее к ZIF-панели программатора CH341A. В зависимости от типа программируемой микросхемы, плата-переходник устанавливается в контактные гнёзда для чипов серии 24хх или 25хх.
Дальше останется только включить программатор CH341A в USB порт, запустить сопровождающую программу на компьютере и можно начинать работать с дампом микросхем памяти. К примеру, для указанной серии микросхем 24С04 потребовалось времени на считывание дампа не более 3 секунд:
Результат работы с микросхемой памяти в условиях её полного контакта с платой устройства. Съём дампа осуществлялся без выпаивания микросхемы из платы устройства
Некоторые микросхемы памяти, рассчитанные под напряжение питания 5 вольт, иногда не реагируют на действия программатора CH341A. Выражается это результатом, когда дамп не считывается и не пишется.
Причина отсутствия чтения/записи на программаторе CH341A
Объясняется причина отсутствия рабочего эффекта просто: по умолчанию схемой программатора CH341A используется рабочее напряжение (стабилизированное от USB) равное 3.3 вольтам. При таком малом уровне напряжения и токе не превышающем 500 мА, некоторые серии чипов попросту «не входят» в режим программирования.
Принципиальная схема программатора CH341A, предназначенного для программирования микросхем памяти серий 24хх (eeprom) и 25хх (флеш память)
К тому же следует учитывать потери тока через ёмкости электронной платы, где установлен операционный чип. Для подобных случаев необходим достаточный рабочий уровень напряжения программирования, а также достаточно высокий токовый потенциал.
Соответственно, устранение причины – подача напряжения программирования непосредственно от более мощного внешнего источника питания. Для этого используется 7-контактный разъём, присутствующий на плате программатора CH341A. Обозначение контактов разъёма есть на принципиальной схеме (см. выше).
Видеоролик обзор + установка драйверов Windows 10
Видеороликом ниже представлен краткий обзор устройства программирования микросхем памяти — программатора CH341A. Дополнительно показана установка драйверов устройства в операционной системе Windows 10 версия 32 бит (для 64-битной версии установка аналогичная):
КРАТКИЙ БРИФИНГ
Z-Сила — публикации материалов интересных полезных для социума. Новости технологий, исследований, экспериментов мирового масштаба. Социальная мульти-тематическая информация — СМИ .