Обсуждаем контроллеры компании Atmel.
Ответить

Attiny13a sleep и interrupt по int0

Вт окт 16, 2018 21:42:39

Добрый день. Только начал осваивать AVR, поэтому хочу задать вам кучу глупых вопросов.

Попросили меня сделать реквезит - фонарик на трехцветном светодиоде, который умеет по кнопке выбирать цвет свечения, запоминать его и отключаться. Задача, собственно, простая, программатор и запас 13а у человека был, программку я на основе примеров сварганил. Но оказалось, что attiny13a, если не заморачиваться с энергоэффективностью очень неплохо кушает - фонарика на 300 мАч батарейке хватало на сутки в выключенном состоянии, потому как работало все на delay. Начал вникать в сон, interrupt и wdr - набил себе граблями огромную шишку.

Проблема 1 - начинал я это делать в CVAVR, но у меня происходит что-то непонятное с библиотеками. Просто нет ни sleep.h, ни interrupt.h, ни wdr.h. Как их к нему прилепить я не понял.

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

Собственно, вот простая мигалка светодиодом на том же delay, которая должна падать в сон при длинном нажатии и по нему просыпаться.

Код:
#include <avr/io.h>         
#include <avr/sleep.h>     
#include <avr/interrupt.h>   
#include <util/delay.h>     

typedef unsigned char byte;
unsigned char trig, count;
unsigned short pushtime;                                       
           
              
SIGNAL(SIG_INTERRUPT0)
{   
   disable_int0();
}


int main()
{
   
count = 0;   
   
   while(1)
   {
   
     if ((PINB & (1<<PB1))==0)   
       {
        pushtime++; 
        if ( pushtime>15) 
         {
           
               
          pushtime=0;
     while ((PINB & (1<<PB1))==0)
     {
        delay_ms(10);
     }
     sleep_power_down();
    
         }                                                                           
       }
       else
       {
     if (pushtime>2 & pushtime<=15)
     {
       PORTB |= _BV(PB2);
       delay_ms(500);
       PORTB &= ~_BV(PB2);
       delay_ms(100);
       PORTB |= _BV(PB2);
       delay_ms(500);
       PORTB &= ~_BV(PB2);
     }
     pushtime=0;
       }
       if(count==10)
       {
     PORTB |= _BV(PB0);
       }
       if (count==20)
       {
     PORTB &= ~_BV(PB0);
     count=0;
       }
       
       
      count++;
      delay_ms(100);
   
     
   }
}


Но она выдает ошибки

Код:
avr-gcc.exe -mmcu=attiny13  -o "./Debug.elf" "main.o"
main.o: In function `main':
C:\Users\nikollor\AppData\Local\Temp\d2d5e583d4a14410bb8265b98c3f5f3c\ATtiny13\Debug/../main.c:35: undefined reference to `delay_ms'
C:\Users\nikollor\AppData\Local\Temp\d2d5e583d4a14410bb8265b98c3f5f3c\ATtiny13\Debug/../main.c:37: undefined reference to `sleep_power_down'
C:\Users\nikollor\AppData\Local\Temp\d2d5e583d4a14410bb8265b98c3f5f3c\ATtiny13\Debug/../main.c:46: undefined reference to `delay_ms'
C:\Users\nikollor\AppData\Local\Temp\d2d5e583d4a14410bb8265b98c3f5f3c\ATtiny13\Debug/../main.c:48: undefined reference to `delay_ms'
C:\Users\nikollor\AppData\Local\Temp\d2d5e583d4a14410bb8265b98c3f5f3c\ATtiny13\Debug/../main.c:50: undefined reference to `delay_ms'
C:\Users\nikollor\AppData\Local\Temp\d2d5e583d4a14410bb8265b98c3f5f3c\ATtiny13\Debug/../main.c:67: undefined reference to `delay_ms'
main.o: In function `__vector_1':
C:\Users\nikollor\AppData\Local\Temp\d2d5e583d4a14410bb8265b98c3f5f3c\ATtiny13\Debug/../main.c:13: undefined reference to `disable_int0'
make: *** [Debug.elf] Error 1

Error code 2


и я их абсолютно не понимаю. Ткните носом, пожалуйста. Можно даже тапком.

Re: Attiny13a sleep и interrupt по int0

Ср окт 17, 2018 05:29:50

Неопределенные функции delay_ms и т.д.
В WINAVR они по-другому пишутся. Посмотрите библиотеки изнутри или хелпы по этим библиотекам.

Re: Attiny13a sleep и interrupt по int0

Ср окт 17, 2018 13:41:45

Неопределенные функции delay_ms и т.д.
В WINAVR они по-другому пишутся. Посмотрите библиотеки изнутри или хелпы по этим библиотекам.


Спасибо. Как ни странно, даже просмотрев библиотеки не заметил что delay в WinAVR через "_" пишется.

Еще проблема - исправил функции, заработало, уходит в сон и будится, но:

При первом уходе в сон зажигается индикатор сна, все гаснет, при пробуждении индикатор сна мигает и гаснет. (прописано в interrupt)
Но при втором и последующих уходах в сон сразу после ухода в сон индикатор сна мигает и гаснет но тем не менее девайс уходит в сон, то есть сразу после ухода в сон исполняется то, что прописано в interrupt'е, но сон не прерывается. Прерывания сразу после пробуждения отключаются и включаются перед сном. Что я забыл?

Код:
#define F_CPU 1000000UL
#include <avr/io.h>         
#include <avr/sleep.h>     
#include <avr/interrupt.h>   
#include <util/delay.h>     

typedef unsigned char byte;
unsigned int trig, count;
unsigned short pushtime;                                       
           
              
ISR(PCINT0_vect) //мигаем лампочкой sleep
{
   PORTB &= ~_BV(PB4);
   _delay_ms(100);
   PORTB |= _BV(PB4);
   _delay_ms(200);
   PORTB &= ~_BV(PB4);
   _delay_ms(100);
   PORTB |= _BV(PB4);
   _delay_ms(200);
   PORTB &= ~_BV(PB4);
}


int main()
{
   
 DDRB=0b00011101;
PORTB=0b00000010;
   
count = 0;   
   
   while(1)
   {
   
     if ((PINB & (1<<PB1))==0)   
       {
        pushtime++; 
        if ( pushtime>15)  //длинное нажатие - уход в сон
         {
           
               
          pushtime=0;
     while ((PINB & (1<<PB1))==0)
     {
        _delay_ms(10);
     }
     PORTB |= _BV(PB4);  //все лампочки выключаем, лампочку sleep включаем
     PORTB &= ~_BV(PB2);
     PORTB &= ~_BV(PB0);
    
     GIMSK |= (1<<PCIE);                    // Enable Pin Change Interrupts
     PCMSK |= (1 << PB1);
    
     sei ();
     set_sleep_mode (SLEEP_MODE_PWR_DOWN);
     sleep_enable ();
    
     sleep_cpu ();
     sleep_disable ();
     cli ();
         }
    _delay_ms(10);
       }
       else
       {
     if (pushtime>2 & pushtime<=15) //короткое нажатие
     {
       PORTB |= _BV(PB2);  //мигаем лампочкой кнопки
       _delay_ms(500);
       PORTB &= ~_BV(PB2);
       _delay_ms(100);
       PORTB |= _BV(PB2);
       _delay_ms(500);
       PORTB &= ~_BV(PB2);
     }
     pushtime=0;
       }
       if(count==10)   //перемигиваемся светодиодом "работа"
       {
     PORTB |= _BV(PB0);
       }
       if (count>=20)
       {
     PORTB &= ~_BV(PB0);
     count=0;
       }
       
       
      count++;
      _delay_ms(100);
   
     
   }
}


Добавлено after 6 minutes 35 seconds:
При прерывании, выводящем из сна, кстати, код из interrupt'а исполняется еще раз.
Ответить