Содержание
Урок 1. Первый проект
Урок 2. Управление кнопками
Урок 3. Подключение LCD
Урок 4. Использование ШИМ
Урок 5. Таймеры
Урок 6.1. Статическая индикация
Урок 6.2. Динамическая индикация
Урок 7.1. Генерация звука
Урок 7.2. Генерация звука. Продолжение
Урок 8.1. Передача данных через UART
Урок 8.2. Передача данных через UART. Продолжение»
Урок 9. Передача данных через SPI
Урок 10. Изучение АЦП. Простой вольтметр
Урок 11. Получение синуса при помощи ШИМ
Урок 12. Измерение температуры
Урок 13. Внешние прерывания.
Урок 14. Использование отладчика
Урок 15.1. Управление инкрементальным энкодером
Урок 15.2. Управление громкостью, при помощи энкодера
Урок 16. Управление RGB светодиодом
Урок 17. Использование ИК
Урок 18.1. Знакомство с графическим дисплеем
Урок 18.2 Вывод изображения на графический дисплей
Урок 18.3 Вывод русскоязычного текста
Урок 19. Формирование сигнала, при помощи ЦАП (R2R)
Урок 20. Опрос матричной клавиатуры
Урок 21. Сторожевой таймер
Урок 22.1 Воспроизведение wav. Введение.
Урок 22.2 Воспроизведение wav. Продолжение.
Урок 23.1 Работа с внешней памятью
Урок 23.2 Работа с файловой системой Fat

btnНа первом уроке мы научились подавать напряжение ножкой микроконтроллера. Теперь нужно научиться управлять микроконтроллером без перепрошивки.

Зачем это нужно? Например, вы сделали часы на микроконтроллере, нужно выставить время, но очень не удобно каждый раз перепрошивать, когда собьется время. Намного удобнее пользоваться кнопками, например, одной менять часы, другой минуты.

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

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

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

#include <mega8.h>
#include <delay.h>
 
void main(void)
{
 
PORTB=0x02;
DDRB=0x01;
 
while (1)
{
 
if(PINB.1==0)
{
PORTB.0=1;
delay_ms(100);
PORTB.0=0;
delay_ms(100);
}
 
};
}

Как мы видим, по сравнению с первым уроком изменилась настройка порта

PORTB=0x02;
DDRB=0x01;

Подробнее о том что значат данные строки можно почитать тут

Также появилась новая строчка

if(PINB.1==0)
{}

данную строчку нужно читать так — если на ножке 1 порта В подключили землю (0 потенциал), то выполнить код в фигурных скобках. В нашем примере это код из первого урока. Если кнопка не замкнута, то ничего не делать. Промоделировать можно в Proteuse.

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

Архив с прошивкой и файлом протеуса доступен тут

Update1: Зачем нужна подтяжка порта?
У входа мк большое сопротивление, если будут течь даже микротоки вызванные помехами, то по закону Ома U=R*I это может привести к тому, что на входе появится лог 1. Чтобы не было таких проблем в AVR микроконтроллерах можно подключить ножку к плюсу питания, через подтягивающий резистор. В этом случае даже, логика работы меняется наоборот — но если появится помеха, нам это не важно, ведь у нас на входе уже логическая единица.

Почему подключение через резистор? Допустим мы подключили вход к плюсу напрямую без резистора. Когда кнопка сработает, она притянет вход к земле, поэтому на входе будет короткое замыкание между + и землей. Если же стоит резистор, то при замыкании кнопки с одной стороны он так и останется подключен к +, а со второй стороны на нем появится земля от кнопки. Через резистор потечет ток, но его величина будет не такой большой.
btn_pup

Update2: Добавлен тест, в котором вы можете проверить на сколько хорошо вы усвоили материал урока

This movie requires Flash Player 9

235 комментариев: Урок 2. Управление кнопками в AVR

  • Спасибо, так я пробовал, но тогда мину будет постоянно мигать, мне бы их разделить хочу сделать шуп который определяет + и — 🙁 Не натолкнете на правильный путь? Может я не той дорогой пошел?

  • Тогда логичнее АЦП использовать и когда щуп будет висеть в воздухе, на нем должно быть половина питания, за счет делителя.

  • подскажите пожалуста как сзелать задержку по if надо чтоб если кнопка нажата 20 секунд выполнился код если нет то другой,
    if(PINB.0==1) надо чтоб железо ппределила 20секунд нажата или нет
    {
    PORTB.1=1
    }
    else
    {
    PORTB.2=1
    }
    зарание спасибо

  • Настраиваем таймер на прерывание раз в секунду. В прерывании увеличиваем переменную на единицу. В теле условия запускаем бесконечный цикл до тех пор, пока не отпустится кнопка. После отпускании кнопки проверяем переменную счёта секунд. Если больше или равно 20, значит удержали и выполняем первое условие, а если меньше то второе.

  • у меня тини 13 и не могу его настроить если можно пожалуста кусок кода

  • Нет. Это на столько банальная задача, что решать я за вас ее не буду. Если вы не научитесь сами искать ответ, то никогда не научитесь программировать МК. Я только последовательно распишу как нужно действовать.
    1. Идем на сайт http://www.atmel.com
    2. В верхнем левом углу есть поиск. Вбиваем tiny13
    3. Появится куча ссылок, одна из которых ATtiny13. Жмем на нее.
    4. Перейдя в раздел ATtiny13 видим два ПДФ файла. Нам нужен ATtiny13 Complete
    5. Качаем его и открываем.
    6. Самая первая страница, Раздел Peripheral Features
    7. One 8-bit Timer/Counter with Prescaler and Two PWM Channels
    8. Ага, наш контроллер имеет один 8-и битный таймер с претделителем и двумя ШИМ.
    9. Кнопка. Чтобы МК не зависал на 20 секунд пока опрашиваем кнопку, лучше повесить ее на внешнее прерывание.
    10. Идем в раздел №9 interrupt
    11. Ага. Второй вектор внешнее прерывание INT0. Идем в начало файла
    12. Смотрим на какой ноге висит INT0. PB1. Чудненько. Вешаем на нее кнопку.
    13. Я давно не работал в CVAVR но как сейчас помню, что там есть генератор кода.
    14. В визарде настраиваем прерывание от ноги PB1 по любому событию.
    15. Настраиваем таймер на срабатывание раз в 1 мс. Такое время связано с тем что таймер 8-и битный и к сожалению секунду не получится получить.
    16. Создаем байтовую. переменную time. В ней будут хранится секунды.
    17. Создаем интовую переменную count. В ней будем хранить мс
    18. Создаем байтовую переменную flags. Это будет 8 флагов.
    20. В обработчике прерывания внешнего события смотрим что на ноге. (нажатие кнопки пусть будет 1) Если 1 взводим первый разряд переменной flags. Говорим что кнопка нажата. Так же взводим второй разряд, говорим что кнопка удерживается.
    21. Если кнопку отпустили, то в сбрасываем первый разряд в переменной flags. Говорим о том что кнопку отпустили, но при этом второй разряд говорит что кнопку нажимали.
    22. В теле обработчика прерывания таймера проверяем взведен ли второй бит в переменной flags. Если взведен, то смотрим первый разряд. Если 0, то сбрасываем третий разряд в переменной flags и обнуляем переменные time и count. Если первый разряд в 1, то прибавляем 1 к cout и смотрим, не равна ли она 1000. Если равна, то прибавляем 1 к time и проверяем не равен ли time 20. Если равен, то взводим третий разряд переменной flag.
    23. В основном цикле программы смотрим на флажки в переменной flags. Если третий разряд в 0, а второй в 1, то выполняем условие кратковременного нажатия на кнопку. Если в третьем разряде 1 и во втором тоже 1, то выполняем задание при удержанной кнопке больше 20 секунд.
    Если оба разряда в 0, то нажатие не происходило.
    Все. Теперь слежка за кнопкой переходит на плечи прерываний и тем самым не тупит МК.
    Как настроить таймер читаем урок 5.
    Как настроить внешнее прерывание читаем урок 13

    ПС
    Если все же возникнут трудности, то помогу. Присылайте куски кода где затыки и вместе разберемся.

  • Добрый вечер Алексей спасибо ,вы показали путь с прерыванием чуть получилась даташит погуглил попробывал вроде понял где заморочка
    // External Interrupt 0 service routine
    interrupt [EXT_INT0] void ext_int2_isr(void) в визарде _int0 поставил2 ечку порт2 загорелся
    {
    if(PINB.1==1)
    {PORTB.2=1;}

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

  • На какой частоте работает МК?

  • Вот вопрос к стати в визарде я выбираю 8 Мгц но фюз биты заводские 1Мгц то выходит МК работает на1 Мгц верно?

  • верно, настройки визарда влияют лишь на расчеты скоростей в программе и на длительности задержек, но они никак не завязаны на фьюзы

  • Это прикол? Идем в даташит на страницу 25 и вникаем в раздел 6.2.2 Откуда 1 МГц взялся?

  • По дефолту mega8 идет с фьюзами на 1МГц, просто код визард сбивает с толку. Там частота это как дефайн, относительно которого расчитываются настройки таймеров, uart, spi, delay и т.п. времязависимые величины. Поэтому если фьюзы не будут соответствовать, этому дефайну, то делеи будут в 8 раз больше, а интерфейсы не будут работать вообще.

  • Я про восьмую мегу знаю, но речь идет о Tiny13.

  • а как понять в визарде тини 13 ставляю 8Мгц фюз по дефалту 9,6мгц если ставит delay_ms(1000) это почти 1 секунда?

  • Вы меня либо не понимаете, либо не хотите понимать. Я же писал, раздел 6.2.2 страница 25, таблица 6-4. Черным по белому написано CKSEL1…0 (10) -> 9600000 Гц, CKSEL1…0 (01) -> 4800000 Гц. Выбрали нужное, а в CVAVR во вкладке «ЧИП» вписывает эту же частоту. Либо 9600000, либо 4800000. После этого все задержки начнут работать. И потом нафик вам delay_ms()? Уж если запустите таймер на прерывание раз в 1 мкс, то софтверный делей ваще будет не нужен.

  • Алексей не обижайтесь вот вы вашим гневом мне дали опять подсказку .Я пока не могу использовать таймер чтоб избавится от delay_ms(),вот прошу попоши не обязательно тини 13 лутше мега8 для любова из них скажите с чего начять ,

  • А куда мой ответ делся? Все пропало! только писал! 😯

  • Алексей давайте разберемся с таймером

  • В спам попало, краем глаза глянул либы, могу дать ссылку, где они есть готовые. Виктор, что же Вы над человеком издеваетесь.

  • Я в основном пишу под не стандартные девайсы. Сейчас доделываю либу для работы с датчиком давления от жигуля. Очень удобно, он может измерять газы и не едкие жидкости от 0 до 8 атм. Такой либы нет не у кого. А Виктор не издевается. Мне кажется он просто не хочет ничего делать и добивается того, что кто-то за него все напишет.

  • НЕТ мне не нужны чужие написанные программы я сам хочю научится их писать . просто не пойму как и с чего начять .Вот вы все супер пупер все знаеете но не знаеете как можно обяснить человеку не знаюшиму чтоб для него чють стало легче вместо того чтоб обвиняли в издевателстве и довали сылки на другой софт посаветовали бы чтоб изучял даташит правда он на англиском что затрудняет .Алексей вот по прерыванию никто не сказал чтобы оно работало interrupt [EXT_INT0] void ext_int0_isr(void) <> инт указывает на канкретную ножку . Также стаймером. А такой датчик давления уже сушиствует могу дать сылочку если хочеш ,мерит давления вольт температиру ….

  • Да и еще для начинаюших что вы посаветуете визард или атмел студио?

  • Виктор. А в чем там проблемного? EXT_INT0 — это просто веяние по названию вектора прерывания в Визарде. Если опять же посмотреть в даташит на тини13 на страничке 44 в таблицу 9-1, то можно увидеть что данный вектор стоит под адресом 2. И не надо иметь сверх знания для того чтобы понять что EXT_INT0 и 2 это одно и тоже. А про ножку я писал аж в самом начале нашей дискуссии. По поводу IDE ЛИЧНО МОЕ МНЕНИЕ!!!! я за студию. Но я ни коем образом не склоняю к ней кого-либо. Я всегда говорил, что выбор IDE равносилен в выборе религии. Кому что по душе. И еще одно важное замечание. Если возник вопрос, то ненужно его сумбурно выкладывать как перепугавшееся барышня. Пишите конкретно, что и где непонятно. На вопрос с чего начать, я уже давал ссылки на уроки. В них все просто подробнейше разжевано и причем на русском языке. Если вам что-то не понятно в каком-либо уроке, то задайте вопрос именно по этому месту. Если непонятно как работает обработчик прерывания, то и спросите про него, а не с чего начать. Начинать надо с прочтения тех двух уроков внимательно. Уверяю очень много вопросов отпадут сами собой и будете даже смеяться над своими вопросами. Я это уже проходил. Сначала естественно паника. Но ненужно паниковать.

  • На счет датчика интересно взглянуть.

  • даыте адресок я вам скину исходник ,работа впротеусе и пошивку

  • отправил поже наыду статью автора

  • Вот пвтарил кусочек кода Админа не получяется почему?
    // Timer1 output compare A interrupt service routine
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
    s++;
    if(s>10)
    {
    s=0;
    }
    TCNT1=0;
    }

    while (1)
    {

    if(s>5)
    {
    PORTC.1=1;
    }
    }

  • получилась 😀

  • Подскажите пожалуйста как реализовать на Codevision:
    нажатие кнопки с удержанием(зажатие) = увеличение переменной,
    одно короткое нажатие + нажатие с удержанием = уменшение переменной.
    Вот мой страшный код, который работает:
    if((PINB.3==1)&(np!=21)){np+=1; delay_ms(10);}
    if(PINB.3==0){np=0;}
    if(np!=0){npb=np;}
    if(PINB.3==1){sp=0;}
    if((PINB.3==0)&(sp!=21)){sp+=1; delay_ms(10);}
    //if(sp==1){lp=1;}
    if((sp>20)&(npb20)&(npb>=15)&(jaga!=0)) //уменшать пока не достигло минимума
    { //нажатие с удержанием
    j-=1; //увеличиваем заполнение
    delay_ms(10); // задержка 10 мс.
    }
    Но нужно еще притулить два коротких — на изменение другой переменной, и одинарное короткое нажатие для входа\выхода в спящий режим.

  • Прошу прощения, вот код
    if((PINB.3==1)&(np!=21)){np+=1; delay_ms(10);}
    if(PINB.3==0){np=0;}
    if(np!=0){npb=np;}
    if(PINB.3==1){sp=0;}
    if((PINB.3==0)&(sp!=21)){sp+=1; delay_ms(10);}
    //if(sp==1){lp=1;}
    if((sp>20)&(npb20)&(npb>=15)&(jaga!=0)) //уменшать пока не достигло минимума
    { //нажатие с удержанием
    j-=1; //увеличиваем заполнение
    delay_ms(10); // задержка 10 мс.
    }

  • код полностью не добавляется почемуто: только начало и конец.

  • почитайте про таймер
    http://avr-start.ru/?p=414
    после слов расчет работы таймера
    http://avr-start.ru/?p=3983

  • Виктор. А сколько шума было. Только я так и не понял, программа писалась для Mega8? Просто в том архиве только HEX и я не смог посмотреть исходник.

  • При использовании контроллера типа Atmega 128 при попытке «загнать» в порт «F» или «G» значение типа «PORTF.0=1;» компилятор CodeVisionAVR выдает ошибку типа: Error: : the first argument of the ‘.’ operator must be of ‘struct’ or ‘union’ type. С портами «A»,»B»,»C»,»D»,»E» подобной проблемы нет. Если вас не затруднит поясните, почему так происходит?

  • Есть такое, лечится только так:
    PORTF |= (1<<3); //установить 3 бит порта F PORTF &= ~(1<<3); //сбросить 3 бит порта F

  • Спасибо огромное за подсказку!!!!!!

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

  • всем привет нашел тиньку 12 🙄 решил прошивку в протеусе испытать, при нажатии кнопки ошибка… вот прошивка :

    #include
    #include

    void main(void)
    {

    PORTB=0x08;
    DDRB=0x01;

    while (1)
    {

    if(PINB.1==1)
    {
    PORTB.3=1;
    delay_ms(10);
    PORTB.3=0;
    delay_ms(100);
    }

    };
    }

  • пишите ошибку, телепатов нет

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика