Помогите начинающему (ATMega328p, Nano v3, Си)

Тема в разделе "Микроконтроллеры AVR", создана пользователем MadHorse, 25 дек 2016.

Метки:
  1. MadHorse

    MadHorse Нуб

    Коллеги
    начинаю делать свои первые шаги.
    Простая схема (см. приложение)

    есть код "
    Код (C++):
    #include <avr/io.h>
    #include <stdint.h>
    #include <util/delay.h>

    #define Port_c PORTC
    #define RegC0  PC0

    int main(void)
    {
        //initial setting port D (connect button)
        DDRD = ~(1 << PD0); //enable input
        PORTD  |= _BV(PD0);
        //initial setting port C (connect led)
        DDRC |= _BV(PC0); //on eixt
        Port_c &= ~ _BV(PC0);  
        while(1)
        {          
            if((PIND & _BV(PD0)) == 1)
            {
                _delay_ms(25); //leveling press button
                Port_c ^= (1<<PC0); //led on/off
            }              
        }
    }
    ...
    Цель: при нажати лед должне включиться при последующием выключиться
    В виртуальной модели (в протеусе) работает, а в физической, лед просто быстро мерцает. Реакция на кнопку- замирает не надолго или вообще никак. На вид все логично, но..., Помогите разобраться где косяк?
     

    Вложения:

  2. rkit

    rkit Гуру

    У вас и написано мерцание каждые 25 мс. Если вы только учитесь программировать, то пишите на ардуино, а не авр.0 Зачем себе задачу усложнять.
     
  3. MadHorse

    MadHorse Нуб

    Спасибо, но
    1. ардуино мне не итересно (и просил помощи, а не совета)
    2. т.е условие нажатие кнопки вы отбрасываете (бит изменятся только при нажатии кнопки)

    возможно стоит уточнить : мерцает в любом случае была нажата кнопка или нет
     
    Последнее редактирование: 25 дек 2016
  4. AlexU

    AlexU Гуру

    Пин с кнопкой подтягиваете к питанию:
    Код (C++):
    PORTD  |= _BV(PD0);
    и при нажатии кнопка замыкается на питание. Учитывая то, что подтягивающий резистор в микроконтроллере не имеет точного номинала, вполне вероятно, что в паре с резистором R1 они создают такое падение напряжения на входе, что контроллер распознаёт логическую "1". Вот светодиод и моргает, не смотря на состояние кнопки. Один из вариантов -- убрать резистор R1 и кнопку замыкать на землю.

    UPD: логика программы не соответствует: "Цель: при нажати лед должне включиться при последующием выключиться"
    Её (программу) надо переписать...
     
    Последнее редактирование: 26 дек 2016
    MadHorse нравится это.
  5. MadHorse

    MadHorse Нуб

    Спасибо,
    эмпирическим путем установил, что в независимости настроек порта D (при отсутствии каких либо подключений)
    данное условие
    Код (C++):
    if((PIND & (1<< PD0)) == 1)
    всегда истина
    хм.. похоже где-то, что-то пропустил...
     
  6. MadHorse

    MadHorse Нуб

    хм похоже нашел, но пока проверить нет времени
     
  7. AlexU

    AlexU Гуру

    Думаю стоит немного пояснить. Среди множества способов подключения кнопок к контроллеру, можно выделить два самых простых:
    1. нога контроллера подтягивается к питанию (либо внешним резистором, либо внутренним), а кнопка при нажатии эту ногу замыкает на землю. Тогда при отжатой кнопке на ноге будет логическая "1", а при нажатой -- "0";
    2. нога контроллера подтягивается к земле (в случае с AVR только внешним резистором, т.к. подтяжки к земле в контроллере нет). Соответственно при отжатой кнопке на ноге будет "0", а при нажатой -- "1".
    Теперь, что касается кода и схемы из первого поста:
    если из кода убрать включение внутренней подтяжки к питанию --
    Код (C++):
    PORTD  |= _BV(PD0);
    -- то получим второй вариант (при нажатии кнопки, на ноге будет логическая "1"). В соответствии с логикой кода, если нажать и удерживать кнопку можно увидеть мерцающий светодиод. При отпускании кнопки светодиод мерцать перестанет и будет либо светить, либо погаснет -- как повезёт.

    У AVR-ок есть одна особенность, о которой не все знают (или забывают) -- менять состояние пина можно записывая "1" в соответствующий бит регистра PINx. Т.е. в Вашем случае конструкцию:
    Код (C++):
    Port_c ^= (1<<PC0); //led on/of
    можно заменить на:
    Код (C++):
    PINC = (1<<PC0); //led on/of
    Да-да, регистр PINx, который обычно считается "входным" и его только "читают", может использоваться для смены состояния битов порта PORTx и соответственно состояний пинов контроллера.
     
    MadHorse нравится это.
  8. MadHorse

    MadHorse Нуб

    Огромное спасибо, 1й уже как бы понял (надо практикой закрепить) вы еще дополнительно разложили. А случае с PINC не будет конфликта? По идее регистр DDRх определяет, на вход/выход будет работать порт.
     
  9. AlexU

    AlexU Гуру

    Не зависимо от значения регистра DDRx (независимо от того как настроены пины -- на "вход" или "выход") запись "1" (и только "1") в те или иные биты регистра PINx будет менять состояние соответствующих битов в регистре PORTx. Если пин настроен на "выход" то будет меняться уровень на пине. Если на "вход", то будет включаться/отключаться подтяжка к питанию.
     
    MadHorse нравится это.
  10. MadHorse

    MadHorse Нуб

    Большое спасибо