Страница 1 из 3

RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Сб апр 20, 2013 23:27:57
robototechnik
Всем доброго времени суток)
Имею проблемы с программой для управления RGB светодиодом с помощью ATtiny13, который при нажатии на кнопку, подключенную к INT0 должен засыпать и соответственно выходить из спячки(power down). Вот есть у меня такая прога а она что то не пашет, в смысле пашет не корректно. Светодиод меняет цвет только при подключенном программаторе(AVR ISP mkII), при отключении его светодиод не пашет и на кнопку проц не реагирует. При подключенном программаторе при нажатии на кнопку светодиод вырубается и остается в таком состоянии все время пока нажата кнопка. Потом врубается обратно и что странно с разгоном процессора, в фьюзах стоит 9.6 МГц + 14СК+64мс то есть светодиод еще какое то вемя разгорается)такое ощущение что проц ресетится. Стоит так же добавить что при отключенном программаторе если схватится пальцем за VCC светодиод светится где то 2 секунды а потом опять ресетится) Какие то непонятки) Гляньте люди добрые од может что не так написал, всетаки не профи) Буду очень благодарен)

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

#define F_CPU 9600000UL 
#include <avr/io.h> 
#include <avr/interrupt.h> 
#include <util/delay.h> 
#include <avr/sleep.h> 
unsigned char e; 
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status); 
unsigned char pwm[3]={255,255,255}; 
unsigned char to[3]={255,255,255}; 
int main(void) 
{ 
DDRB = 0b00011001; 
PORTB = 0b00011011; 

GIMSK = 0b01000000; 
MCUCR = 0b00000000; 

TCCR0A = 0x00; 
TCCR0B = 0x01; 
TIMSK0 = 0b00000010; 
sei(); 
while(1){ 
if (pwm[0]<to[0]) pwm[0]++; 
if (pwm[0]>to[0]) pwm[0]--; 
if (pwm[1]<to[1]) pwm[1]++; 
if (pwm[1]>to[1]) pwm[1]--; 
if (pwm[2]<to[2]) pwm[2]++; 
if (pwm[2]>to[2]) pwm[2]--; 
if(pwm[0]==to[0]&&pwm[1]==to[1]&&pwm[2]==to[2]) 
{ 
to[0]=rand()%255; 
to[1]=rand()%255; 
to[2]=rand()%255; 
} 
_delay_ms(20); 
} 
} 
ISR(TIM0_OVF_vect) 
{ 
if(e==255) 
{ 
e=0; 
PORTB = 0b00011001; 
} 
abc(pwm[0],pwm[1],pwm[2],e); 
e++; 
} 
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status) 
{ 
if((status==a)) PORTB&= ~(1<<3); 
if((status==b)) PORTB&= ~(1<<4); 
if((status==c)) PORTB&= ~(1<<0); 
} 

ISR(INT0_vect) { 
 TIMSK0 = 0b00000000; 
 cli(); 
 set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
 sleep_mode(); 
 sleep_disable(); 
 TIMSK0 = 0b00000010; 
 sei(); 
} 

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вс апр 21, 2013 01:59:45
vitalik_1984
А вы уверены, что у вас это компилируется? Я не нашел блока фигурных скобок для функции abc();
И еще в ней переменные всегда анициализируются при каждом вызове.
Нужно добавить static перед объявлением.
И что она вообще делает эта функция?

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вс апр 21, 2013 09:21:50
robototechnik
все компилируется и ошибок не выдает, без понятия)
я ж поэтому и в недоумении)все пучком, а прога не пашет)
признаться код составлял из частей своего и из частей инетовского кода)поэтому не до конца доезжаю что за чем)знаю только что если убрать из кода все что связано с прерыванием INT0, код работает без проблем.
как только добавляю регистры INT0 и внизу функцию для выполнения по вектору сразу проблемы((((((
есть идеи в чем может быть ошибка?
спасибо)

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вс апр 21, 2013 15:06:46
vitalik_1984
А все, понял. Недосмотрел что у вас еще и внизу объявление функции есть. Просто редко кто прототипами пользуется :))
Функция abc не нужна, можете все это сделать в самом прерывании и сэкономите несколько тактов в каждом прерывании по переполнению.

По внешнему прерыванию: что конкретно должно происходить при нажатии на кнопку?

Еще важный момент

при инициализации объявляете
DDRB = 0b00011001;
PORTB = 0b00011011;

далее в самой программе
пишете для погашения светодиодов:
PORTB = 0b00011001;
но ведь у вас на ноге 1 кнопка и получается происходит смена уровня с 1 на 0 за счет отключения подтяжки.
используйте
PORTB &= ~0b00011001;
для сброса битов, так не будет остальной порт задевать.

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вс апр 21, 2013 18:06:25
robototechnik
большое спасибо!!!не обратил на эту мелочь внимания)
у меня светодиод с общим анодом поэтому немного по другому код поправил)плюс еще одна поправочка и теперь все отлично выключается....но не включается(((
то есть теперь все работает даже при отключенном программаторе)при нажатии на кнопку светодиоды вырубаются,проц спит)
но при последующем нажатии проц не просыпается(((
как это можно поправить?)))))))
спасибо заранее)
вот так код выглядит теперь)

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

#define F_CPU 9600000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>
unsigned char e;
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status);
unsigned char pwm[3]={255,255,255};
unsigned char to[3]={255,255,255};
int main(void)
{
DDRB = 0b00011001; 
PORTB = 0b00011011;

GIMSK = (1<<INT0);

TCCR0A = 0x00;
TCCR0B = (1<<CS00);
TIMSK0 = (1<<TOIE0);
sei();
while(1){
if (pwm[0]<to[0]) pwm[0]++;
if (pwm[0]>to[0]) pwm[0]--;
if (pwm[1]<to[1]) pwm[1]++;
if (pwm[1]>to[1]) pwm[1]--;
if (pwm[2]<to[2]) pwm[2]++;
if (pwm[2]>to[2]) pwm[2]--;
if(pwm[0]==to[0]&&pwm[1]==to[1]&&pwm[2]==to[2]) 
{
to[0]=rand()%255; 
to[1]=rand()%255;
to[2]=rand()%255;
}
_delay_ms(20);
}
}
ISR(TIM0_OVF_vect)
{
if(e==255)
{
e=0;
PORTB |= 0b00011001;
}
abc(pwm[0],pwm[1],pwm[2],e);
e++;
}
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status)
{
if((status==a)) PORTB&= ~(1<<3);
if((status==b)) PORTB&= ~(1<<4);
if((status==c)) PORTB&= ~(1<<0);
}

ISR(INT0_vect) { 
 TIMSK0 = (0<<TOIE0);
 PORTB |= 0b00011001;
 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 sleep_enable(); 
 sleep_mode();
 sleep_disable();
 TIMSK0 = (1<<TOIE0);
}	

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вс апр 21, 2013 20:30:08
vitalik_1984
Для начала разделить включение и выключение, например ввести доп переменную в которой будет храниться что нужно делать в данный момент.
Так получается при нажатии проц засыпает, потом просыпается, выходит из прерывания и снова входит в прерывание, так как флаг прерывания поднят. нужно либо его очистить установив в 1 перед выходом из прерывания либо разделить пробуждение и сон как было написано выше.

Еще я не разбирался что там за режим прерывания по int0 и вас назначен, нужно чтобы перед сном был установлен режим по низкому уровню, иначе проц не проснется.

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вс апр 21, 2013 21:08:34
robototechnik
немного не понял каким образом и что разделить)можно на примере?)
очищать флаг прерывания нет смысла так как в даташите написано что при конфигурации на низкий уровень,так как у меня сконфигурировано,флаг всегда ноль!
режим по низкому уровню у меня)не знаю в чем затык)
я думл что при засыпании проц не выходит из прерывания, а остается на том месте где я написал ему спать, при включении он просыпается сразу в прерывании и заканчивает его работу....получается если он выходит то....кажется понял идею с переменной)а ее значение будет сохранятся при спячке?надо наверное в епром писать?

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вс апр 21, 2013 22:02:38
vitalik_1984
для каждого прерывания есть один или несколько регистров управления, и регистр состояния.
То есть активировать разрешение прерывания можно через регистр управления, а считать через регистр состояния.
То есть аппаратно при наступлении события прерывания выставляется флаг.
Далее через один такт идет сравнение с разрешенными прерываниями если это прерывание разрешено и установлены флаги прерывания и глобальное разрешение, тогда происходим переход на вектор прерывания.и далее к обработке.
Все векторы прописаны в паспорте на Мк.(datasheet)

А для очистки флага нужно присвоить ему значение 1.

поищите в паспорте interrupt flag мне на телефоне лениво искать.

Разделить это значит вошли в прерывание
если А равна 1, то спать и А =0, если нет, то просыпаться и А =1

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Пн апр 22, 2013 18:00:34
robototechnik
прежде чем я пожалуюсь на то что у меня не получилось, скажите пожалуйста, после ухода в спячку где останавливается программа и после выходи из спячки где она начинается...и что происходит с флагом после входа в спячку и после выхода?
если после этой информации код не налажу, скину что получилось...

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Пн апр 22, 2013 19:15:56
vitalik_1984
Вообще должен с того же места где и заснул. Только вот незадача- просыпаясь по ИНТ0 одновременно устанавливается флаг необходимости вызова прерывания( сбрасывается он после входа в прерывание, но они у нас аппаратно запрещены так как мы уже в нем) то есть сначала выходит из него, и тут же опять заходит и ложится спать.
Вот выдержка из паспорта МК :
ATtiny13 писал(а):There are basically two types of interrupts. The first type is triggered by an event that sets the
Interrupt Flag. For these interrupts, the Program Counter is vectored to the actual Interrupt Vec-
tor in order to execute the interrupt handling routine, and hardware clears the corresponding
Interrupt Flag. Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s)
to be cleared. If an interrupt condition occurs while the corresponding interrupt enable bit is
cleared, the Interrupt Flag will be set and remembered until the interrupt is enabled, or the flag is
cleared by software. Similarly, if one or more interrupt conditions occur while the Global Interrupt
Enable bit is cleared, the corresponding Interrupt Flag(s) will be set and remembered until the
Global Interrupt Enable bit is set, and will then be executed by order of priority.
далее смотрим:
GIFR – General Interrupt Flag Register
Bit 6 – INTF0: External Interrupt Flag 0
When an edge or logic change on the INT0 pin triggers an interrupt request, INTF0 becomes set
(one). If the I-bit in SREG and the INT0 bit in GIMSK are set (one), the MCU will jump to the cor-
responding Interrupt Vector. The flag is cleared when the interrupt routine is executed.
Alternatively, the flag can be cleared by writing a logical one to it. This flag is always cleared
when INT0 is configured as a level interrupt.
Но раз тут еще приписочка о том что он всегда очищен когда настроен на прерывание по уровню, то лучше воспользоваться старым добрым способом насчет выбора нужного действия при входе.
Можно вообще переключить на прерывание PIN CHANGE
Bit 5 – PCIF: Pin Change Interrupt Flag
When a logic change on any PCINT5:0 pin triggers an interrupt request, PCIF becomes set
(one). If the I-bit in SREG and the PCIE bit in GIMSK are set (one), the MCU will jump to the cor-
responding Interrupt Vector. The flag is cleared when the interrupt routine is executed.
Alternatively, the flag can be cleared by writing a logical one to it.
Вроде как из POWER DOWN могут вывести прерывания INT0 and
Pin Change
из Table 7-1

Короче вот нарыл, реально сначала выполняется прерывание, потом уже только возвращается к ранее исполнявшемуся коду, так что однозначно нужно разделить на спать и не спать.
If an enabled interrupt occurs while the MCU is in a sleep mode, the MCU wakes up. The MCU
is then halted for four cycles in addition to the start-up time, executes the interrupt routine, and
resumes execution from the instruction following SLEEP.
The contents of the Register File and
SRAM are unaltered when the device wakes up from sleep. If a reset occurs during sleep mode,
the MCU wakes up and executes from the Reset Vector.
Вот и получается, что мк постоянно входит в прерывание и засыпает.

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Пн апр 22, 2013 19:52:31
robototechnik
получается сразу перед входом в спячку надо флаг очистить?или как?

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Пн апр 22, 2013 19:58:03
vitalik_1984
При входе в прерывание нужно сделать выбор спать или просыпаться. Так если входит в прерывание после спячки просто будет мимо проходить наружу из прерывания и все.

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Пн апр 22, 2013 20:32:55
robototechnik
ну я вот так вот пока что переделал.....что опять не так?всеравно не пашет(((((((((((

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

#define F_CPU 9600000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>
unsigned char e;
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status);
unsigned char pwm[3]={255,255,255};
unsigned char to[3]={255,255,255};
int main(void)
{
DDRB = 0b00011001; 
PORTB = 0b00011011;

ACSR = (1<<ACD);
GIMSK = (1<<INT0);

TCCR0A = 0x00;
TCCR0B = (1<<CS00);
TIMSK0 = (1<<TOIE0);
sei();
while(1){
if (pwm[0]<to[0]) pwm[0]++;
if (pwm[0]>to[0]) pwm[0]--;
if (pwm[1]<to[1]) pwm[1]++;
if (pwm[1]>to[1]) pwm[1]--;
if (pwm[2]<to[2]) pwm[2]++;
if (pwm[2]>to[2]) pwm[2]--;
if(pwm[0]==to[0]&&pwm[1]==to[1]&&pwm[2]==to[2]) 
{
to[0]=rand()%255; 
to[1]=rand()%255;
to[2]=rand()%255;
}

}
}
ISR(TIM0_OVF_vect)
{
if(e==255)
{
e=0;
PORTB |= 0b00011001;
}
abc(pwm[0],pwm[1],pwm[2],e);
e++;
}
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status)
{
if((status==a)) PORTB&= ~(1<<3);
if((status==b)) PORTB&= ~(1<<4);
if((status==c)) PORTB&= ~(1<<0);
}

ISR(INT0_vect) { 
 PORTB |= 0b00011001;
 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
 sleep_enable(); 
 sleep_mode();
 GIFR = (1<<INTF0);
 sleep_disable();
}	

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Пн апр 22, 2013 20:33:29
robototechnik
если делаю выбор спать не спать тоже не пашет(((((((((((((

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вт апр 23, 2013 00:15:51
robototechnik
переделал код!!радикально!!
вроде работает, но не всегда, плюс память закончилась((((((уже не могу сделать регулировку скорости смены цветов и паузу после выхода из спячки чтобы я руку от кнопки убрать успел((
может можно как нибудь код оптимизировать для освобождения еще около 4 процентов памяти????а то здесь 100 под завязку
буду благодарен)
вот он код

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

#define F_CPU 9600000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>
unsigned char e;
unsigned char state = 0;
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status);
unsigned char pwm[3]={255,255,255};
unsigned char to[3]={255,255,255};
int main(void)
{
DDRB = 0b00011001; 
PORTB = 0b00011011;

ACSR = (1<<ACD);
GIMSK = (1<<INT0);

TCCR0A = 0x00;
TCCR0B = (1<<CS00);
TIMSK0 = (1<<TOIE0);
sei();
while(1){
if (pwm[0]<to[0]) pwm[0]++;
if (pwm[0]>to[0]) pwm[0]--;
if (pwm[1]<to[1]) pwm[1]++;
if (pwm[1]>to[1]) pwm[1]--;
if (pwm[2]<to[2]) pwm[2]++;
if (pwm[2]>to[2]) pwm[2]--;
if(pwm[0]==to[0]&&pwm[1]==to[1]&&pwm[2]==to[2]) 
{
to[0]=rand()%255; 
to[1]=rand()%255;
to[2]=rand()%255;
}

if (state == 0){
sleep_disable();
}
else{
PORTB |= 0b00011001;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable(); 
sleep_mode();
}
}
}
ISR(TIM0_OVF_vect)
{
if(e==255)
{
e=0;
PORTB |= 0b00011001;
}
abc(pwm[0],pwm[1],pwm[2],e);
e++;
}
void abc(unsigned char a,unsigned char b,unsigned char c,unsigned char status)
{
if((status==a)) PORTB&= ~(1<<3);
if((status==b)) PORTB&= ~(1<<4);
if((status==c)) PORTB&= ~(1<<0);
}

ISR(INT0_vect) { 
if (state == 1) state = 0;
else state = 1;
}

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вт апр 23, 2013 00:32:08
Stalker007
Кроме чисел ещё есть логические переменные. Может их использовать?
Тогда вместо:

unsigned char state = 0;
...
if (state == 0){
sleep_disable();
}
else{
PORTB |= 0b00011001;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
}
...
ISR(INT0_vect) {
if (state == 1) state = 0;
else state = 1;

будет:

boolean state = false;
...
if (!state){
sleep_disable();
}
else{
PORTB |= 0b00011001;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
}
...
ISR(INT0_vect) {
state=!state;

Чутьё мне подсказывает, что код уменьшится, но вот насколько? Нужно пробовать.

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вт апр 23, 2013 00:49:19
vitalik_1984
Stalker007 , нет в студии никаких логических переменных.
robototechnik 1.зачем два раза сравнивать, если можно все в одном месте все сделать?
2. кардинально это когда весь код переписан или хотя бы 60%. еще раз спрашиваю, зачем нужна функция abc? если ее объявить как inline, тоже код может уменьшиться, а так при ее вызове могут делаться ненужные сохранения регистров.

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вт апр 23, 2013 08:23:29
robototechnik
Stalker007, идея хорошая но что то не определяет у меня winavr такую переменную(
vitalik_1984, 1. откуда такие точные проценты?)я просто поменял принцип, и высказался образно)что тут такого?)
2.а как можно сравнить в одном месте???
на счет авс без понятия)эту часть я скопировал из примера)давайте пробовать все подряд)

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вт апр 23, 2013 09:03:29
ibiza11
так попробуйте:

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

#define F_CPU 9600000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/sleep.h>
unsigned char e;
unsigned char state = 0;
void abc(unsigned char a, unsigned char b, unsigned char c, unsigned char status);
unsigned char pwm[3]={255,255,255};
unsigned char to[3]={255,255,255};
int main(void)
{
   DDRB  = 0b00011001; 
   PORTB = 0b00011011;

   ACSR = (1<<ACD);
   GIMSK = (1<<INT0);

   TCCR0A = 0x00;
   TCCR0B = (1<<CS00);
   TIMSK0 = (1<<TOIE0);
   sei();
   while(1){
      if (pwm[0]<to[0]) pwm[0]++;
      if (pwm[0]>to[0]) pwm[0]--;
      if (pwm[1]<to[1]) pwm[1]++;
      if (pwm[1]>to[1]) pwm[1]--;
      if (pwm[2]<to[2]) pwm[2]++;
      if (pwm[2]>to[2]) pwm[2]--;
      if(pwm[0]==to[0]&&pwm[1]==to[1]&&pwm[2]==to[2]){
         to[0]=rand()%255;
         to[1]=rand()%255;
         to[2]=rand()%255;
      }
      if (state == 0){
         sleep_disable();
      } else {
         PORTB |= 0b00011001;
         set_sleep_mode(SLEEP_MODE_PWR_DOWN);
         sleep_enable(); 
         sleep_mode();
      }
   }
}

ISR(TIM0_OVF_vect)
{
   if(++e == 0)
      PORTB |= 0b00011001;
   else {
      if(pwm[0] == e)
         PORTB &= ~(1<<3);
      if(pwm[1] == e)
         PORTB &= ~(1<<4);
      if(pwm[2] == e)
         PORTB &= ~(1<<0);
   }
}


ISR(INT0_vect) { 
   state ^= 0x01;
   while(!(PINB&0b00000010));
} 

Re: RGB светодиод, INT0 прерывание и все это для ATtiny13

Добавлено: Вт апр 23, 2013 12:01:08
Stalker007
Stalker007 писал(а):будет:

boolean state = false;
...
if (!state){
sleep_disable();
}
else{
PORTB |= 0b00011001;
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
}
...
ISR(INT0_vect) {
state=!state;
Извиняюсь, я в основном на паскале писал. Никак не привыкну к тому что в Си всё более коротко. Нужно объявлять так:
bool state;