Как правильно делать маски на порты?

Обсуждаем контроллеры компании Atmel.
Ответить
Встал на лапы
Аватара пользователя
Сообщения: 118
Зарегистрирован: Вт апр 21, 2020 07:44:24
Откуда: Сумы, Украина

Сообщение Alek_von_German »

Доброго здравия, господа.
Роясь в литературе всякой по AVR Atmel, в поисках ответа на всяческие вопросы, заметил, что везде на всяких форумах/книгах присутствует один и тот же сценарий,
Берем кнопку1 и цепляем её на пин0 порта В, далее берем светодиод и цепляем его на ножку порта С. Это понятно. НО, если мне нужно выделить часть порта на кнопки, а вторую часть порта будет иметь прерывание от таймера- как в таком случае быть? Стандартное DDRB|=0x0f; PORTB|=0xf0;- не работает, точнее из-за того, что двумя пинами дергает таймер, остальные не включаются как входы и не подтягиваются к плюсу, они просто висят. Как обойти такое?
Хочется всё и сразу, а получаешь нихрена и постепенно...
Реклама
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1314
Зарегистрирован: Пт ноя 27, 2009 19:47:13
Откуда: Казань

Сообщение НАПАЛМ »

В таких тонкостях архитектуры не силен, что таймер целый потр забивает, но если действительно так, что первый костыль, приходящий на ум, это дерганье ногами таймера в прерывании таймера, и всеми остальными уже как вам нужно.
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18677
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Alek_von_German писал(а):Стандартное DDRB|=0x0f; PORTB|=0xf0;- не работает, точнее из-за того, что двумя пинами дергает таймер, остальные не включаются как входы и не подтягиваются к плюсу, они просто висят.
все работает, если делать правильно. поскольку мы не видим, как делаете вы, вам придется самостотельно искать ошибку
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Полагаю речь идет о
Спойлер

Код: Выделить всё

#define ClearBit(reg, bit)       reg &= (~(1<<(bit)))
//пример: ClearBit(PORTB, 1); //сбросить 1-й бит PORTB

#define SetBit(reg, bit)          reg |= (1<<(bit))	
//пример: SetBit(PORTB, 3); //установить 3-й бит PORTB

#define BitIsClear(reg, bit)    ((reg & (1<<(bit))) == 0)
//пример: if (BitIsClear(PORTB,1)) {...} //если бит очищен

#define BitIsSet(reg, bit)       ((reg & (1<<(bit))) != 0)
//пример: if(BitIsSet(PORTB,2)) {...} //если бит установлен

#define InvBit(reg, bit)	  reg ^= (1<<(bit))
//пример: InvBit(PORTB, 1); //инвертировать 1-й бит PORTB
Реклама
Эиком - электронные компоненты и радиодетали
Встал на лапы
Аватара пользователя
Сообщения: 118
Зарегистрирован: Вт апр 21, 2020 07:44:24
Откуда: Сумы, Украина

Сообщение Alek_von_German »

[uquote="ARV",url="/forum/viewtopic.php?p=3885804#p3885804"]
Alek_von_German писал(а):Стандартное DDRB|=0x0f; PORTB|=0xf0;- не работает, точнее из-за того, что двумя пинами дергает таймер, остальные не включаются как входы и не подтягиваются к плюсу, они просто висят.
все работает, если делать правильно. поскольку мы не видим, как делаете вы, вам придется самостотельно искать ошибку[/uquote] Хочется делать всё правильно, но получается как получается...
вот куски кода
Спойлер

Код: Выделить всё

ISR (TIMER1_COMPA_vect)
{

    sec++;                          // увеличиваем счетчик секунд на 1
  
    if (sec>10)                     //если счетчик секунд перешел через 59
    {
        sec=0;                       // сбрасываем счетчик секунд в 0
                                 // увеличиваем счетчик минут
        display--;                      // уменьшаем значение в переменной дисплея
        if (display<0) display=0;       // если на дисплее 0-ниже не опускаемся
        if (display==0)
        {
        PORTD|=(1<<5);
        }
        else PORTD&=~(1<<5);
    }

}
Спойлер

Код: Выделить всё

void start (void)
{
    
    TCCR1B|= (1<<CS12) | (1<<CS10);      // деление частоты на 64 = 15625
    TIMSK1|= (1<<OCIE1A);                 // разрешаем прерывание при совпадении
    OCR1A=100;//
    TCNT1 = 0;
    TCCR1A |= (1<<WGM12);                // сброс при совпадении
    
    sei();//
    
}
Спойлер

Код: Выделить всё

ISR (TIMER1_COMPA_vect)
{

    sec++;                          // увеличиваем счетчик секунд на 1
  
    if (sec>10)                     //если счетчик секунд перешел через 59
    {
        sec=0;                       // сбрасываем счетчик секунд в 0
                                 
        display--;                      // уменьшаем значение в переменной дисплея
        if (display<0) display=0;       // если на дисплее 0-ниже не опускаемся
        if (display==0)
        {
        PORTD|=(1<<5);
        }
        else PORTD&=~(1<<5);
    }

}
Спойлер

Код: Выделить всё

ISR(TIMER2_OVF_vect)
{
    
    PORTB = 0xFF;                       // Гасим все разряды
    PORTC= (1 << segcounter);              // Выбираем следующий разряд
    
    
    switch(segcounter)
    {
        case 0:
        PORTB =~ (SEGMENTE[display % 100 / 10]);//десятки
        break;
        case 1:
        PORTB =~ (SEGMENTE[display % 10]);     //единицы
        break;
    }
    if(segcounter++ > 0) segcounter = 0;
}
И почему-то когда работает UART- тормозит таймер.
Хочется всё и сразу, а получаешь нихрена и постепенно...
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18677
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

смотрел ваш код 5 секунд, и заметил вот это: в одном прерывании вы делаете правильно

Код: Выделить всё

        PORTD|=(1<<5);
        }
        else PORTD&=~(1<<5);
  
а в другом уже иначе

Код: Выделить всё

   PORTC= (1 << segcounter);              // Выбираем следующий разряд
в первом случае вы именно маскируете нужные разряды, а во втором обновляете значение порта целиком.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Встал на лапы
Аватара пользователя
Сообщения: 118
Зарегистрирован: Вт апр 21, 2020 07:44:24
Откуда: Сумы, Украина

Сообщение Alek_von_German »

Угу. Я так уже думал. Но когда я делаю вот так PORTC|= (1 << segcounter); то на выходе обе ноги принимают значение 1-цы.
Хочется всё и сразу, а получаешь нихрена и постепенно...
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18677
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Alek_von_German писал(а):то на выходе обе ноги принимают значение 1-цы.
ну так это нормально... потому что вы неправильно делаете вообще. сначала надо подавить в ноль ту единицу, что сейчас, затем обновить порт с данными, затем вычислить номер единицы для новых данных, а уж затем активировать эту единицу.

Код: Выделить всё

ISR(TIMER2_OVF_vect)
{
   
    PORTB = 0xFF;                       // Гасим все разряды
    //PORTC= (1 << segcounter);              // Выбираем следующий разряд
   PORTC &= ~(1<<segcounter); // душим текущий разряд
   
    switch(segcounter)
    {
        case 0:
        PORTB =~ (SEGMENTE[display % 100 / 10]);//десятки
        break;
        case 1:
        PORTB =~ (SEGMENTE[display % 10]);     //единицы
        break;
    }
    segcounter ^= 1;
    PORTC |= 1<<segcounter; // активируем следующий разряд
}
Добавлено after 2 minutes 18 seconds:
но вообще говоря, сдвиг на переменное количество разрядов - это весьма затратная работа... лучше как-то обойтись без вот этого (1<<segcounter)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
OKF
Это не хвост, это антенна
Сообщения: 1405
Зарегистрирован: Вт июн 07, 2011 08:03:18

Сообщение OKF »

Терпеть не могу эти PORTB и т.п.! Конечно, это дело личное, но накой всё это, когда можно чуть выше:

Код: Выделить всё

void ledExe() {
  static uint8_t com;
  
  segment_off();                        //выключим всё
  com_off();
  keyExe();                             //опрашиваем кнопки
  switch (com) {                        //включим один общий
    case 0: com1_on(); break;
    case 1: com2_on(); break;
    case 2: com3_on(); break;
  }
  segment_on(segment[com]);             //включим сегменты
  if (++com >= COM_MAX)                 //следующая позиция  
    com = 0;                            
}
А остальное (аппаратнозависимое) выведи вне, макро (или инлайн):

Код: Выделить всё

#define segment_off()     ( DDRA  = B00000000, PORTA = B11111111)
#define segment_on(x)     ( DDRA  = B11111111, PORTA = ~(x)     )
Друг Кота
Аватара пользователя
Сообщения: 15595
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Сообщение BOB51 »

Иногда проще не состояние порта менять, а содержимое регистра направления.
Это ежли не требуется полный ток стекающий с 1...
:roll:
Встал на лапы
Аватара пользователя
Сообщения: 118
Зарегистрирован: Вт апр 21, 2020 07:44:24
Откуда: Сумы, Украина

Сообщение Alek_von_German »

ARV писал(а):ну так это нормально... потому что вы неправильно делаете вообще. сначала надо подавить в ноль ту единицу, что сейчас, затем обновить порт с данными, затем вычислить номер единицы для новых данных, а уж затем активировать эту единицу.

Код: Выделить всё

ISR(TIMER2_OVF_vect)
{
   
    PORTB = 0xFF;                       // Гасим все разряды
    //PORTC= (1 << segcounter);              // Выбираем следующий разряд
   PORTC &= ~(1<<segcounter); // душим текущий разряд
   
    switch(segcounter)
    {
        case 0:
        PORTB =~ (SEGMENTE[display % 100 / 10]);//десятки
        break;
        case 1:
        PORTB =~ (SEGMENTE[display % 10]);     //единицы
        break;
    }
    segcounter ^= 1;
    PORTC |= 1<<segcounter; // активируем следующий разряд
}
Добавлено after 2 minutes 18 seconds:
но вообще говоря, сдвиг на переменное количество разрядов - это весьма затратная работа... лучше как-то обойтись без вот этого (1<<segcounter)
Да, это работает. Беру себе в коллекцию для изучения. Спасибо большое!!! :beer:

Добавлено after 3 minutes 25 seconds:
[uquote="BOB51",url="/forum/viewtopic.php?p=3886097#p3886097"]Иногда проще не состояние порта менять, а содержимое регистра направления.
Это ежли не требуется полный ток стекающий с 1...
:roll:[/uquote]
Т.Е., если я правильно вас понял, то прямо из функции можно менять направление порта? Теми же DDRx\PORTx?
Хочется всё и сразу, а получаешь нихрена и постепенно...
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Alek_von_German, почитайте что-ли какие-то статьи хотя бы про AVR и C. Самые азы. И поймите. И тогда магия вокруг исчезнет, как придет понимание.
Эти вещи уже столько раз написаны во стольких местах. Хотя бы вот: http://easyelectronics.ru/avr-uchebnyj- ... ast-4.html
Т.Е., если я правильно вас понял, то прямо из функции можно менять направление порта? Теми же DDRx\PORTx?
Что-то неправильно вообще поняли. Направление порта меняется только через DDRx. А PORTx при это обычно 0 всегда. Так реализуется вывод с открытым стоком. Вместо того, чтобы дергать порт из низкого в высокий уровень, он дергается либо в низкий уровень, чтобы прижать линию к земле, либо в высокий, чтобы "отпустить" линию. При это подтяжка обычно внешняя ставится. Но это уже BOB51 ушел в другую "степь", развивая мысль дальше.
Встал на лапы
Аватара пользователя
Сообщения: 118
Зарегистрирован: Вт апр 21, 2020 07:44:24
Откуда: Сумы, Украина

Сообщение Alek_von_German »

NStorm, спасибо. Я-то читаю, литературы много есть, просто сразу всё охватить и запомнить тяжело. Про DDRx я знаю, правда зачем в коментарий я вплёл еще и PORTx- без понятия))
Хочется всё и сразу, а получаешь нихрена и постепенно...
Ответить

Вернуться в «AVR»