Страница 1 из 1
Как правильно делать маски на порты?
Добавлено: Вс авг 30, 2020 19:25:45
Alek_von_German
Доброго здравия, господа.
Роясь в литературе всякой по AVR Atmel, в поисках ответа на всяческие вопросы, заметил, что везде на всяких форумах/книгах присутствует один и тот же сценарий,
Берем кнопку1 и цепляем её на пин0 порта В, далее берем светодиод и цепляем его на ножку порта С. Это понятно. НО, если мне нужно выделить часть порта на кнопки, а вторую часть порта будет иметь прерывание от таймера- как в таком случае быть? Стандартное DDRB|=0x0f; PORTB|=0xf0;- не работает, точнее из-за того, что двумя пинами дергает таймер, остальные не включаются как входы и не подтягиваются к плюсу, они просто висят. Как обойти такое?
Re: Как правильно делать маски на порты?
Добавлено: Вс авг 30, 2020 19:59:52
НАПАЛМ
В таких тонкостях архитектуры не силен, что таймер целый потр забивает, но если действительно так, что первый костыль, приходящий на ум, это дерганье ногами таймера в прерывании таймера, и всеми остальными уже как вам нужно.
Re: Как правильно делать маски на порты?
Добавлено: Вс авг 30, 2020 20:04:36
ARV
Alek_von_German писал(а):Стандартное DDRB|=0x0f; PORTB|=0xf0;- не работает, точнее из-за того, что двумя пинами дергает таймер, остальные не включаются как входы и не подтягиваются к плюсу, они просто висят.
все работает, если делать правильно. поскольку мы не видим, как делаете вы, вам придется самостотельно искать ошибку
Re: Как правильно делать маски на порты?
Добавлено: Вс авг 30, 2020 20:17:21
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
Re: Как правильно делать маски на порты?
Добавлено: Вс авг 30, 2020 21:25:31
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- тормозит таймер.
Re: Как правильно делать маски на порты?
Добавлено: Пн авг 31, 2020 08:56:54
ARV
смотрел ваш код 5 секунд, и заметил вот это: в одном прерывании вы делаете правильно
а в другом уже иначе
Код: Выделить всё
PORTC= (1 << segcounter); // Выбираем следующий разряд
в первом случае вы именно маскируете нужные разряды, а во втором обновляете значение порта целиком.
Re: Как правильно делать маски на порты?
Добавлено: Пн авг 31, 2020 12:07:07
Alek_von_German
Угу. Я так уже думал. Но когда я делаю вот так PORTC|= (1 << segcounter); то на выходе обе ноги принимают значение 1-цы.
Re: Как правильно делать маски на порты?
Добавлено: Пн авг 31, 2020 13:10:28
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)
Re: Как правильно делать маски на порты?
Добавлено: Пн авг 31, 2020 14:10:23
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) )
Re: Как правильно делать маски на порты?
Добавлено: Пн авг 31, 2020 14:37:02
BOB51
Иногда проще не состояние порта менять, а содержимое регистра направления.
Это ежли не требуется полный ток стекающий с 1...

Re: Как правильно делать маски на порты?
Добавлено: Пн авг 31, 2020 15:00:16
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)
Да, это работает. Беру себе в коллекцию для изучения. Спасибо большое!!!
Добавлено after 3 minutes 25 seconds:
[uquote="BOB51",url="/forum/viewtopic.php?p=3886097#p3886097"]Иногда проще не состояние порта менять, а содержимое регистра направления.
Это ежли не требуется полный ток стекающий с 1...

[/uquote]
Т.Е., если я правильно вас понял, то прямо из функции можно менять направление порта? Теми же DDRx\PORTx?
Re: Как правильно делать маски на порты?
Добавлено: Пн авг 31, 2020 15:16:50
NStorm
Alek_von_German, почитайте что-ли какие-то статьи хотя бы про AVR и C. Самые азы. И поймите. И тогда магия вокруг исчезнет, как придет понимание.
Эти вещи уже столько раз написаны во стольких местах. Хотя бы вот:
http://easyelectronics.ru/avr-uchebnyj- ... ast-4.html
Т.Е., если я правильно вас понял, то прямо из функции можно менять направление порта? Теми же DDRx\PORTx?
Что-то неправильно вообще поняли. Направление порта меняется только через DDRx. А PORTx при это обычно 0 всегда. Так реализуется вывод с открытым стоком. Вместо того, чтобы дергать порт из низкого в высокий уровень, он дергается либо в низкий уровень, чтобы прижать линию к земле, либо в высокий, чтобы "отпустить" линию. При это подтяжка обычно внешняя ставится. Но это уже BOB51 ушел в другую "степь", развивая мысль дальше.
Re: Как правильно делать маски на порты?
Добавлено: Пн авг 31, 2020 15:31:42
Alek_von_German
NStorm, спасибо. Я-то читаю, литературы много есть, просто сразу всё охватить и запомнить тяжело. Про DDRx я знаю, правда зачем в коментарий я вплёл еще и PORTx- без понятия))