Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Тема закрыта

Re: Обработка нажатия кнопки в AVR...

Пт дек 17, 2010 12:58:14

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

в твоей программе есть задержки 150 и 1000мкс. можно настроить таймер на сработку 1 раз в 50мкс, а внутри прерывания вставить такое
Код:
х++:  if(x==  )  x=0;
switch (x)
{
case __:  тут зажигаешь первый режим светофора
break;
.
.              тут по очереди зажигаешь остальные режимы светофора
.
.
case __:  тут зажигаешь последний режим светофора
break;
}
конкретные, нужные тебе значения х - посчитай сам. переменная х должна быть либо глобальной. или локальной но static.

зы. наверное, можно сделать и по другому......

Re: Обработка нажатия кнопки в AVR...

Пт дек 17, 2010 13:23:53

Подскажите, что я делаю не так?
Вот счетчик нажатий кнопки:
У меня такая задача: задержки как можно меньше (должно успевать считать быстро), но не использовать прерываний.
Код:
  if (PIND.3==1) {
  delay_ms(10);
    if (PIND.3==1) {
     while(PIND.3==1) {}; // ожидание отпускания кнопки
     sw2=sw2+1;
     delay_ms(15);
    }
  }

В Proteus работает правильно, а в железе реально: если кнопку держать - считает бесконечное количество раз (пока держится кнопка). Почему так, из-за дребезга?

Вместо кнопки реально будет фотодиод оптического датчика, подключенный вот таким образом: http://easyelectronics.ru/img/starters/fotodetector/fotodetect.GIF
Но изменение его яркости будет достаточно резкое, по этому сильного "дребезга" в этом случае надеюсь не будет.

Re: Обработка нажатия кнопки в AVR...

Пт дек 17, 2010 16:45:29

Внешний резистор не нужен, используйте внутренний. Соответственно вам считать нужно не высокий уровень и низкий
if (PIND.3==0)

Re: Обработка нажатия кнопки в AVR...

Пт дек 17, 2010 18:11:25

Программу светофора я запустил, таймер тикает раз в секунду. Но вот я нажал кнопку, цикл остановился, а таймер дальше считает. Получается, что перед повторным запуском цикла (нажатии другой кнопки) таймер будет считать не с нуля а с некоторого значения. Вот мне и нужно перезапустить таймер, чтобы счет начался сначала.

P.S.

Может я что-то не правильно понял в работе таймера, поправьте если что... :)

Re: Обработка нажатия кнопки в AVR...

Пт дек 17, 2010 18:27:07

leowka писал(а):Внешний резистор не нужен, используйте внутренний. Соответственно вам считать нужно не высокий уровень и низкий if (PIND.3==0)
Да мне как раз высокий надо... Так уже схема спаяна.
А это имеет какое-то значение?

Re: Обработка нажатия кнопки в AVR...

Пт дек 17, 2010 18:47:22

КАШАК Все правильно понял.
А из того что я писал выше чтото понял? там описано что тебе нужно. в твоем случаи обнулять ничего не нужно. таймер считает сам по себе, и когда отсчитывает нужный кусок времени, срабатывает прерывание, в обработчике которого ты зажигаешь нужные лампочки. а таймер в это время, сам обнуляется, и начинает считать с нуля. И когда снова отсчитывает заданный интервал, снова происходит прерывание, в котором ты загигаешь уже другие лампочки, а таймер обнуляется и тикает дальше. И снова все повторяется по кругку. Единственное что тебе нужно сделать чтоб таймер сам обнулялся, это настроить его в режим СТС. Если ты используешь прерывание по переполнению, то СТС ненужен.

Re: Обработка нажатия кнопки в AVR...

Пт дек 17, 2010 18:59:46

Спасибо. Будут вопросы, напишу :))

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 01:43:13

Переписал программу с использование таймера, вот что получилось:

Код:
int a, b, per=0;

interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
a++;                         // Увеличиваем а на 1 при каждом прерывании
}                             

void main(void)
{
PORTA=0x00; DDRA=0x07;

PORTB=0x00; DDRB=0x00;

PORTC=0x00; DDRC=0x07;

PORTD=0x00; DDRD=0x07;

TCCR0=0x00;
TCNT0=0x00;
OCR0=0x00;

// Используем таймер 1, т.к таймера 0 не хватает, коэффициет больше 256
TCCR1A=0x00;                 //
TCCR1B=0x0C;                 // Режим СТС, делитель 256
TCNT1H=0x00;                 //
TCNT1L=0x00;                 //
ICR1H=0x00;                  //
ICR1L=0x00;                  //
OCR1AH=0x7A;                 // Ждем пока наберется 31250
OCR1AL=0x12;                 //
OCR1BH=0x00;                 //
OCR1BL=0x00;                 //

ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

MCUCR=0x00;
MCUCSR=0x00;

TIMSK=0x10;

ACSR=0x80;
SFIOR=0x00;

#asm("sei")                    // Разрешаем прерывания

while (1)
      {
     
      if (PINA.3==1){          // Включаем программу
      delay_ms(100);           // Антидребезг
      TCNT1H=0;                //
      TCNT1L=0;                // Обнуляем таймер
      a=0;                     // Обнуляем комбинацию включенных светодиодов
      per=1;                   //
      }
     
      if (PINA.4==1){          // Выключаем программу
      delay_ms(100);           // Антидребезг
      PORTA=0b00000000;        //
      PORTD=0b00000000;        // Гасим все светодиоды
      PORTC=0b00000000;        //
      per=0;                   //
      }
     
if (per==1){                   // Проверяем, можно-ли запуститься
           
      if (a==0){               // (0 секунда)
      PORTA=0b00000100;        // Зеленый
      PORTD=0b00000100;        // Зеленый
      PORTC=0b00000001;        // Красный
      }
     
      if (a==5){               // Ждем 5 секунд (5 секунда)
                     
      for(b=0; b<=4; b++){     // Мигаем зеленым
      delay_ms(500);           //
      PORTA=0b00000100;        // Зеленый вкл.
      PORTD=0b00000100;        // Зеленый вкл.
      delay_ms(500);           //
      PORTA=0;                 // Зеленый выкл.
      PORTD=0;                 // Зеленый выкл.
      }
       }
     
      if (a==10 || a==25){     // Ждем 5 секунд (10 секунда, 25 секунда)
      PORTA=0b00000010;        // Желтый
      PORTD=0b00000010;        // Желтый
      PORTC=0b00000010;        // Желтый
      }
     
      if (a==15){              // Ждем 5 секунд (15 секунда)
      PORTA=0b00000001;        // Красный
      PORTD=0b00000001;        // Красный
      PORTC=0b00000100;        // Зеленый
      }
     
      if (a==20){              // Ждем 5 секунд (20 секунда)
      for(b=0; b<=4; b++){     // Мигаем зеленым 5 секунд
      delay_ms(500);           //
      PORTC=0b00000100;        // Зеленый вкл
      delay_ms(500);           //
      PORTC=0;                 // Зеленый выкл.
      }
       }
     
      if (a>=30){              // Ждем 5 секунд (30 секунда)
      a=0;                     // Обнуляем комбинацию включенных светодиодов
      }
       }
        } 
};


Как её еще можно изменить или укоротить?

P.S.

Написал небольшую програмку для расчета времени задержки таймера. Кому интересно, качайте AVR_Калькулятор :) (обменник бесплатный, никакого времени ожидания, кодов и т.п.)

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 03:07:22

Молодец :beer: если раньше программировать не пробовал, то очень не плохо за три дня разобрался. я буксовал на этом этапе месяц :oops:
По проге я бы сделал так.
во первых повесил бы все лампочки на один порт, на 3 младших разряда.
таймер настроил бы на прерывание на самый маленький интервал, и кучу if заменил бы на один switch. переменную а обнулять можно тоже в этом же switch
Код:
switch  (a)
        {
        case 0:                           PORTA=0b00000xxx;  break;
        case __:                          PORTA=0b00000xxx;  break;
        case __:                          PORTA=0b00000xxx;  break;
        case (__ || __):                  PORTA=0b00000xxx;  break;
        case (__ || __ || __ || __.....): PORTA=0b00000xxx;  break;
        case __:  а=0;
        }
С кнопками тоже можно чтото оптимизировать. но у тебя и у самого не плохо получается :)))

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 03:14:11

До этого контроллеры вообще не программировал, писал только на С++ :)) Вот и программку по быстрому сделал, чтобы с калькулятором не сидеть :))
Ваши замечания обязательно учту. А на лампочки на разные порты повесил, чтобы в Proteus удобнее собирать было :). Теперь хотелось бы научиться работать с ШИМ и АЦП...

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 03:28:58

Ну раз Си знаешь, это хорошо. Тогда многое из того что я говорю для тебя должно быть прописной истиной.
Я вообще понятия не имел о языке, и контроллерах. исходник что на Си, что на асме был для меня набором букв и цифр. :shock:

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 03:41:59

Вот, переписал программу. Потом на счет кнопок подумаю :) . Со swith-case намного удобнее работать

Код:
while (1)
      {
      if (PINA.3==1){          // Включаем программу
      delay_ms(100);           // Антидребезг
      TCNT1H=0;                //
      TCNT1L=0;                // Обнуляем таймер
      a=0;                     // Обнуляем комбинацию включенных светодиодов
      per=1;                   //
      }
     
      if (PINA.4==1){          // Выключаем программу
      delay_ms(100);           // Антидребезг
      PORTA=0b00000000;        //
      PORTD=0b00000000;        // Гасим все светодиоды
      PORTC=0b00000000;        //
      per=0;                   //
      }
      if(per==1){
      switch  (a)
        {
        case 0:                           PORTA=0b00000100; PORTC=0b00000001; PORTD=0b00000100;  break;
        case 5:           
                for(b=0; b<=4; b++){     // Мигаем зеленым
                delay_ms(500);           //
                PORTA=0b00000100;        // Зеленый вкл.
                PORTD=0b00000100;        // Зеленый вкл.
                delay_ms(500);           //
                PORTA=0;                 // Зеленый выкл.
                PORTD=0;                 // Зеленый выкл.
                }                  break;
        case 10:       
        case 25:                          PORTA=0b00000010; PORTC=0b00000010; PORTD=0b00000010;  break;
        case 15:                          PORTA=0b00000001; PORTC=0b00000100; PORTD=0b00000001;  break;
        case 20:
                for(b=0; b<=4; b++){     // Мигаем зеленым
                delay_ms(500);           //
                PORTC=0b00000100;        // Зеленый вкл.
                delay_ms(500);           //
                PORTC=0;                 // Зеленый выкл.
                }                  break;
        case 30:  a=0;
        }
         }
          } 
};


Где можно про ШИМ и АЦП почитать?

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 12:09:06

увлекся твоим светофором, как своим :)))
работа шим и ацр расписана в книге в подписи. хоть эта книга является справочником, а не обучалкой, но прочтя её сразу понимаешь что как работает, в каком регистре какой бит установить, чтоб контроллер начал делать то что тебе нужно.
Еще на сайте у дихалта посмотри. там вообще все на пальцах и с картинками. единственно что он делает на примере ассемблера, но суть понять можно.

возвращаясь к твоей программе.
тебе нужно полностью избавится от delay. сделать это очень просто, я писал выше как. Сейчас у тебя получается, что если нажать кнопку когда контроллер отрабатывает delay то она не сработает.
Опиши с указанием времени полный цикл работы светофора, и я набросаю прогу вообще без delay , if. , for. будет один единственный switch с 4-5 case.

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 16:04:08

Цикл работы такой:

Включили питание, ничего не происходит. Жмем кнопку, включается программа:

1) 0-секунда: Включились 2 зелёных и один красный;
Код:
PORTA=0b00000100; PORTC=0b00000001; PORTD=0b00000100;

2) 5-секунда: Зелёные мигают, красный горит;
3) 10-секунда: Красный и зелёный погасли, горят 3 жёлтых;
Код:
PORTA=0b00000010; PORTC=0b00000010; PORTD=0b00000010;

4) 15-секудна: Жёлтые погасли, загорелись 2 красных и один зелёный.
Код:
PORTA=0b00000001; PORTC=0b00000100; PORTD=0b00000001;

5) 20-секунда: Зелёный мигает, 2 красных горят.
6) 25-секунда: Красный и зелёный погасли, горят 3 жёлтых;
Код:
PORTA=0b00000010; PORTC=0b00000010; PORTD=0b00000010;

7) 30-секунда: Возврат цикла на 0-й шаг.
Код:
a=0;


Есть ещё кнопка выключения программы. :)

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 17:52:06

переменная а должна увеличиваться каждые 0,5 сек
Код:
switch  (a)
        {
        case 0:                      2 зелёных и один красный вкл;                  break;
        case (10||12||14||16||18):   Зелёные вкл, красный вкл;                      break;
        case (11||13||15||17||19):   Зелёные выкл;                                  break;
        case 20:                     Красный и зелёный выкл, 3 жёлтых вкл;          break;
        case 30:                     Жёлтые выкл,  2 красных и один зелёный вкл.    break;
        case (40||42||44||46||48):   Зелёный , 2 красных вкл.                       break;
        case (41||43||45||47||49):   Зелёный выкл                                   break;
        case 50:                     Красный и зелёный выкл, 3 жёлтых вкл;          break;
        case 60:  а=0;                                                              break;
        }
если лампочки повесишь на один порт, то код стает минимальным.

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 17:58:33

CodeVision ругается на
Код:
case (40||42||44||46||48):
Пишет Error: D:\Projects_AVR\Svetofor_2\main.c(92): constant integral expression required

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 18:57:34

хм. действительно. я думал кодевижн такое проглотит. ну тогда придется делать кучу case. :dont_know:

Re: Обработка нажатия кнопки в AVR...

Сб дек 18, 2010 19:23:32

Перписал без for, все лампочки на порт А повесил.

Код:
      switch  (a)
        {                           //    PORTA=0b0ygrgrgr
        case 0:                           PORTA=0b00101001; break;
        case 10: case 14: case 18:        PORTA=0b00000001; break;
        case 12: case 16:                 PORTA=0b00101001; break;
        case 20:                          PORTA=0b01000000; break;
        case 30:                          PORTA=0b00100101; break;
        case 40: case 44: case 48:        PORTA=0b00000101; break;
        case 42: case 46:                 PORTA=0b00100100; break;
        case 50:                          PORTA=0b01000000; break;
        case 60:  a=0;
        }

Re: Обработка нажатия кнопки в AVR...

Вс дек 19, 2010 01:59:48

Вот как можно оптимизировать работу кнопок.
Код:
if (PINA.3==1)  TCNT1H=0; TCNT1L=0;  a=0;  #asm("sei")
if (PINA.4==1)  #asm("cli") 
антидребезг в твоём случаи ненужен.

кодевижен схавал это???
Код:
 case 10: case 14: case 18:
надо запомнить на будущее.

Re: Обработка нажатия кнопки в AVR...

Вс дек 19, 2010 02:04:22

Спасибо. :)

Пытаюсь разобраться с ШИМ, пока как-то не очень. Можете дать несколько простых примеров с использованием ШИМ?
Тема закрыта