Опрос кнопок микроконтроллером

Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25122
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Мелкие вопросы по МК и ПЛИС.

Сообщение КРАМ »

...задержки в ISR? :o :o :o
...очень круто...
Дальше можно не смотреть.
:cry:
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: Мелкие вопросы по МК и ПЛИС.

Сообщение service47 »

А каким образом можно реализовать отслеживание удержания 2-х кнопок в течении 2сек. вне обработчика прерывания?
У меня они не реагируют на команду (PIND2 == 0) или единице, пробовал через:
while(EIFR == 0b00000011)
и те же задержки.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25122
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Мелкие вопросы по МК и ПЛИС.

Сообщение КРАМ »

1. Кнопки не относятся к устройствам реального времени.
2. Кнопки анализируются циклическим ОПРОСОМ.
3. Цикл можно задавать прерыванием от таймера.
4. Циклический опрос одновременно защищает от дребезга, если интервал опроса больше времени дребезга.
Далее думайте. Когда появятся СВОИ идеи - продолжим...
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: Помогите опросить кнопку

Сообщение service47 »

Пункт 2 непонятен (что опрашивать: пин, флаг прерывания...), у меня кнопки через резистор 10кОм соединены с питанием, а другим выводом на землю и при замыкании кнопки на пине д.б. 0, пробую в программе, но код не работает.
Аватара пользователя
ibiza11
Поставщик валерьянки для Кота
Сообщения: 1900
Зарегистрирован: Сб фев 21, 2009 13:11:40
Откуда: Москва

Re: Помогите опросить кнопку

Сообщение ibiza11 »

прочтите эту тему и все встанет на свои места.
Ставим плюсы: )
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25122
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Помогите опросить кнопку

Сообщение КРАМ »

Причем тут прерывания?
Опрашивается КНОПКА. То есть ПИН.
А опрашивается он с интервалом прерываний от таймера.
Состояние обеих кнопок фиксируется в специальном регистре, который называется машиной состояний.
Анализ машины состояний и есть путь для решения Вашей задачи.
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: Помогите опросить кнопку

Сообщение service47 »

Если под машиной состояний имеется ввиду флаг прерываний, устанавливаемый в единицу, когда происходит прерывание регистр EIFR биты INTF0 и INTF1:
опрос while(EIFR == 0b00000011)
то тут получается трудно нажать идеально одновременно обе кнопки чтобы запустился алгоритм, видимо придется опрашивать от прерывания таймера эти биты.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Помогите опросить кнопку

Сообщение Аlex »

видимо придется опрашивать от прерывания таймера эти биты.
Не "видимо придётся", а так и нужно делать.
Где то в районе 4-ой страницы я выкладывал пример обработки кнопок. А на предыдущей странице есть посты, где человек запустил длинные нажатия. Почитайте темку, не ленитесь...
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25122
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Помогите опросить кнопку

Сообщение КРАМ »

service47 писал(а):Если под машиной состояний имеется ввиду флаг прерываний, устанавливаемый в единицу, когда происходит прерывание регистр EIFR биты INTF0 и INTF1:
опрос while(EIFR == 0b00000011)
то тут получается трудно нажать идеально одновременно обе кнопки чтобы запустился алгоритм, видимо придется опрашивать от прерывания таймера эти биты.

У Вас дислексия? :cry: :facepalm:
Я РУССКИМ языком написал: ЗАБУДЬТЕ О ПРЕРЫВАНИЯХ ОТ КНОПОК.
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: Помогите опросить кнопку

Сообщение service47 »

Пытаюсь настроить таймер1 для опроса кнопок, но при компиляции выдает ошибку:

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

interrupt [TIM1_OVF] void timer1_ovf_isr(void){
//...
}

Error 1 'TIM1_OVF' undeclared here (not in a function)

Даташит на ATmega88PA: http://www.atmel.com/images/doc2545.pdf
В даташите написано на стр.59, что есть прерывания:
TIMER1 OVF и приводиться код на асме:
0x00D rjmp TIM1_OVF ; Timer1 Overflow Handler
а AtmelStudio6 предлагает вместо TIM1_OVF ввести:
timer1_ovf_isr()
TIMER1_OVF_vect
TIMER1_OVF_vect_num
а там уже другие ошибки выскакивают.

Подключены:
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>

Погуглил, тут вроде есть решение, но мне оно непонятно:
http://www.avrfreaks.net/index.php?name ... 04&start=0

Ввожу:
interrupt [TIMER1_OVF_vect] void timer1_ovf_isr(void){... }
и ошибка: Error 1 '__vector_13' undeclared here (not in a function)
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Кнопки не работают от 0 и 1цы

Сообщение service47 »

Ситуация интересная: если кнопка нажата и замыкается на землю, то на входе порта д.б. ноль, пробовал писать в коде ноль не работает, стал методом тыка подбирать другие значения и вот результат:

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

ISR(INT1_vect)  //MINUS PIND3
{_delay_ms(200);
if (PIND3 <= 2,9) //(PIND3 <= 3) работает (PIND3 <= 2,95)
      {s--;}
}

ISR(INT0_vect)  //PLUS PIND2
{_delay_ms(200);
if (PIND2 >= 3) //(PIND2 >= 2,995) работает, а если (PIND2 >= 3) то не работает
      {s++;}
}

      DDRD=0x0C; //0b00001100
      PORTD=0xff; // 0b11111111


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

Схема (кнопки S4, S5):
Изображение

В архиве схема протеуса (в которой если подгрузить прошивку .НЕХ можно погонять значения на индикаторе), прошивка, исходник для AtmelStudio6 и принципиальная схема: http://rghost.ru/50883666

Даташит на ATmega88PA: http://www.atmel.com/images/doc2545.pdf

PS: на дэлэй в обработчике внимания не обращать.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25122
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: Помогите опросить кнопку

Сообщение КРАМ »

Есть старый анекдот про прапорщика: "Х-ли думать, трясти надо!"...
Увы, Ваша маниакальная "привязанность" к кнопкам на прерываниях неизлечима....
:cry:
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: Помогите опросить кнопку

Сообщение service47 »

Как раз наоборот пытаюсь сделать опрос кнопок по шаблону от Alex'a (все в архиве), а в обработчики прерывания полез чтобы в протеусе тестировать значение на портах при которых кнопка замкнута и т.д. т.к. в голове не укладывается как так может быть, что у кнопки может быть состояние отличное от логических нулей и единиц...

Спойлер

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

#define F_CPU 1000000UL

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>


#define COUNTDOWN 1

volatile char FLAG = 0;
volatile char s = 6;    //Переменная цифры
volatile char a = 6;
volatile char b = 1;    //Начальный сброс флага
volatile char c = 6;
volatile char j = 6;    //Перескок через ШИМ
// массив знаков на индикатор
char digits[11] = {0b00111111, 0b00000110, 0b00011011, 0b00001111, 0b00100110, 0b00101101, 0b00111101, 0b00000111, 0b00111111, 0b00101111, 0b00101111}; // PORTC 0,1,2,3,4,5,6,7,8,9,x
char digita[11] = {0b00000000, 0b00000000, 0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000000, 0b00000001, 0b00000001, 0b00000001}; // PORTB

/******************************************************************/
#define ACT_BUTT_LEV    0       // Активный уровень нажатых кнопок
#define ACT_BUTT_LEV_2    0
//----------
#define PORT_BUTT_1     PIND    // Порт кнопки №1
#define PIN_BUTT_1      2       // Номер бита порта кнопки №1
#define PORT_BUTT_2     PIND    // Порт кнопки №2
#define PIN_BUTT_2      3       // Номер бита порта кнопки №2
//----------
#define PORT_LED_1      PORTB   // Светики
#define DDR_LED_1       DDRB    //
#define PIN_LED_1       2       //
#define PORT_LED_2      PORTB   //
#define DDR_LED_2       DDRB    //
#define PIN_LED_2       7       //
/******************************************************************/

/******************************************************************/
typedef struct{
   unsigned cur:   1;      // Текущее состояние
   unsigned prev:  1;      // Предыдущее состояние
   unsigned down:  1;      // Была нажата
   unsigned up:    1;      // Была отжата
}tButt;
volatile tButt  mButt_1 = {0,!ACT_BUTT_LEV,0,0};    // Объявляем структуру mButt_1 для нашей кнопки и иним её.

typedef struct{
   unsigned cur:   1;      // Текущее состояние
   unsigned prev:  1;      // Предыдущее состояние
   unsigned down:  1;      // Была нажата
   unsigned up:    1;      // Была отжата
}tButt2;
volatile tButt2  mButt_2 = {0,!ACT_BUTT_LEV_2,0,0};    // Объявляем структуру mButt_2 для нашей кнопки и иним её.
/******************************************************************/

/******************************************************************/
ISR (TIMER1_OVF_vect) {   s=3;   //interrupt [TIM1_OVF] void timer1_ovf_isr(void){ //TIMER1_OVF_vect_num
   static unsigned char cnt_ms_butt=20;    // Счётчик для формирования периода в 20 мс.
   TCNT1 -= 4000;          // Перезапускаем таймер на 1 мс.
   //----------//
   if(!--cnt_ms_butt){     // Формируем 20-ти миллисек. периоды
   cnt_ms_butt=20;
   mButt_1.cur = (PORT_BUTT_1&(1<<PIN_BUTT_1))!=0;                 // Считываем текущее значение вывода.
   // Дальше работаем с этим битом, т.к. порт может измениться в любой момент.
   if((mButt_1.cur==ACT_BUTT_LEV) && (mButt_1.prev!=ACT_BUTT_LEV)) // Если текущее значение - "нажата" и предыдущее - "не нажата"
   mButt_1.down = 1;                                                   // Устанавливаем флаг down
   if((mButt_1.cur!=ACT_BUTT_LEV) && (mButt_1.prev==ACT_BUTT_LEV)) // Если текущее значение - "не нажата" и предыдущее - "нажата"
   mButt_1.up = 1;                                                     // Устанавливаем флаг up
   mButt_1.prev=mButt_1.cur;                                       // Сохраняем текущее значение. Оно для следующего входа будет предыдущим

   mButt_2.cur = (PORT_BUTT_2&(1<<PIN_BUTT_2))!=0;                         // Считываем текущее значение вывода.
   if((mButt_2.cur==ACT_BUTT_LEV_2) && (mButt_2.prev!=ACT_BUTT_LEV_2))     // Если текущее значение - "нажата" и предыдущее - "не нажата"
   mButt_2.down = 1;                                                   // Устанавливаем флаг down
   if((mButt_2.cur!=ACT_BUTT_LEV_2) && (mButt_2.prev==ACT_BUTT_LEV_2))     // Если текущее значение - "не нажата" и предыдущее - "нажата"
   mButt_2.up = 1;                                                     // Устанавливаем флаг up
   mButt_2.prev=mButt_2.cur;
   }
//----------//
}
/******************************************************************/

ISR(INT1_vect)  //MINUS PIND3
{_delay_ms(200);
if (PIND3 >= 2) //(PIND3 <= 3) работает (PIND3 <= 2,95)
      {s--;}
}

ISR(INT0_vect)  //PLUS PIND2
{_delay_ms(200);
if (PIND2 >= 2,995) //(PIND2 >= 2,995) работает, а если (PIND2 >= 3) то не работает
      {s++;}
}

void shim_start()
{
   if (j==6)
   {goto jstop;
   }
//   ASSR=0x00;
//   // Установим биты COM1A1-COM1A0:0b10,означает сброс вывода канала A при сравнении Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM (non-inverting mode), for Fast PWM. page135
//   TCCR1A |= (1 << COM1A1)|(0 << COM1A0)|(0 << WGM11)|(1 << WGM10);
//   // Установим биты WGM13-10:0b0101, согласно таблице это будет режим - Fast PWM, 8-bit, где верхний предел счета задается битом ICR1. page136
//   TCCR1B |= (0 << WGM13)|(1 << WGM12)|(1 << CS12)|(0 << CS11)|(0 << CS10);
//   // Битами CS12-10:0b100 задаем источник тактового сигнала для таймера МК, clkI/O/256 (From prescaler)=31250Hz. page137
//   TCNT1 = 0x00; // начальная установка счетчика
//   TIMSK1=0x00;
//   ICR1 = 0x20;  // задаем период ШИМ, здесь у нас число 255,
//   // по формуле  fPWM=fclk_I/O/N*(1+ICR1) вычисляем частоту ШИМ, она будет равна 8MHz/256(1+2)=10416Hz
//    // для FR3706 надо 50000Hz, irlm0030 надо 16666Hz<
//    OCR1A = 0x50; // начальный коэффициент заполнения ШИМ 0xC8=200, 0x50=1/3
   jstop:
   j=0;
}

int main(void)
{
      DDRC=0x3f;  //0b00111111 0-ввод 1-вывод
      PORTC=0x00; //
      DDRD=0x0C; //0b00001100
      PORTD=0xff; // 0b11111111
      DDRB=0xFF; //0b11000111 PB1(OC1A)-ШИМ DDRB=0xC7;
      PORTB=0x00; //PORTB=0x00;
   EICRA  =  (1<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00);   // настройка срабатывания прерываний The falling edge of INT1 generates an interrupt request
   PCICR  |= (1<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);// разрешение прерываний PCINT23...16
   PCMSK2=0b11000000; //разрешаем прерывание pcint23 pcint22
   EIMSK=0b11000011; //разрешаем прерывание int0 и int1 - кнопка
   MCUCR=0b00001111;// IVSEL, IVCE
   sei(); //Глобальное разрешение прерываний
      //Установка таймера0
   //TCCR0A |= (0 << COM1A1)|(0 << COM1A0)|(1 << WGM01)|(0 << WGM00); //биты COM Normal port operation, OC0A disconnected, WGM T/C in CTC mode
   //TCCR0B |= (0 << WGM02)|(0 << CS02)|(0 << CS01)|(1 << CS00); //биты CS fclk_I/O/1
   //TCNT0=0x00;
   //OCR0A=0x80;   
   //----------//
   //TCCR0A=0x00; //TCCR0=0x00;
//   TCCR0B=0x01; //TCCR0=0x00;
//   TCNT0=0x00;
   // Timer/Counter 1 initialization
   TCCR1A=0x00; //для Compare Output Mode, non-PWM COM1A1/COM1B1=0 COM1A0/COM1B0=0 Normal port operation, OC1A/OC1B disconnected.
   TCCR1B=0x01; //Waveform Generation Mode Bit Description WGM10-13=0 Normal //CS12-10=001 No prescaling
   TCNT1H=0x00;
   TCNT1L=0x00;
   ICR1H=0x00;
   ICR1L=0x00;
   //OCR1AH=0x00;
   //OCR1AL=0x00;
   OCR1BH=0x00; //OCR1B compared with the counter value (TCNT1)
   OCR1BL=0x00;
   // Timer/Counter 2 initialization
   //ASSR=0x00;
   //TCCR2=0x00; //TCCR2=0x00;
   //TCNT2=0x00;
   //OCR2=0x00; //OCR2=0x00;
   MCUCR=0x00;
   //TIMSK0=0x04; //TIMSK=0x04;
   TIMSK1=0x04; //TIMSK=0x04; //OCIE1B=1
   //ACSR=0x80;
   //SFIOR=0x00;
   //----------//
   
    while(1)
    {
      //----------//
      if(mButt_1.up){     // Если кнопка была нажата -> отжата
      mButt_1.up=0;                   // Сбрасываем флаг
      PORT_LED_1 ^=(1<<PIN_LED_1);    // Инвертируем светодиод №1
      s++;
      }
      //----------//
      if(mButt_1.down){   // Если кнопка была отжата -> нажата
      mButt_1.down=0;                 // Сбрасываем флаг
      PORT_LED_2 ^=(1<<PIN_LED_2);    // Инвертируем светодиод №2
      s++;
      }
      //----------//   
      //----------//
      if(mButt_2.up){     // Если кнопка была нажата -> отжата
      mButt_2.up=0;                   // Сбрасываем флаг
      PORT_LED_1 ^=(1<<PIN_LED_1);    // Инвертируем светодиод №1
      s--;
      }
      //----------//
      if(mButt_2.down){   // Если кнопка была отжата -> нажата
      mButt_2.down=0;                 // Сбрасываем флаг
      PORT_LED_2 ^=(1<<PIN_LED_2);    // Инвертируем светодиод №2
      s--;
      }
      //----------//   
              start:
              if (b == 1)
              {s=5;
                 FLAG &= ~ COUNTDOWN;
                 b++;
              }
              
              if (s > 9)
              s--;
              else if (s == 0)
              s++;
              if (FLAG == COUNTDOWN)
              {
                 //cli();
               char i = 0;
                 while (s > -1)
                 {
                    if (s > -1)
                    {
                       a = 5;
                       c = 5;
                       if (FLAG != COUNTDOWN)
                       {
                          goto start;
                       }
                       PORTB |= _BV(PB6); // чтобы мигала точка на индикаторе
                       _delay_ms(250);
                       PORTB &= ~_BV(PB6);
                       _delay_ms(250);
                    }
                    PORTC = digits[s];
                    PORTB = digita[s];
                    _delay_ms(500);
                    PORTB &= ~_BV(PB7); //Красный светодиод
                    _delay_ms(500);
                    PORTB |= _BV(PB7);
                    s--;
                    if (s == 0)
                    {
                       PORTC = digits[s];
                       PORTB = digita[s];                     
                     j=0;
                     shim_start();
                       PORTB &= ~_BV(PB2); //Зеленый светодиод
                       _delay_ms(250);
                       PORTB |= _BV(PB2);
                       _delay_ms(250);
                    }
                  i++;
                     if (i>=10)
                     {ICR1 = 0x00;
                     OCR1A = 0x00;}
                 }
                 sei();
                 FLAG &= ~ COUNTDOWN;
              }
              PORTC = digits[s];
              PORTB = digita[s];

    }
}
Аватара пользователя
zero648
Вымогатель припоя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Re: Помогите опросить кнопку

Сообщение zero648 »

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

      DDRD=0x0C; //0b00001100
      PORTD=0xff; // 0b11111111

А че пины для кнопок проинициализированы на выход??
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: Помогите опросить кнопку

Сообщение service47 »

Делал на основе этой статьи:
http://easyelectronics.ru/avr-uchebnyj- ... yvoda.html

DDRD=0x0C; //0b00001100 единичные биты это те две кнопки PIND2 и PIND3, поставил нули реакции нет (но еще повожусь с этими нулями, чтоб наверняка знать)...
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Помогите опросить кнопку

Сообщение Аlex »

service47 писал(а):поставил нули реакции нет
Какой кошмар :facepalm:
Прежде чем что-то делать, нужно хорошо понимать что ты делаешь. А с таким методом тыка можно дотыкаться до убийства портов МК (как минимум)...
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3868
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: Помогите опросить кнопку

Сообщение Engineer_Keen »

service47 писал(а):DDRD=0x0C; //0b00001100 единичные биты это те две кнопки PIND2 и PIND3

Надеюсь вы эти кнопочки на настоящем контроллере не нажимали, иначе у меня для вас плохие новости...
service47
Прорезались зубы
Сообщения: 219
Зарегистрирован: Вт мар 12, 2013 16:05:45

Re: Помогите опросить кнопку

Сообщение service47 »

Вобщем так:
1. Таймер1В отключен и прерывание тоже по переполнению. Запуск ШИМ откл.
2. Включены прерывания INT0 и INT1 с условиями для проверки значений нажатой кнопки.
3. При старте программы прописаны условия if чтобы проверить состояние отжатой кнопки методом подбора значении (если совпадет, то на индикаторе будет цифра 8 ).

Кнопки соответственно уменьшают и увеличивают значение на индикаторе на 1.
Как только значения проясняться или все сведется к лог.0 и 1, то будет включен модуль написанный Alex'ом, там уже другие заморочки.

Спойлер

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

#define F_CPU 1000000UL

#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>


#define COUNTDOWN 1

volatile char FLAG = 0;
volatile char s = 6;    //Переменная цифры
volatile char a = 6;
volatile char b = 1;    //Начальный сброс флага
volatile char c = 6;
volatile char j = 6;    //Перескок через ШИМ
// массив знаков на индикатор
char digits[11] = {0b00111111, 0b00000110, 0b00011011, 0b00001111, 0b00100110, 0b00101101, 0b00111101, 0b00000111, 0b00111111, 0b00101111, 0b00101111}; // PORTC 0,1,2,3,4,5,6,7,8,9,x
char digita[11] = {0b00000000, 0b00000000, 0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000001, 0b00000000, 0b00000001, 0b00000001, 0b00000001}; // PORTB

/******************************************************************/
#define ACT_BUTT_LEV    0       // Активный уровень нажатых кнопок
#define ACT_BUTT_LEV_2    0
//----------
#define PORT_BUTT_1     PIND    // Порт кнопки №1
#define PIN_BUTT_1      2       // Номер бита порта кнопки №1
#define PORT_BUTT_2     PIND    // Порт кнопки №2
#define PIN_BUTT_2      3       // Номер бита порта кнопки №2
//----------
#define PORT_LED_1      PORTB   // Светики
#define DDR_LED_1       DDRB    //
#define PIN_LED_1       2       //
#define PORT_LED_2      PORTB   //
#define DDR_LED_2       DDRB    //
#define PIN_LED_2       7       //
/******************************************************************/

/******************************************************************/
typedef struct{
   unsigned cur:   1;      // Текущее состояние
   unsigned prev:  1;      // Предыдущее состояние
   unsigned down:  1;      // Была нажата
   unsigned up:    1;      // Была отжата
}tButt;
volatile tButt  mButt_1 = {0,!ACT_BUTT_LEV,0,0};    // Объявляем структуру mButt_1 для нашей кнопки и иним её.

typedef struct{
   unsigned cur:   1;      // Текущее состояние
   unsigned prev:  1;      // Предыдущее состояние
   unsigned down:  1;      // Была нажата
   unsigned up:    1;      // Была отжата
}tButt2;
volatile tButt2  mButt_2 = {0,!ACT_BUTT_LEV_2,0,0};    // Объявляем структуру mButt_2 для нашей кнопки и иним её.
/******************************************************************/

/******************************************************************/
ISR (TIMER1_OVF_vect) {   s=3;   //interrupt [TIM1_OVF] void timer1_ovf_isr(void){ //TIMER1_OVF_vect_num
   static unsigned char cnt_ms_butt=20;    // Счётчик для формирования периода в 20 мс.
   TCNT1 -= 4000;          // Перезапускаем таймер на 1 мс.
   //----------//
   if(!--cnt_ms_butt){     // Формируем 20-ти миллисек. периоды
   cnt_ms_butt=20;
   mButt_1.cur = (PORT_BUTT_1&(1<<PIN_BUTT_1))!=0;                 // Считываем текущее значение вывода.
   // Дальше работаем с этим битом, т.к. порт может измениться в любой момент.
   if((mButt_1.cur==ACT_BUTT_LEV) && (mButt_1.prev!=ACT_BUTT_LEV)) // Если текущее значение - "нажата" и предыдущее - "не нажата"
   mButt_1.down = 1;                                                   // Устанавливаем флаг down
   if((mButt_1.cur!=ACT_BUTT_LEV) && (mButt_1.prev==ACT_BUTT_LEV)) // Если текущее значение - "не нажата" и предыдущее - "нажата"
   mButt_1.up = 1;                                                     // Устанавливаем флаг up
   mButt_1.prev=mButt_1.cur;                                       // Сохраняем текущее значение. Оно для следующего входа будет предыдущим

   mButt_2.cur = (PORT_BUTT_2&(1<<PIN_BUTT_2))!=0;                         // Считываем текущее значение вывода.
   if((mButt_2.cur==ACT_BUTT_LEV_2) && (mButt_2.prev!=ACT_BUTT_LEV_2))     // Если текущее значение - "нажата" и предыдущее - "не нажата"
   mButt_2.down = 1;                                                   // Устанавливаем флаг down
   if((mButt_2.cur!=ACT_BUTT_LEV_2) && (mButt_2.prev==ACT_BUTT_LEV_2))     // Если текущее значение - "не нажата" и предыдущее - "нажата"
   mButt_2.up = 1;                                                     // Устанавливаем флаг up
   mButt_2.prev=mButt_2.cur;
   }
//----------//
}
/******************************************************************/

ISR(INT1_vect)  //MINUS PIND3
{_delay_ms(200);
if (PIND3 == 3) //(PIND3 <= 3) работает (PIND3 <= 2,95) (PIND3 == 3)
      {s--;}
}

ISR(INT0_vect)  //PLUS PIND2
{_delay_ms(200);
if (PIND2 == 2) //(PIND2 == 2)(PIND2 >= 2,995) работает, а если (PIND2 >= 3) то не работает
      {s++;}
}

void shim_start()
{
   if (j==6)
   {goto jstop;
   }
//   ASSR=0x00;
//   // Установим биты COM1A1-COM1A0:0b10,означает сброс вывода канала A при сравнении Clear OC1A/OC1B on Compare Match, set OC1A/OC1B at BOTTOM (non-inverting mode), for Fast PWM. page135
//   TCCR1A |= (1 << COM1A1)|(0 << COM1A0)|(0 << WGM11)|(1 << WGM10);
//   // Установим биты WGM13-10:0b0101, согласно таблице это будет режим - Fast PWM, 8-bit, где верхний предел счета задается битом ICR1. page136
//   TCCR1B |= (0 << WGM13)|(1 << WGM12)|(1 << CS12)|(0 << CS11)|(0 << CS10);
//   // Битами CS12-10:0b100 задаем источник тактового сигнала для таймера МК, clkI/O/256 (From prescaler)=31250Hz. page137
//   TCNT1 = 0x00; // начальная установка счетчика
//   TIMSK1=0x00;
//   ICR1 = 0x20;  // задаем период ШИМ, здесь у нас число 255,
//   // по формуле  fPWM=fclk_I/O/N*(1+ICR1) вычисляем частоту ШИМ, она будет равна 8MHz/256(1+2)=10416Hz
//    // для FR3706 надо 50000Hz, irlm0030 надо 16666Hz<
//    OCR1A = 0x50; // начальный коэффициент заполнения ШИМ 0xC8=200, 0x50=1/3
   jstop:
   j=0;
}

int main(void)
{
      DDRC=0x3f;  //0b00111111 0-ввод 1-вывод
      PORTC=0x00; //
      DDRD=0x00; //0b00001100 DDRD=0x0C;
      PORTD=0xff; // 0b11111111 PORTD=0xff;
      DDRB=0xFF; //0b11000111 PB1(OC1A)-ШИМ DDRB=0xC7;
      PORTB=0x00; //PORTB=0x00;
   EICRA  =  (1<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00);   // настройка срабатывания прерываний The falling edge of INT1 generates an interrupt request
   PCICR  |= (1<<PCIE2) | (0<<PCIE1) | (0<<PCIE0);// разрешение прерываний PCINT23...16
   PCMSK2=0b11000000; //разрешаем прерывание pcint23 pcint22
   EIMSK=0b11000011; //разрешаем прерывание int0 и int1 - кнопка
   MCUCR=0b00001111;// IVSEL, IVCE
   sei(); //Глобальное разрешение прерываний
      //Установка таймера0
   //TCCR0A |= (0 << COM1A1)|(0 << COM1A0)|(1 << WGM01)|(0 << WGM00); //биты COM Normal port operation, OC0A disconnected, WGM T/C in CTC mode
   //TCCR0B |= (0 << WGM02)|(0 << CS02)|(0 << CS01)|(1 << CS00); //биты CS fclk_I/O/1
   //TCNT0=0x00;
   //OCR0A=0x80;   
   //----------//
   //TCCR0A=0x00; //TCCR0=0x00;
//   TCCR0B=0x01; //TCCR0=0x00;
//   TCNT0=0x00;
   // Timer/Counter 1 initialization
   TCCR1A=0x00; //для Compare Output Mode, non-PWM COM1A1/COM1B1=0 COM1A0/COM1B0=0 Normal port operation, OC1A/OC1B disconnected.
   TCCR1B=0x01; //Waveform Generation Mode Bit Description WGM10-13=0 Normal //CS12-10=001 No prescaling
   TCNT1H=0x00;
   TCNT1L=0x00;
   ICR1H=0x00;
   ICR1L=0x00;
   //OCR1AH=0x00;
   //OCR1AL=0x00;
   OCR1BH=0x00; //OCR1B compared with the counter value (TCNT1)
   OCR1BL=0x00;
   // Timer/Counter 2 initialization
   //ASSR=0x00;
   //TCCR2=0x00; //TCCR2=0x00;
   //TCNT2=0x00;
   //OCR2=0x00; //OCR2=0x00;
   //MCUCR=0x00;
   //TIMSK0=0x04; //TIMSK=0x04;
//   TIMSK1=0x04; //TIMSK=0x04; //OCIE1B=1
   //ACSR=0x80;
   //SFIOR=0x00;
   //----------//
   
    while(1)
    {      
      //if (PIND3 == 3) //(PIND3 == 3) работает если кнопка не нажата
    //{s=8;}
      //if (PIND2 == 2) //(PIND2 == 2) работает если кнопка не нажата
   //{s=8;}
      //----------//
      if(mButt_1.up){     // Если кнопка была нажата -> отжата
      mButt_1.up=0;                   // Сбрасываем флаг
      PORT_LED_1 ^=(1<<PIN_LED_1);    // Инвертируем светодиод №1
      s++;
      }
      //----------//
      if(mButt_1.down){   // Если кнопка была отжата -> нажата
      mButt_1.down=0;                 // Сбрасываем флаг
      PORT_LED_2 ^=(1<<PIN_LED_2);    // Инвертируем светодиод №2
      s++;
      }
      //----------//   
      //----------//
      if(mButt_2.up){     // Если кнопка была нажата -> отжата
      mButt_2.up=0;                   // Сбрасываем флаг
      PORT_LED_1 ^=(1<<PIN_LED_1);    // Инвертируем светодиод №1
      s--;
      }
      //----------//
      if(mButt_2.down){   // Если кнопка была отжата -> нажата
      mButt_2.down=0;                 // Сбрасываем флаг
      PORT_LED_2 ^=(1<<PIN_LED_2);    // Инвертируем светодиод №2
      s--;
      }
      //----------//   
              start:
              if (b == 1)
              {s=5;
                 FLAG &= ~ COUNTDOWN;
                 b++;
              }
              
              if (s > 9)
              s--;
              else if (s == 0)
              s++;
              if (FLAG == COUNTDOWN)
              {
                 //cli();
               char i = 0;
                 while (s > -1)
                 {
                    if (s > -1)
                    {
                       a = 5;
                       c = 5;
                       if (FLAG != COUNTDOWN)
                       {
                          goto start;
                       }
                       PORTB |= _BV(PB6); // чтобы мигала точка на индикаторе
                       _delay_ms(250);
                       PORTB &= ~_BV(PB6);
                       _delay_ms(250);
                    }
                    PORTC = digits[s];
                    PORTB = digita[s];
                    _delay_ms(500);
                    PORTB &= ~_BV(PB7); //Красный светодиод
                    _delay_ms(500);
                    PORTB |= _BV(PB7);
                    s--;
                    if (s == 0)
                    {
                       PORTC = digits[s];
                       PORTB = digita[s];                     
                     j=0;
                     shim_start();
                       PORTB &= ~_BV(PB2); //Зеленый светодиод
                       _delay_ms(250);
                       PORTB |= _BV(PB2);
                       _delay_ms(250);
                    }
                  i++;
                     if (i>=10)
                     {ICR1 = 0x00;
                     OCR1A = 0x00;}
                 }
                 sei();
                 FLAG &= ~ COUNTDOWN;
              }
              PORTC = digits[s];
              PORTB = digita[s];

    }
}


2 Engineer_Keen
Нажимал в протеусе и на плате, но все работало с прошлой допотопной версией программы.
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3868
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: Помогите опросить кнопку

Сообщение Engineer_Keen »

service47 писал(а):Нажимал в протеусе и на плате, но все работало с прошлой допотопной версией программы.

Работать оно может, но если записать в DDR и PORT "1", а потом закоротить этот пин на землю, то верхний ключ сгорит (или PORT в "0", а кнопкой соединить с +5В - нижний сдохнет), этот пин больше не сможет работать как выход, только как вход, если повезет. Нельзя соединять напрямую с питанием пины, сконфигурированные как выходы (DDR=1).
Аватара пользователя
zero648
Вымогатель припоя
Сообщения: 650
Зарегистрирован: Пн июн 18, 2012 12:01:04
Откуда: Челябинская область, Копейск

Re: Помогите опросить кнопку

Сообщение zero648 »

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

      DDRD=0x00; //0b00001100 DDRD=0x0C;
      PORTD=0xff; // 0b11111111 PORTD=0xff;
   EICRA  =  (1<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00);   // настройка срабатывания прерываний The falling edge of INT1 generates an interrupt request
   EIMSK=0b00000011; //разрешаем прерывание int0 и int1 - кнопка
   sei(); //Глобальное разрешение прерываний

Этого вполне достаточно, чтобы понять что произошло с кнопками в момент срабатывания прерываний, дальше остается только отфильтровать ложные срабатывания, все остальное относительно кнопок просто мусор.
Ответить

Вернуться в «Периферия»