Attiny13 arduino IDE
Содержание
CAMOKAT-BETEPAHA ›
Блог ›
Программирование микроконтроллеров. С чего начать?
Достаточно часто в личке ко мне обращаются люди с просьбой дать ссылки на полезные сайты, нужную информацию по программированию микроконтроллеров, необходимые программы и т.п. находясь при этом в самом начале своего познания микроконтроллеров. Сам я проходил через это буквально полтора года назад, имея нулевые знания и знаю, насколько это сложно, дать себе первоначального пинка, разобраться в лавине информации по микроконтроллерам, которую выдают поисковики, когда на тебя обрушивается куча непонятной информации и т. п.
Постараюсь объяснить на простом языке, для людей, умеющих держать паяльник, знающих, что такое цифровая микросхема логики, умеющих читать схемы и пользоваться мультиметром.
Микроконтроллеры бывают разных фирм, которые делают одно и тоже дело, но разными методами. Сравнить это можно с человеческими расами: европейцы, китайцы и африканцы например. Я лично работаю с микроконтроллерами фирмы Атмел, про них и буду говорить. Ну уж пошло сравнение с расами, пускай это будут европейцы.) Программы для микроконтроллеров пишут на языках программирования. Я рекомендую начать с языка Си. Это древний и простой язык. Для написания текста програмы используют программы компиляторы. Они позволяют создавать, редактировать и переваривать написанный программистом текст программы в код (прошивку), который можно загрузить (прошить) в микроконтроллер. Таких программ есть множество. Пример для Атмел: Code VisionAVR, родная от Атмел AVR Studio, Bascom-avr и ещё.
Эти программы делают одно и тоже дело, но своими методами, особенностями достоинствами и недостатками. При это текст Си в тих программах компиляторах немного отличается, но в общем похож. Можно сравнить с различием украинского, русского и белорусского языка. Я использую Code VisionAVR, что и советую начинающим.
Далее я приведу простой текст программы, написанный на языке Си в компиляторе Code VisionAVR для микроконтроллера ATTiny13A. В конце темы есть проект, прошивка и проект для эмулятора протеуса. Микроконтроллер в этой программе умеет делать простую вещь: при помощи кнопки менять логическое состояние на двух выходах, при этом короткое нажатие меняет состояние первого выхода а длинное — второго. В автомобиле например эту схему можно применить для управления одной кнопкой обогревом заднего стекла (которая есть у многих штатно) и добавленным обогревом зеркал. Нажал коротко на кнопку — сработал обогрев стекла, нажал ещё — обогрев стекла выключился. Если нажать и удерживать кнопку, то через какое-то время включиться обогрев зеркал. Если нажать и удерживать кнопку повторно — обогрев зеркал отключится.
Для понятия текста нужно знать грамматику, правила писанины языка Си, этого материала в интернете предостаточно. Так же желательно ознакомиться хотя бы с материалом, по использованию мастера создания проектов в CodeVisionAVR.
Текст программы:
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;
TIMSK0=0x00;
ACSR=0x80;
ADCSRB=0x00;
DIDR0=0x00;
ADCSRA=0x00;
delay_ms(10);
}
}
А теперь поподробнее.
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;
Далее по тексту кода идет:
Настройка таймера микроконтроллера, прерываний, АЦП, компаратора и всего такого пока сложного. Пока его не используем — рановато. У всех этих регистров стоят в значениях нули, это значит, что они отключены. А особо внимательные заметили, что какой-то регистр ACSR имеет значение =0x80; Лезем в даташит и читаем:
Analog Comparator Control and Status Register – ACSR
Вообще, как правило название всех регистров это сокращение от первых букв или части их полного названия.
Если стоит значение данного регистра 0x80, значит в двоичной системе это число 10000000, значит стоит единичка в 7 бите этого регистра, значит читаем в даташите, что он означает:
По-русски это означает, что установка единицы в этом бите отключает аналоговый компаратор, что его можно выключить в любой момент, что это приводит к снижению потребления электричества, и в конце текста написано про зависимости и что нужно соблюдать, если нужно изменять этот бит.
while (1)
После того, как микроконтроллер настроен запущен и выполнена инициализация необходимых частей и выполнены необходимые первоначальные команды в void main(void) в дело вступает его величество главный цикл. Все что находиться внутри этого главного цикла while (1) и заключено в скобки начала { и конца } будет крутиться, команды выполняться по кругу от начал до конца. А у нас в нашем коде будет крутиться алгоритм опроса кнопки, подключенной к порту PB0, от состояния которой (нажата кнопка или нет) будет меняться состояние выходных портов PB1 и PB2
На картинке видна схема собранную в эмуляторе Протеус схему, которая позволяет видеть работу кода программы.
Теперь про сами основные команды, которые находятся внутри цикла. Все команды используют один оператор if Это условие ЕСЛИ.
if (PINB.0==0)
{
кучка кода;
}
else
{
ещё кучка кода;
}
Подробнее:
if (PINB.0==0)
Если в регистре PINB в бите, отвечающем за порт PB0 микроконтроллера.0 содержится значение равное нулю ==0, то выполняем кучку кода, которая находится далее в границах скобок { и }
Короче, если нажата кнопка то выполняется следующий код в границах последующих скобок { и }
Далее после кучки кода в скобках видим оператор else и ещё кучку кода за ним в скобках { и }
Оператор else переводится не как ещё а как иначе
Оператор if и else всегда работают в паре, сначала идет if затем else. Оператор else можно не использовать совсем, если он не нужен.
В нашей ситуации алгоритм можно описать так:
если (нажата кнопка подключенная к порту PB0)
{
то выполняем кучку кода;
}
иначе (кнопка не нажата)
{
выполняем эту кучку кода;
}
Так как это все находится внутри главного цикла, то этот код будет выполняться по кругу, будет постоянно опрашиваться кнопка и будет выполняться нужная кучка кода
Теперь рассмотрим кучку кода, которая выполняется, если кнопка нажата:
if (trig==0) b++;
if (b>100)
{
if (PINB.2==0)PORTB.2=1;
else PORTB.2=0;
trig=1;
b=0;
}
Операторы можно вкладывать друг в друга, как матрешку. то есть выполняется одно условие, потом если условие сработало, то другое внутри первого условия и т.д.
if (trig==0) b++;
Если переменное значение trig равняется нулю, то выполняем инкремент переменной b Инкремент — операция увеличения значения, хранящегося в переменной, на 1. То есть при проходе выполнения кода, если процессор натыкается на команду инкремента b++, то процессор прибавляет единичку в число, которое находится в переменной b
Так же здесь применяется упрощенная «орфография» написания условия и команды, без скобок { и }:
if (trig==0) b++;
это же самое что:
if (trig==0)
{
b++;
}
Такое представление используют, если после условия всего одна команда.
Немного отвлеклись, возвращаемся:
if (trig==0) b++; — если значение переменной равно нулю (а оно у нас равно нулю) то выполняем инкремент переменной b — переменная в была равна нулю, теперь стало единице.
Следующая операция:
if (b>100)
{
кучка кода;
}
Если переменная 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=0;
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);
Это задержка в главном цикле. То есть, выполняется пошагово команды, затем процессор натыкается на команду delay_ms(10); и начинает её выполнять. В итоге процессор будет 10 миллисекунд ждать и ничего не делать в этой строчке, затем опять приступит к выполнению команд.
Находясь в одном общем цикле, скорость нарастания значения инкремента b++ зависит от времени задержки, указанной в delay_ms.
Команда delay_ms находится в библиотеке задержек #include <delay.h>, которую мы для этого и включили в начале кода.
Как видно из описания, длинное нажатие срабатывает от фронта сигнала нажатия кнопки ( начинает работать инкремент) а короткое нажатие кнопки — по спаду, то есть срабатывает по отжатию кнопки.
Вообще выполняемая здесь последовательность: условие + инкремент достаточно часто используемая команда и в языке Си присутствует отдельный оператор для этого for
Архив с прошивкой, исходником и моделью Протеуса:
umat.ru/files/Button_13.zip
ВНИМАНИЕ!
Архив перезалил 22 сентября 2014 года, обнаружил косяк в выставленной частоте в проекте. Теперь тактовая частота 1.2 Мегагерца, при этом фьюзы стоят по дефолту и их при прошивке трогать вообще не надо
GTRacing ›
Блог ›
Прошивка МК Attiny13A
С китайскими USBASP вообще нездоровая ситуация. При получении прошивку менять однозначно на последнюю офф — после этого ругаться перестает. Я шил через 5 проводков. Сейчас перешил на прошивку от asprog — чтобы еще и флешки шить. У меня 2 версии — на одной просто процессор 8, на второй 8L. Кварцы одинаковые — по даташиту 8L не длжна работать на такой частоте — но работает. (я х.з.). Вчера попробовал прошить ими ATTINY13а — обломился. Не видит сигнатуры. Тьму прог перебрал — не помогло. Попробовал ими же друг друга перешить — аналогично, нет сигнатуры? Воткнул 5 проводков — на раз прошил оба и офф и от asprog. Проверил в asprog оба — отлично работают. Друг друга НЕ ШЬЮТ! Что на фигня? Все варианты пробовал — и слоу перемычку тоже. И местами менял…Провод-перемычку прозванивал и менял. Раньше ими же шил Ардуино мини со стертым загрузчиком — идеально все (тоже китайская, проц 328). Поздно уже было — бросил. Вечером еще добью до конца — попробую 5 проводков на ATTINY13а и еще раз прошить Ардуино мини через USBASP.
Дополнительная информация — ATTINY13а из магазина, ничего не менялось — делалась попытка читать только сигнатуру и состояние фьюзов — т.е. совсем без записи. Стоит Win7 32.
А так то после того, как увидел, какой фокус китайцы забабахали с FTDI и PL чипами — уже ничему не удивляюсь (3 дня тупил, пока дошло что просто переходники перестали работать — все 3 штуки одновременно! — установил обновления на винду называется!). Так что не сильно удивлюсь, если окажется что и меги8 в этих программаторах — подделка. особенно учитывая ту цену, по которой они продаются…
По поводу переходника и прищепки — удобнее 1 ногу сначала припаять, так на порядок легче «прилепить» правильно. У меня есть колодка под это дело и «прищепка» с переходными контактами — стоят копейки, работать на порядок удобнее.
Простой ШИМ на ATTiny13.Регулируем всё
Потребовалось регулировать температуру маленького 12-ти вольтового паяльника Baku 938 мощностью 8 Вт , но в интернете попадались схемы ШИМ на дискретных элементах, например, схемы на таймере 555, к561ла7, к561лн2, на мультивибраторе из транзисторов.
ШИМ или PWM — процесс управления мощностью, подводимой к нагрузке, путём изменения скважности импульсов, при постоянной частоте.
Собрав несколько из них, ни одна меня не устроила, у них был слишком крутой спад\подъем сопротивления при вращении ручки переменного резистора — от 2 кОм сразу подскакивало к 7 кОм, и следовательно, при этом, к примеру, подключенный для теста на исток полевого транзистора, компьютерный вентилятор со скорости 20 процентов сразу поднимал обороты до 90-100 процентов. В общем, чтобы пользоваться схемой, пришлось бы вращать потенциометр с прецизионной точностью и\или с замером сопротивления при вращении.
Однако, нашлась схема, собранная на ATTiny13, в которой используется цифровая ШИМ . Посмотреть статью о ней можно на странице cxem.net/master/61.php
Сначала я отнесся к ней скептически, но зря, потому что схема минимальна по обвязке, по сравнению с дискретными схемами найденными ранее. Микросхема маленькая и дешевая, изготавливается в корпусах SOIC,DIP, QFN, MLF, ножек всего 8, как и у таймера NE\LM555.
ШИМ на ней получается точным и легко регулируется.
—Как прошить микроконтроллер ATmega, AVR
—Эмуляция AVR в Proteus, микроконтроллеры в Proteus
—Как написать код для AVR, программирование микроконтроллеров Atmel AVR на Си
Наглядная схема (принципиальную схему смотрите по ссылке выше на сайте-источнике).
Описание чипа Atmel (Microchip) ATTiny13A
ATTiny13A — это 8 битный AVR микроконтроллер с программируемой Flash памятью внутрисистемно, размером 1 КБ.
Распиновка (pinout) микроконтроллера ATTiny13A
В чем отличие ATTiny13 от ATTiny13A ?
Tiny13A — это более новый и улучшенный микроконтроллер от Atmel.
Ранее выпускались два варианта Тини13 — с обычным (ATTiny13, работает от 2.7 вольт) и пониженным (ATTiny13V, работает от 1.8 вольт) питанием.
При этом первый вариант работает на частоте до 20 Мгц, второй — до 10Мгц.
С выходом Тини13А убрали разделение мк по питанию, Тини13А работает и от 1.8 вольт (в этом режиме, при пониженном низковольтном питании его невозможно заставить работать на высокой частоте).
Примечание по сборке схемы
По случаю у меня как раз завалялось уже ненужное мне реле времени, где оказался тот самый микроконтроллер attiny13, к тому же на плате уже были выводы под пайку для прошивки микросхемы. На основе этой платы была собрана новая схема, с новой прошивкой.
Светодиоды лучше брать с тусклым свечением, разные яркие цвета могут раздражать, особенно ярко светится синий светодиод. Яркость можно снизить применив в цепи питания светодиодов резисторы, например, до 2 кОм.
Можно обойтись и без светодиодов (следовательно и еще без трёх резисторов), они просто нужны для индикации и отображения режима работы.
Также можно обойтись и без линейного стабилизатора напряжения LM7805 (КРЕН5), если схема питается напряжением в 5 вольт, и регулируемая нагрузка работает от такого же напряжения, а не от 12 вольт.
Для стабильности напряжения можно добавить керамические конденсаторы (на наглядной схеме выделены квадратом салатового цвета) — 0,33 микроФарад (334) на вход 7805, и 0,1 микрофарад (104) на выходе 7805.
Используемая нагружаемая мощность будет ограничена полевым (MOSFET) транзистором.
Прошивка
Почитав комментарии на оригинальной странице, увидел несколько комментариев об ошибке — надо вначале держать кнопку 30 секунд, чтобы ШИМ запустился, что конечно же ну очень долго.
Так как исходники прилагались — решил исправить ошибку и добавить индикацию работы светодиодами нагляднее. Исходники, к моему сожалению оказались на BascomAVR.
Пришлось его скачать и открыть исходник в нем. Исправив ошибку с ожиданием в 30 секунд — решил проверить и залить прошивку. Но прошивка не захотела литься, подумав что это ошибка компилятора BascomAVR, было решено написать свой код для ATTiny13 на Си в Atmel Studio 7, конечно с сохранением оригинальной схемотехники, чтобы было можно только лишь залить прошивку и ничего не переделывать на печатке.
Написал тестовый код в Atmel Studio, скомпилировал прошивку, заливаю в attiny13 – опять ошибка:
mismatch 0x000000
Ошибка оказалась не в средах разработки, а в программе для прошивки мк, конкретно в моем случае в eXtreme Burner AVR, для того, чтобы исправить данную ошибку необходимо открыть файл
C:\Program Files\eXtreme Burner – AVR\Data\chips.xml
Найти ATTiny13 и между тегами 64 Вместо 64 написать 32 – после этого ATTiny13 начал шиться без проблем.
Спустя несколько дней программа была написана.
Что изменено и добавлено в прошивку:
+ Не нужно удерживать кнопку на протяжении 30 секунд
+ Добавлено 8 значений ШИМ вместо 7
+ Добавлена индикация включения.
+ Сделана наглядная индикация режима ШИМ .
+ Добавлено автосохранение значения ШИМ (по умолчанию выключено)
Индикация включения — при включении очень быстро и с реверсом перельются все три светодиода.
Переключение режимов осуществляется нажатием на кнопку, действует циклически.
Файлы прошивки находятся в конце статьи.
При возникновении дополнительных вопросов по работе с кодами для микроконтроллеров , вам может помочь статья:
Как написать код для AVR, программирование микроконтроллеров Atmel AVR на Си
Пояснения по работе устройства с новой прошивкой
Режимы работы:
0 — Все светодиоды выключены, Значение ШИМ — 0 (0%)
1 — Моргает светодиод 1, ШИМ — 32 (12%)
2 — Моргает светодиод 2, ШИМ — 64 (25%)
3 — Моргает светодиод 3, ШИМ — 96 (37.6%)
4 — Все светодиоды переливаются, ШИМ — 128 (50%)
5 — Горит светодиод 1, ШИМ — 160 (62.7%)
6 — Горит светодиод 2, ШИМ — 192 (75.2%)
7 — Горит светодиод 3, ШИМ — 224 (87.8%)
8 — Все светодиоды моргают, ШИМ — 255 (100%)
ШИМ — 0 (0%) — питание на «регулируемом устройстве» отсутствует, например, паяльник не греется.
ШИМ — 255 (100%) — полная мощность работы «регулируемого устройства».
Для включения автосохранения значения ШИМ необходимо удержать кнопку в течении 3-х секунд, для отключения — осуществить тоже самое.
При этом при включении автосохранения на 1,5 секунды загорится светодиод 1.
При отключении — на 1,5 секунды загорится светодиод 3.Удерживать кнопку можно в любом режиме, но лучше это делать в режиме 0- так будет нагляднее.
Не стоит забывать, что при включенном автосохранении каждый раз, при нажатии на кнопку записываются данные в EEPROM, ресурс записи EEPROM в Atmel AVR — 100 000.
Программирование ATTiny13 микроконтроллера
- Для заливки прошивки в ATTiny потребуется: USB ASP Программатор микроконтроллеров ATmega AVR.
- Программа eXtreme Burner AVR.
Необходимо поставить фьюз на работу от внутреннего тактового генератора на 9,6 Мгц
Т.к. я пользуюсь eXtreme Burner AVR то во вкладке Fuse\Bits записываю такие байты вместо выставления галок(в других программах-прошивальщиках галки):
Младший байт(Low Byte\Fuse) – 7A
Старший байт (High Byte\Fuse) – EB
Для того, чтобы знать какие галки ставить в других программах, чтобы микроконтроллер работал на частоте 9.6Мгц , можно использовать данный сайт:
homes-smart.ru/fusecalc/?prog=avrstudio&part=ATtiny13A
Слева вверху, где написано Байты конфигурации вводим – 7A в окошечко LOW
и EB в окошечко HIGH – получаем указание на то, где следует поставить галки.
Собранное в корпус устройство ШИМ с вынесенной кнопкой:
(Принципиальная схема и печатная плата имеется на приведенном выше сайте.)
Плата ШИМ, упакованная в корпус от другого устройства и подключенный к ней паяльник.
Файлы прошивки в формате HEX:
Оригинальная, скомпилированная из приведенных ниже исходников:
Прошивка с более высокой частотой (Не тестировалась на реальной схеме!):
Прошивка по просьбе одного из пользователей нашего сайта, частота ШИМ — около 2,3 килоГерц:
В данной прошивке всего три режима
0 — Выключено
1 — ШИМ 80%, светится светодиод 1
2 — ШИМ 90%, светится светодиод 1,2
3 — ШИМ 100%(Постоянное питание), светится светодиод 1, 2 и 3
Исходник с подробными комментариями также прилагается, можно изменить под свои нужды:
/* /* * SolderPWM.c * * Created: 05.11.2017 23:33:14 * Author LampCORE.ru: */ #define F_CPU 9600000UL //частота процессора 9,6 Мгц #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #include <avr/eeprom.h> //макросы для включения, выключения светодиодов //низкий уровень — на ножке 0 вольт, высокий уровень — на ножке 5 вольт #define LED1_OFF PORTB &= ~(1<<PB4); //Низкий уровень ножки PB4 #define LED2_OFF PORTB &= ~(1<<PB3); //Низкий уровень ножки PB3 #define LED3_OFF PORTB &= ~(1<<PB2); //Низкий уровень ножки PB2 #define LED1_ON PORTB |= (1<<PB4); //Высокий уровень ножки PB4 #define LED2_ON PORTB |= (1<<PB3); //Высокий уровень ножки PB3 #define LED3_ON PORTB |= (1<<PB2); //Высокий уровень ножки PB2 //Указатели для EEPROM uint8_t autosave_p EEMEM; uint8_t level_p EEMEM; //Переменная для выбора режима ШИМ uint8_t level=0; //volatile — чтобы компилятор не трогал эти переменные и не оптимизировал //Счетчики в прерывании //для мигания volatile uint8_t count=0; //для переливания 3х светодиодов volatile uint8_t count2=0; //счетчик удержания кнопки volatile uint8_t i=0; //переменная для события был_клик volatile uint8_t wasclick=0; //36 переполнений (36 раз происходит событие TCNT0>255 ) = 1 секунда // Прерывание по совпадению счетчика таймера с OCR0A // 9 600 000 Гц/Предделитель 1024 / 1000 = 9 375 Гц в секунду/255=36 прерываний //в секунду ISR (TIM0_COMPA_vect) { //инкремент счетчиков, две переменные, чтобы режимы //светодиодов мигания и переливания не зависили друг от друга count++; //если больше пол секунды if(count>18){count=0;} count2++; //если больше секунды if(count2>36){count2=0;} } //функция отключить все светодиоды void off_all_led() { LED1_OFF;LED2_OFF;LED3_OFF; } int main(void) { // Настраиваем порты ввода/вывода DDRB |= 1<<PB4;//Ножка PB4 как выход DDRB |= 1<<PB3;//Ножка PB3 как выход DDRB |= 1<<PB2;//Ножка PB2 как выход DDRB |= 0<<PB1;//Ножка PB1 как вход(кнопка) PORTB |= (1 << PB1);//Включаем подтягивающий Pull-UP резистор для ножки //PB1(вход-кнопка)(высокий уровень(+5Вольт)) DDRB |= (1 << PB0); //Ножка PB0 как выход(ШИМ) TCCR0A = (1 << COM0A1) | (1 << WGM00); //выбор ШИМ с фазовой коррекцией TCCR0B = 0x05; //Предделитель — 1024 и старт таймера TCNT0 = 0; // Сброс счетчика прерываний(0-255) OCR0A=0; //Выбор Значения ШИМ TIMSK0=0x04;//Разрешить выполнение прерываний по совпадению в OCR0A sei();// Разрешить глобальные прерывания //Индикация включения, быстрое переливание светодиодов с инвертированием LED3_ON; _delay_ms(45); LED3_OFF; LED2_ON; _delay_ms(45); LED2_OFF; LED1_ON; _delay_ms(45); LED1_OFF; LED2_ON; _delay_ms(45); LED2_OFF; LED3_ON; _delay_ms(45); LED3_OFF; //переменная для хранения значения автосохранения включено\выключено uint8_t autosave; //считать значение автосохранения с EEPROM по адресу в &autosave_p autosave=eeprom_read_byte(&autosave_p); //если сохранение включено то режим ШИМ равен значению из EEPROM if (autosave==1) { level=eeprom_read_byte(&level_p); //Проследовать сразу на метку handler_button, где //сразу инициируется режим, считанные из EEPROM goto handler_button; } //Бесконечный цикл while(1) { //Если на PB1 низкий уровень(если кнопка нажата) if( ! (PINB & (1 << PB1))) { //Событие был_клик произошло wasclick=1; //инкремент счетчика нажатия кнопки до i=255 if (i!=255){ _delay_ms(83); i++; //если прошло 3 и более секунд if (i>=36) { //События был_клик НЕ было wasclick=0; //если автосохранение включено — отключить, записать // это в EEPROM if (autosave==1) { eeprom_write_byte(&autosave_p,0); autosave=0; } //если автосохранение выключено — включить, записать в EEPROM else { eeprom_write_byte(&autosave_p,1); autosave=1; } //если автосохранение включено включить светодиод 1 на 1,5 секунды if (autosave==1) { LED1_ON; _delay_ms(1500); LED1_OFF; //перейти сразу к обработке переменной level goto handler_button; } else //иначе, если автосохранение выключено включить светодиод 3 на //1,5 секунды { LED3_ON _delay_ms(1500); LED3_OFF; //перейти сразу к обработке переменной level goto handler_button; } i=0;//сброс счетчика после долгого нажатия //перейти сразу к обработке переменной level goto handler_button; }//i>=36 }//i!=255 }//! (PINB & (1 << PB1)) // Выполнять только, если кнопка отпущена т.е. выполняется, только, если wasclick=1 //(событие был_клик произошло) if ( (PINB & (1 << PB1))&&wasclick==1) { //события был_клик не было wasclick=0; _delay_ms(83); //Точные числа перескакивают, в узкий диапазон попасть трудно, поэтому от 2х до 12, // 2*83+83=249 миллисекунд //если кнопка была нажата (+83миллисекунды пауза внутри условия) 83*2 миллисекунд if (i>=2&&i<=12) { // повысить режим level++; //если режим превышает 7 сделать режим 0 if(level>8){level=0;} //если включено автосохранение записать в EEPROM значение // режима if (autosave==1) { eeprom_write_byte(&level_p,level); } //метка обработки переменной level(режимов) handler_button: switch(level) { //каждому значению level — свое значение ШИМ и режим //светодиодов case 0:OCR0A=0;off_all_led();break; case 1:OCR0A=32 ;off_all_led(); break; case 2:OCR0A=64;off_all_led() ;break; case 3:OCR0A=96;off_all_led() ;break; //Если быстро нажать кнопку count2 не сбросится и какой-либо // светодиод будет гореть //некоторое время вместо того, чтобы погаснуть — переливания не // будет //принудительно сбросим count2 case 4:OCR0A=128;off_all_led();count2=0;break; case 5:OCR0A=160;off_all_led() ; LED1_ON; break; case 6:OCR0A=192;off_all_led() ; LED1_ON;LED2_ON; break; case 7:OCR0A=224;off_all_led() ; LED1_ON;LED2_ON;LED3_ON; break; case 8:OCR0A=255;off_all_led();break; }//switch i=0;//сброс счетчика кнопки }//i>=2 }//release отпущено //Мерцания светодиодов //Каждому значению ШИМ — свой режим светодиодов switch(level) { case 0:;break; case 1: //count прибавляется на 9 за пол секунды if(count>=0&&count<9){LED1_ON;} if(count>9&&count<=18){LED1_OFF;} ; break; case 2: // if(count>=0&&count<9){LED2_ON;} if(count>9&&count<=18){LED2_OFF;} ; break; case 3: // if(count>=0&&count<9){LED3_ON;} if(count>9&&count<=18){LED3_OFF;} ; break; case 4: //переливания, свой счетчик count2 if(count2>=0&&count2<6) {LED3_OFF;LED2_OFF;LED1_ON} if(count2>6&&count2<=12){LED1_OFF;} if(count2>=12&&count2<18){LED1_OFF;LED3_OFF;LED2_ON} if(count2>18&&count2<=24){LED2_OFF;} if(count2>=24&&count2<30){LED2_OFF;LED1_OFF;LED3_ON} if(count2>30&&count2<=36){LED3_OFF;} ;break; case 5: ;break; case 6:;break; case 7:;break; case 8: if(count>=0&&count<9){LED1_ON;LED2_ON;LED3_ON;} if(count>9&&count<=18){LED1_OFF;LED2_OFF;LED3_OFF;} ;break; } }//while }//main
Добавить комментарий