Сделал светильник с светодиодной лентой на Attiny13 c управлением яркостью с пульта. В протеусе работает как часы)) Спаял и получил небольшие затыки.
Управление яркостью осуществляется через транзисторный модуль с опторазвязкой.
На ножку PB3 подключен ИК приёмник 1838 с обвязкой. С ИК приёмом проблем нет. Потому что если воспроизвести код вот отсюда
команды проходят чётко и без пропусков
Я сделал свой вариант в котором есть миллисекундный таймер и PWM c регулируемой скважностью с частотой примерно 1кГц и обработку повторных нажатий
Но как только я меняю код на свой Начинаются небольшие затыки. Проявляются в том что пульт иногда не реагирует на кнопку, как бы пропускает её. Может 20 раз среагировать, а потом несколько пропустить. Или один пропуск на 10 нажатий. Ну и далее в этом же духе. Проявляется не часто. Мне кажется проблема с двумя прерываниями и переменными с которыми работаю из двух прерываний. В исходном коде работает 1 прерывание и самый длительный интервал ИК 9000 мкр сек помещается между минимальным и максимальным значением TCNT0. А у меня частота гораздо выше из-за PWM и счетчика миллисекунд. Подскажите как исправить этот баг и при этом сохранить приемлемую частоту PWM ~1K?
PS атинька не перезагружается и не зависает, у меня задана начальная скважность и если лента горит в половину яркости, то при пропусках команд яркость не падает. И после пропуска нажатия атинька продолжает обрабатывать нажатия далее.
Управление яркостью осуществляется через транзисторный модуль с опторазвязкой.
На ножку PB3 подключен ИК приёмник 1838 с обвязкой. С ИК приёмом проблем нет. Потому что если воспроизвести код вот отсюда
ATtiny13-TinyDecoder/software/tiny13/TinyDecoder_t13.ino at main · wagiminator/ATtiny13-TinyDecoder
IR Remote Receiver and Decoder. Contribute to wagiminator/ATtiny13-TinyDecoder development by creating an account on GitHub.
github.com
Я сделал свой вариант в котором есть миллисекундный таймер и PWM c регулируемой скважностью с частотой примерно 1кГц и обработку повторных нажатий
Но как только я меняю код на свой Начинаются небольшие затыки. Проявляются в том что пульт иногда не реагирует на кнопку, как бы пропускает её. Может 20 раз среагировать, а потом несколько пропустить. Или один пропуск на 10 нажатий. Ну и далее в этом же духе. Проявляется не часто. Мне кажется проблема с двумя прерываниями и переменными с которыми работаю из двух прерываний. В исходном коде работает 1 прерывание и самый длительный интервал ИК 9000 мкр сек помещается между минимальным и максимальным значением TCNT0. А у меня частота гораздо выше из-за PWM и счетчика миллисекунд. Подскажите как исправить этот баг и при этом сохранить приемлемую частоту PWM ~1K?
PS атинька не перезагружается и не зависает, у меня задана начальная скважность и если лента горит в половину яркости, то при пропусках команд яркость не падает. И после пропуска нажатия атинька продолжает обрабатывать нажатия далее.
C:
#include <avr/io.h>
#include <avr/interrupt.h>
#define IR_OUT PB3
#define IR_WAIT_HIGH() while(~PINB & (1<<IR_OUT))
#define IR_WAIT_LOW() while( PINB & (1<<IR_OUT))
#define IR_9000us 1350 //9000us*9.6Mhz/64
#define IR_4500us 675
#define IR_2250us 337
#define IR_1687us 253
#define IR_562us 84
#define IR_FAIL 0
#define IR_NEC 1
#define Pwm_start 105
volatile uint16_t milliseconds;
volatile uint16_t IR_duration;
volatile uint16_t duration;
volatile uint8_t c2;
uint16_t addr;
uint8_t cmd;
uint8_t flag=1;
uint16_t last_milliseconds;
uint8_t IR_checkDur(uint16_t dur)
{
uint16_t error = dur >> 3;
//if(error < 6) error = 6;
if(IR_duration > dur)
{
return((IR_duration - dur) < error);
}
return((dur - IR_duration) < error);
}
ISR(PCINT0_vect)
{
IR_duration=duration+TCNT0-c2;
c2=TCNT0;
duration=0;
}
ISR(TIM0_OVF_vect)
{
TCNT0=Pwm_start;
duration+=150;
milliseconds++;
}
void timer1_init()
{
TCCR0A|=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00);
TCCR0B|=(1<<CS00)|(1<<CS01);
OCR0A=Pwm_start+1;
TCNT0=Pwm_start;
TIMSK0|=(1<<TOIE0);
asm("sei");
}
void pcint_init()
{
PCMSK|=(1<<PCINT3);
}
uint8_t IR_readNEC(void)
{
uint32_t data;
IR_WAIT_LOW();
if(IR_checkDur(IR_2250us))
{
IR_WAIT_HIGH();
if(IR_checkDur(IR_562us))
{
//repeat code
if(cmd!=0)
{
return IR_NEC;
}
}
}
if(!IR_checkDur(IR_4500us)) return 0;
for(uint8_t i=32; i; i--)
{
data >>= 1;
IR_WAIT_HIGH();
if(!IR_checkDur(IR_562us)) return 0;
IR_WAIT_LOW();
if(IR_checkDur(IR_1687us)) data |= 0x80000000;
else if(!IR_checkDur(IR_562us)) return 0;
}
IR_WAIT_HIGH();
if (!IR_checkDur(IR_562us)) return 0;
uint8_t addr1 = data;
uint8_t addr2 = data >> 8;
uint8_t cmd1 = data >> 16;
uint8_t cmd2 = data >> 24;
if((cmd1 + cmd2) < 255) return 0;
cmd = cmd1;
if((addr1 + addr2) == 255) addr = addr1;
else addr = data;
return IR_NEC;
}
uint8_t IR_Read()
{
uint8_t protocol = 0;
GIMSK|=(1<<PCIE);
do
{
IR_WAIT_HIGH();
IR_WAIT_LOW();
IR_WAIT_HIGH();
if(IR_checkDur(IR_9000us))
{
protocol = IR_readNEC();
}
} while (!protocol);
GIMSK &= ~(1<<PCIE);
return protocol;
}
int main(void)
{
DDRB|=(1<<PB0);
DDRB &= ~(1<<IR_OUT);
timer1_init();
pcint_init();
while (1)
{
IR_Read();
if(addr!=0) continue;
if( cmd == 0x40)
{
if(flag)
{
TCCR0A&=~(1<<COM0A1);
PORTB|=(0<<PB0);
}
else
{
TCCR0A|=(1<<COM0A1);
PORTB|=(0<<PB0);
}
flag=!flag;
cmd=0;
last_milliseconds=milliseconds;
}
else if(cmd == 0x44)
{
if(OCR0A>Pwm_start+1)
{
OCR0A--;
}
last_milliseconds=milliseconds;
}
else if(cmd == 0x43)
{
if(OCR0A<0xFF)
{
OCR0A++;
}
last_milliseconds=milliseconds;
}
if(milliseconds-last_milliseconds>=250)
{
cmd=0;
IR_duration=0;
}
}
}
Изменено: