Зарегистрирован: Вт мар 12, 2013 16:05:45 Сообщений: 219
Рейтинг сообщения:0
Получается и так и есть в протеусе, что при нажатии кнопки и не отпускании происходит прерывание по спадающему фронту (т.е. получается теоретически лог.0), порт настроен на вход DDRD=0x00; с подтягивающими резисторами PORTD=0xff; (которые если отключить то прерывание не будет работать) бит PUD в регистре MCUCR отключен, прерывания разрешены и глобально разрешены. Пишу в обработчике прерываний:
Код:
ISR(INT1_vect) //MINUS PIND3 {_delay_ms(200); if (PIND3 == 0) {s--;} }
и в протеусе нет реакции на нажатие кнопки, т.е. на входе порта нет лог.0. но если прописать if (PIND3 == 3) то прерывание работает, да и это же условие выполняется если кнопка не нажата. С другой стороны в коде Alex'a прописаны:
Код:
#define ACT_BUTT_LEV 0 // Активный уровень нажатых кнопок
т.е. мне туда прописывать эту тройку, но тогда дальше:
Код:
if((mButt_1.cur==ACT_BUTT_LEV) && (mButt_1.prev!=ACT_BUTT_LEV)) // Если текущее значение - "нажата" и предыдущее - "не нажата"
не будет работать из-за этой тройки, срабатывающей всегда.
Задача стоит такая сделать отслеживание кнопок от таймера: При нажатии любой кнопки происходит увеличение или уменьшении значения на индикаторе на 1 (это работает, но не на таймере, а на векторах прерываний), При нажатии и удержании в течении 3сек. происходит запуск обратного отсчета (работает если отслеживать циклом while флаги в регистре EIFR).
Зарегистрирован: Вт мар 12, 2013 16:05:45 Сообщений: 219
Рейтинг сообщения:0
Новая концепция: записывать чтобы-там ни было на входе порта в переменную и работать уже с ней: Только такое условие работает с каждой кнопкой по отдельности, а вместе они почему то конфликтуют.
Код:
int Knopka_Staroe, Knopka_Novoe; int Knopka_Star2, Knopka_Nov2;
Knopka_Staroe = (PIND&=(1<<3)); // Записываем старое состояние кнопки в переменную Knopka_Staroe. if (Knopka_Staroe) // Если Knopka_Staroe равно 1 (кнопка не нажата), то... { _delay_ms(80); // Пауза для подавления дребезга контактов. Knopka_Novoe = (PIND&=(1<<3)); //...считываем новое состояние кнопки.
if (!Knopka_Novoe) // Новое состояние кнопки должно быть равно 0 (нажата). { // В этом случае падающий фронт сформирован и можно инвертировать пины. _delay_ms(80); // Пауза для подавления дребезга контактов. s--; } }
// Knopka_Star2 = (PIND&=(1<<2)); // Записываем старое состояние кнопки в переменную Knopka_Staroe. // if (Knopka_Star2) // Если Knopka_Staroe равно 1 (кнопка не нажата), то... // { // _delay_ms(80); // Пауза для подавления дребезга контактов. // Knopka_Nov2 = (PIND&=(1<<2)); //...считываем новое состояние кнопки. // // if (!Knopka_Nov2) // Новое состояние кнопки должно быть равно 0 (нажата). // { // В этом случае падающий фронт сформирован и можно инвертировать пины. // _delay_ms(80); // Пауза для подавления дребезга контактов. // s++; // } // }
да и вообще если прерывание наступило, зачем тогда в прерывании проверять кнопку, если и так понятно, что она нажата, можно смело выходить из прерывания, и уже в основном цикле проверять это нажатие еще несколько раз на антидребезг, отвыкайте от паузного антидребезга и забудьте слово пауза, есть другое слово - игнор.
Это определение бита а НЕ ПОРТА, все правильно. PIND3 - константа, которую НАДО подставлять в сравнение вроде PORTD = (1<<PIND3). На этой концепции построено все. PINB3=PINC3=PIND3=3 ведь все эти биты портов 3-и по счету!!! Разница в имени константы, указывающая на порт всего лишь для удобства.
PORTD = 0b10000000; // Подключаем подтягивающий PULL-UP резистор к 7 пину порта D. DDRD = 0b00000000; // Настроим порт D на ввод информации. // Важна последовательность! Сперва подключаем PULL-UP резистор, // и только потом настраиваем порт на ввод, иначе кнопка работать не будет.
даже это не помогло.
Вобщем в связи с новой концепцией посмотрите код вначале цикла while(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 // /******************************************************************/ int Knopka_Staroe, Knopka_Novoe; int Knopka_Star2, Knopka_Nov2; /******************************************************************/ 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 == 0) //(PIND3 <= 3) работает (PIND3 <= 2,95) (PIND3 == 3) {s--;} }
ISR(INT0_vect) //PLUS PIND2 {_delay_ms(200); if (PIND2 == 0) //(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; }
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=0b00000000; //разрешаем прерывание int0 и int1 - кнопка EIMSK=0b11000011; //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) { Knopka_Staroe = (PIND&=(1<<3)); // Записываем старое состояние кнопки в переменную Knopka_Staroe. if (Knopka_Staroe) // Если Knopka_Staroe равно 1 (кнопка не нажата), то... { //_delay_ms(80); // Пауза для подавления дребезга контактов. Knopka_Novoe = (PIND&=(1<<3)); //...считываем новое состояние кнопки.
if (!Knopka_Novoe) // Новое состояние кнопки должно быть равно 0 (нажата). { // В этом случае падающий фронт сформирован и можно инвертировать пины. //_delay_ms(80); // Пауза для подавления дребезга контактов. s--; } }
// Knopka_Star2 = (PIND&=(1<<2)); // Записываем старое состояние кнопки в переменную Knopka_Staroe. // if (Knopka_Star2) // Если Knopka_Staroe равно 1 (кнопка не нажата), то... // { // //_delay_ms(80); // Пауза для подавления дребезга контактов. // Knopka_Nov2 = (PIND&=(1<<2)); //...считываем новое состояние кнопки. // // if (!Knopka_Nov2) // Новое состояние кнопки должно быть равно 0 (нажата). // { // В этом случае падающий фронт сформирован и можно инвертировать пины. // //_delay_ms(80); // Пауза для подавления дребезга контактов. // s++; // } // }
//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];
Зарегистрирован: Вт мар 12, 2013 16:05:45 Сообщений: 219
Рейтинг сообщения:0
a_skr писал(а):
Цитата:
Knopka_Staroe = (PIND&=(1<<3)); // Записываем старое состояние кнопки в переменную Knopka_Staroe.
Зачем там &= ? Где _BV(), где (1<<PBx), где (1<<3). Опишите задачу. Составьте алгоритм. Очень сложно читать код.
Как я понимаю (PIND&=(1<<3)) это чтение состояния третьего пина порта, в любом случае что-бы это ни-было функция в протеусе действительно считывает замыкание кнопки на землю и реагирует на это.
Задача уже писал, вот она: При нажатии любой кнопки происходит увеличение или уменьшении значения на индикаторе на 1 (это работает, но не на таймере, а на векторах прерываний), При нажатии и удержании обоих клавиш в течении 3сек. происходит запуск обратного отсчета (работает если отслеживать циклом while флаги в регистре EIFR).
Алгоритм: 1. Опрос кнопок 2. Замкнута 1якнопка goto3 else goto4 3. Увеличить значение на 1 4. Замкнута 2якнопка goto5 else goto6 5. Уменьшить значение на 1 6. Замкнуты обе кнопки и удерживаются в течении 3сек. goto7 else goto1 7. Запуск обратного отсчета
Остальной код работает. Постараюсь выкладывать код покомпактнее.
Как я понимаю (PIND&=(1<<3)) это чтение состояния третьего пина порта
Это не так. a = (PIND&=(1<<3)); соответствует следующему коду:
Код:
PIND = PIND & (1<<3); // - не имеет смысла, т.к. регистр PIND только на чтение a = PIND; // - в "a" попадут все биты PIND
Правильные варианты:
Код:
a = PIND & (1<<3); // - в "a" будет или ноль или 8 a = PIND & (1<<3) ? 1 : 0; // - в "a" будет или ноль или 1 a = (PIND>>3) & 1; // - тоже самое, займет меньше кода
Карма: 90
Рейтинг сообщений: 1432
Зарегистрирован: Чт мар 18, 2010 23:09:57 Сообщений: 4599 Откуда: Планета Земля
Рейтинг сообщения:0 Медали: 1
Alexeyslav писал(а):
Это определение бита а НЕ ПОРТА, все правильно. PIND3 - константа, которую НАДО подставлять в сравнение вроде PORTD = (1<<PIND3)
Интересно, если это константа, зачем тогда в имени буква "D" ? Она (эта константа) как то привязана конкретно к этому порту ? Глупое, на мой взгляд, имя для объявления константы-номера бита, малоинформативное. Я, например, увидев её, даже и не понял, что под ней может скрываться цифра 3. На первый взгляд, PIND3 - Это 3-ий пин порта D. Где логика ....
Чисто гипотетически, вдруг выйдет контроллер, в котором какая-нибудь ножка PD8 будет адресоваться через бит 0 в регистре PINDH, и тогда логично объявить константы PIND8 и PD8, равные нулю... а в порту C не будет ножки PC8, тогда константы PINC8 не будет и компилятор даст ошибку при ее использовании.
PS. ну есть же контроллеры, в которых только порт B, например и не все 8 бит задействованы...
Зарегистрирован: Вт мар 12, 2013 16:05:45 Сообщений: 219
Рейтинг сообщения:0
В таком коде срабатывает первое if когда кнопка не нажата, а при нажатии кнопки, т.е. замыкании ее на землю второй if не срабатывает.
Код:
Knopka_Staroe = PIND3; // Записываем старое состояние кнопки в переменную Knopka_Staroe. if (Knopka_Staroe) // Если Knopka_Staroe равно 1 (кнопка не нажата), то... { _delay_ms(80); // Пауза для подавления дребезга контактов. Knopka_Novoe = PIND3; //...считываем новое состояние кнопки.
if (!Knopka_Novoe) // Новое состояние кнопки должно быть равно 0 (нажата). { // В этом случае падающий фронт сформирован и можно инвертировать пины. _delay_ms(80); // Пауза для подавления дребезга контактов. s--; } }
Зарегистрирован: Вт мар 12, 2013 16:05:45 Сообщений: 219
Рейтинг сообщения:0
a_skr спасибо, заработали обе кнопки, только три раза через раз срабатывают.
Код:
Knopka_Staroe = PIND & (1<<3) ? 1 : 0; // Записываем старое состояние кнопки в переменную Knopka_Staroe. if (Knopka_Staroe) // Если Knopka_Staroe равно 1 (кнопка не нажата), то... { _delay_ms(80); // Пауза для подавления дребезга контактов. Knopka_Novoe = PIND & (1<<3) ? 1 : 0; //...считываем новое состояние кнопки.
if (!Knopka_Novoe) // Новое состояние кнопки должно быть равно 0 (нажата). { // В этом случае падающий фронт сформирован и можно инвертировать пины. _delay_ms(80); // Пауза для подавления дребезга контактов. s--; } }
Knopka_Star2 = PIND & (1<<2) ? 1 : 0; // Записываем старое состояние кнопки в переменную Knopka_Staroe. if (Knopka_Star2) // Если Knopka_Staroe равно 1 (кнопка не нажата), то... { _delay_ms(80); // Пауза для подавления дребезга контактов. Knopka_Nov2 = PIND & (1<<2) ? 1 : 0; //...считываем новое состояние кнопки.
if (!Knopka_Nov2) // Новое состояние кнопки должно быть равно 0 (нажата). { // В этом случае падающий фронт сформирован и можно инвертировать пины. _delay_ms(80); // Пауза для подавления дребезга контактов. s++; } }
Зарегистрирован: Вт мар 12, 2013 16:05:45 Сообщений: 219
Рейтинг сообщения:0
Данный код в цикле while(1); работает раз через три, как сделать чтобы если нажата одна кнопка срабатывала одна команда, если другая то соответственно другая и стабильно. Прерывания отключены. Может дело в дэлэях, может есть способ их не использовать...
Спойлер
Код:
Knopka_Staroe = PIND & (1<<3) ? 1 : 0; if (Knopka_Staroe) //кнопка не нажата тогда if=1 { _delay_ms(20); Knopka_Novoe = PIND & (1<<3) ? 1 : 0; Knopka_Nov2 = PIND & (1<<2) ? 1 : 0; if(!Knopka_Novoe && Knopka_Nov2) //кнопка нажата и кнопка не нажата тогда if=1 { PORTB |= _BV(PB6); //точка на индикаторе загорается _delay_ms(100); s--; } PORTB &= ~_BV(PB6); //точка на индикаторе гаснет }
Knopka_Star2 = PIND & (1<<2) ? 1 : 0; if (Knopka_Star2) { _delay_ms(20); Knopka_Novoe = PIND & (1<<3) ? 1 : 0; Knopka_Nov2 = PIND & (1<<2) ? 1 : 0; if(Knopka_Novoe && !Knopka_Nov2) { PORTB |= _BV(PB6); //точка на индикаторе загорается _delay_ms(100); s++; } PORTB &= ~_BV(PB6); //точка на индикаторе гаснет }
Добрый день, Коты! Получилась такая тема: остались свободными 2 ножки МК, которые как раз INT0 и INT1. И мне как раз нужно сделать 2 кнопки. И вот я думаю, что легче для программы, подключить библиотеку нажатия кнопок, в которой ловится 0 на ноге, потом заданное количество раз перепроверяется и даёт на выходе разрешение на выполнение кода. Или использовать внешнее прерывание, допустим, по спадающему фронту на ножках?
_________________ Почему я здесь и задаю тупые вопросы? Потому что хочу научиться.
Подключение через INT0 или INT1 оправдано только если надо выводить устройство из энергосберегающих режимов... В других случаях лучше периодически (в прерывании) опрашивать линии кнопок.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения