Прием команд с пульта дистанционного управления

Обновлено 21.01.14. Исходники переписаны под AVR Studio 6 (с тулчейном)

В этой статье я расскажу, как принимать команды с пульта (ПДУ) с кодировкой RC5. Подробное описание протокола не имеет смысла так как этого в интернете предостаточно.

Схема:

Микроконтроллер Atmega8 (тактирование 1 МГц от внутреннего генератора), ИК-приемник TSOP1736 подключен к входу захвата ICP, на порту D висят светодиоды.

Я все это сделал на своей отладочной плате, которую спаял когда то минут за 20.

Верху слева ИК-приемник, справа — светодиоды.

Итак, сейчас мы сделаем чтобы при нажатии на цифровую кнопку на ПДУ зажигался соответствующий светодиод (от 0 до 7). Код, ну очень простой:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "rc5.h"
#include "main.h"
 
int main (void)
{
	PORTB = 0b00000000; DDRB = 0b00000000;
	PORTC = 0b00000000; DDRC = 0b00000000;
	PORTD = 0b00000000; DDRD = 0b11111111;	// тут светодиоды
 
	Rc5_SetRx();	// инициализируем таймер 1
 
	sei();	// глобально разрешаем прерывания
 
	while(1)
	{
		if (rc5.dataOK) {	// если получены данные с ПДУ
			PORTD = 0;	// тушим все светодиоды
			sbi(PORTD, rc5.command);	// зажигаем светодиод, соответствующий комманде с ПДУ
 
			rc5.dataOK = 0;	// сбрасываем флаг
		}
	}
 
}

После инициализации таймера и разрешения прерываний включается захват, и микроконтроллер начинает обрабатывать данные, принятые с пульта. Если получен пакет данных, то активируется флаг rc5.dataOK, а принятая команда записывается с переменную структуры rc5.command.
Стоит иметь ввиду, что пульт отправляет не только команду, а и номер системы, если 0, то это команда для телевизора.
rc5.h содержит функции, для работы с RC5 и структуру rc5:

1
2
3
4
5
6
7
8
struct {
	unsigned char	control_bit;
	unsigned char	system;
	unsigned char	command;
	unsigned char	flag;
	unsigned char	dataOK;
	unsigned char	error;
	}	rc5;

После приема пакета с пульта поднимается флаг dataOK, в system записывается номер системы, в command — номер команды, если в пакете была ошибка, то поднимается флаг error.

А вот видео работы устройства: http://youtu.be/Dqghjc3oivY

Скачать файлы

209 комментариев Прием команд с пульта дистанционного управления

  • vpashko

    Здравствуйте, а нет ли у Вас кода с таким алгоритмом, нажали на кнопку пульта светик горит, отпустили светик погас(ну очень нужно).

    • Kibermaster

      типа так:
      while(1)
      {
      if (rc5.dataOK) { // если получены данные с ПДУ
      sbi(PORTD, 1); // зажигаем светодиод на PORTD.1
      rc5.dataOK = 0; // сбрасываем флаг
      }
      else сbi(PORTD, 1); // если данные не получены, тушим светодиод на PORTD.1

      _delay_ms(700);
      }

  • neo

    Интересно!
    Попробую собрать. А фюз биты как выставить в программе AVRDUDE?

  • neo

    Как я понял, светодиод только один может гореть? А нету у Вас прошивки что б все диоды можно было включить?
    Спасибо.

  • Vivo

    Подскажите пожалуйста, нужно что бы при нажатии кнопки включался светодиод, по нажатии этой же клавиши второй раз, он выключался, код примерно такой,

    int u=0;//декларируем переменную состояния, задаем значение 0
    /////////////////////////////////////////////////
    if(u==0) //если предидущее значение было ноль
    {u=1;}//меняем на единицу
    else
    {u=0;}//если не ноль то меняем на ноль
    break;
    /////////////////////////////////////////////////

    void u_check (void)
    {
    if(u==0) {PORTB = 0b00000001;}//включаем светодиод
    else (PORTB = 0b00000000;}//выключаем светодиод
    }, но я не пойму как сделать переход или условие, в rc5.command что именно хранится?
    может так
    if (rc5.dataOK)
    if (rc5.command == 000001){ // если получены данные с ПДУ
    и эта кнопка 1
    if(u==0) //если предидущее значение было ноль
    {u=1;}//меняем на единицу
    else
    {u=0;}//если не ноль то меняем на ноль

    rc5.dataOK = 0; // сбрасываем флаг
    }

    • Kibermaster

      На PORTB.0 висит приемник, этой ножкой дрыгать нельзя. Предложим, вам нужно управлять светодиодом на PORTD.0
      while(1)
      {
      if (rc5.dataOK) { // если получены данные с ПДУ
      if (rc5.command==1){ // если это кнопка 1
      if (CheckBit(PIND, 0)) cbi(PORTD, 0); // если светодиод включен, выключаем
      else sbi(PORTD, 0); // если светодиод выключен, включаем
      }

      rc5.dataOK = 0; // сбрасываем флаг
      }
      }

  • Vivo

    отлично, получилось спасибо, теперь у меня возникло еще парочка вопросов что такое CheckBit и cbi? и куда лучше поставить задержку между приемами команда, а то лампочка сразу выключается((или не с первого раза включается(

  • vpashko

    Здравствуйте, а Вы можете выложить HEX файл с таким алгоритмом:нажали на кнопку пульта светик горит, отпустили светик погас(ну очень нужно).

  • Vivo

    Kibermaster, наверно я тебя замучил((( но у меня опять возникла проблема, помоги плиз, делаю дистанционное управление светом, первая часть получилась, а вторая нет, суть при нажатии одной клавиши с помощью шим яркость увеличивается, при нажатии другой-уменьшается, вот то что я смог сделать

    #include
    #include
    #include «rc5.h»
    #include «main.h»

    int main (void)
    {//1

    PORTB = 0b00000000; DDRB = 0b00000010;
    PORTC = 0b00000000; DDRC = 0b00000000;
    PORTD = 0b00000000; DDRD = 0b11111111; // òóò ñâåòîäèîäû
    unsigned int i=0;
    Rc5_SetRx(); // èíèöèàëèçèðóåì òàéìåð 1
    TCCR1A = (1 << COM1A1)|(0 << COM1A0) // Óñòàíîâèì áèòû COM1A1-COM1A0:0b10,
    // îçíà÷àåò ñáðîñ âûâîäà êàíàëà A ïðè ñðàâíåíèè
    |(1 << WGM11)|(0 << WGM10); // Óñòàíîâèì áèòû WGM13-10:0b1110, ñîãëàñíî òàáëèöå ýòî

    TCCR1B = (1 << WGM13)|(1 << WGM12) // áóäåò ðåæèì — FAST PWM, ãäå âåðõíèé ïðåäåë ñ÷åòà çàäàåòñÿ áèòîì ICR1
    |(0 << CS12)|(0 << CS11)|(1 << CS10); // Áèòàìè CS12-10:0b001 çàäàåì èñòî÷íèê òàêòîâîãî
    // ñèãíàëà äëÿ òàéìåðà ÌÊ, âêëþ÷åí áåç äåëèòåëÿ
    TCNT1 = 0x00; // íà÷àëüíàÿ óñòàíîâêà ñ÷åò÷èêà
    ICR1 = 0xFF; // çàäàåì ïåðèîä ØÈÌ, çäåñü ó íàñ ÷èñëî 255,
    // ïî ôîðìóëå fPWM=fclk_I/O/N*(1+ICR1)
    // âû÷èñëÿåì ÷àñòîòó ØÈÌ, îíà áóäåò ðàâíà 15625 Hz
    OCR1A = 0x00; // íà÷àëüíûé êîýôôèöèåíò çàïîëíåíèÿ ØÈÌ
    sei(); // ãëîáàëüíî ðàçðåøàåì ïðåðûâàíè

    while(1)
    {//2
    if (rc5.dataOK)
    { // åñëè ïîëó÷åíû äàííûå ñ ÏÄÓ 3
    if (rc5.command==7)
    { // åñëè ýòî êíîïêà 1 4
    if (i 0) // êîýôôèöèåíò çàïîëíåíèÿ ØÈÌ èçìåíÿåòñÿ îò 255 äî 0
    {
    i=i-20; // óìåíüøàåì i íà åäèíèöó(òàê òîæå ìîæíî ïèñàòü)
    OCR1A = i; // çàïèñûâàåì ïåðåìåííóþ â ðåãèñòð ñðàâíåíèÿ
    }
    }
    rc5.dataOK = 0; // ñáðàñûâàåì ôëàã
    }
    }
    }

    ссылался на http://radioparty.ru/index.php/prog-avr/program-c/240-lesson8?start=3

    • Vivo

      Kibermaster, наверно я тебя замучил((( но у меня опять возникла проблема, помоги плиз, делаю дистанционное управление светом, первая часть получилась, а вторая нет, суть при нажатии одной клавиши с помощью шим яркость увеличивается, при нажатии другой-уменьшается, вот то что я смог сделать

      #include
      #include
      #include «rc5.h»
      #include «main.h»

      int main (void)
      {//1

      PORTB = 0b00000000; DDRB = 0b00000010;
      PORTC = 0b00000000; DDRC = 0b00000000;
      PORTD = 0b00000000; DDRD = 0b11111111;
      unsigned int i=0;
      Rc5_SetRx();
      TCCR1A = (1 << COM1A1)|(0 << COM1A0)

      |(1 << WGM11)|(0 << WGM10);

      TCCR1B = (1 << WGM13)|(1 << WGM12)
      |(0 << CS12)|(0 << CS11)|(1 << CS10);
      TCNT1 = 0×00;
      ICR1 = 0xFF;

      OCR1A = 0×00;
      sei();

      while(1)
      {//2
      if (rc5.dataOK)
      {
      if (rc5.command==7)
      {
      if (i 0)
      {
      i=i-20;
      OCR1A = i;
      }
      }
      rc5.dataOK = 0;
      }
      }
      }

      ссылался на http://radioparty.ru/index.php/prog-avr/program-c/240-lesson8?start=3

  • vpashko

    А чем скомпилировать?

  • mastech

    как заставить этот код работать на 8МГц?

  • mastech

    как я понял в этом месте с погрешностью не более 10%
    // RC5_T нужно расчитать вручную (особенности компилятора)
    #define RC5_T 14304 //((F_CPU/PRESCALER/1000)*1.778) в моем случае получается 14304(8000*1.778)
    #define FAULT_TIME_RC5 RC5_T*17 // не должно быть более 65535
    #define TOLERANCE (RC5_T/10) // 10%

    не получается решить проблему с не стабильностью включения выключения(думал подниму частоту добавлю стабильности)))
    что посоветуете?

  • Kibermaster

    а что там нестабильного?

  • mastech

    я сразу прошу прощения за свой быдло код))) когда я делаю так(см.код) то отклики не стабильны либо сразу включится и выключится или вкл. но с 3его раза вобщем в этом духе. не прошу код за меня написать прошу хотя бы направить на путь истинный. чую что должно быть но сообразить не могу.

    #include
    #include
    #include «rc5.h»
    #include «main.h»
    //#include

    int main (void)
    {
    PORTD = 0b00000000; DDRD = 0b00000000; // прием
    PORTA = 0b00000000; DDRA = 0b11111111;
    PORTC = 0b00000000; DDRC = 0b11111111;

    Rc5_SetRx(); // инициализируем таймер 1

    sei(); // глобально разрешаем прерывания

    while(1)
    {
    if (rc5.dataOK) { // если получены данные с ПДУ
    if (rc5.command==1){ // если это кнопка 1
    if (CheckBit(PINA, 0)) cbi(PORTA, 0); // если светодиод включен, выключаем
    else sbi(PORTA, 0); // если светодиод выключен, включаем
    }
    rc5.dataOK = 0; // сбрасываем флаг

    }
    /*
    if (rc5.dataOK) { // если получены данные с ПДУ
    if (rc5.command==2){ // если это кнопка 1
    if (CheckBit(PINA, 1)) cbi(PORTA, 1); // если светодиод включен, выключаем
    else sbi(PORTA, 1); // если светодиод выключен, включаем
    }
    rc5.dataOK = 0; // сбрасываем флаг

    }*/
    if (rc5.dataOK) { // если получены данные с ПДУ

    if (rc5.command==9){ // если это кнопка 1
    if (CheckBit(PINC, 1)) cbi(PORTC, 1); // если светодиод включен, выключаем
    else sbi(PORTC, 1); // если светодиод выключен, включаем
    }
    rc5.dataOK = 0; // сбрасываем флаг

    //и так далие перебирая каждый порт
    }
    }
    }

  • mastech

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

    while(1)
    {
    if (rc5.dataOK) {
    if (rc5.command==1){
    if (CheckBit(PINA, 0)) cbi(PORTA, 0);
    else sbi(PORTA, 0);
    }
    rc5.dataOK = 0;

    if (rc5.command==2){
    if (CheckBit(PINA, 1)) cbi(PORTA, 1);
    else sbi(PORTA, 1);
    }
    rc5.dataOK = 0;
    }
    }
    }

  • mastech

    прееелестно) работает на 5 балов спасибо) до этого побывал задержки, но ставил не туда))

  • mastech

    сейчас прикидываю как код покрасивее сделать.

  • vvangog

    Всем привет.
    Я в программировании полный 0, поэтому у меня есть немного вопросов.
    Спаял на днях вашу схему, и возник вопрос как и чем програмировать.
    В интернете нашел ну очень простую схему (даже и не схема 🙂 ) программатора для AVR, так называемая «5 проводков».
    И вот вроде запрограммировал мк прошивкой из приложенного фаила (rc5.HEX) , но как привязать ее к пульту?
    программировал программой CodeVisionAVR.
    Пульт от Горизонта RC5-7.
    Подскажите пожалуйста.

  • vvangog

    #include «rc5.h»
    #include «main.h»

    int main (void)
    {
    PORTB = 0b00000000; DDRB = 0b00000000;
    PORTC = 0b00000000; DDRC = 0b00000000;
    PORTD = 0b00000000; DDRD = 0b11111111; // тут светодиоды

    Rc5_SetRx(); // инициализируем таймер 1

    sei(); // глобально разрешаем прерывания

    while(1)
    {
    if (rc5.dataOK) { // если получены данные с ПДУ
    PORTD = 0; // тушим все светодиоды
    sbi(PORTD, rc5.command); // зажигаем светодиод, соответствующий комманде с ПДУ

    rc5.dataOK = 0; // сбрасываем флаг
    }
    }

    }

    это полный код прошивки или только отрывок? Или вообще что это?)

  • vvangog

    а как вы прописали имено кнопки 1-8 (или какие там)?
    Помогите пожалуйста.

  • vvangog

    я уже раз 20 пробовал прошить мк… все безуспешно…
    может я что-то не так делаю?
    можете если вас не затруднит подробно расписать процесс програмирования?
    или скажите, куда вам можно написать.

  • vvangog

    я не так изложил вопрос.
    Атмега у меня прошивается фаилом rc5.HEX !!! (или нужно кодом,выложенным в теме??? ) выложенным вами.
    после программирования нажимаю на кнопки ПДУ и ничего.
    такое чувство что пульт не подходит.
    перепробывал все пульты которые нашел… ничего.
    кстати! программировать отдельно мк, или можно прямо в схеме?
    Извените меня, если надоедаю тупыми вопросами… просто программирование это не мое… а вот эта схема позарез нужна…

  • vvangog

    ладно… сейчас попробую поменять приемник…

  • vvangog

    приемник проверил — рабочий.
    как можно проверить подходит пульт или нет?

  • vvangog

    он рабочий.
    я спрашивал как проверить подходит пульт к схеме или нет?

  • Atabek

    Здравствуйте. У меня ИК-приемник SM0038 (приемник телевизора) схема будут работать для него?
    или только для TSOP1736?

  • Atabek

    Здравствуйте. У меня вопрос Atmega8 A сколько раз могу прошить ? 1000 раз или больший?

  • Atabek

    я не мог найти datasheete. значит 10000 раз да . спасибо

  • Atabek

    Здравствуйте. У меня программатор не прошивает больше 6 кб Ошибка выдают. программатор у меня Chip Blaster а чип Atmega8. Знаю что Atmega8 можно писать программу до 8 кб , а у меня hex файл 7 кб.
    Что делать помогите пожалуйста.

    • Kibermaster

      hex — это прошивка в текстовом формате, реально она весит, помойму, меньше 1кб. Я думаю, что у вас какие то проблемы с тактированием, ну или с питанием

  • rastamanoff

    Здравствуйте.Cпасибо за статью.
    Собрал на макетке — «поковырятся».Но меня больше интресовал алгоритм уже обсуждаемый с пользователем mastech ,при нажатии кнопки включался светодиод, по нажатии этой же клавиши второй раз, он выключался.
    С номером системы(№0) разобрался,поскольку пульт «самопальный» -пришлось компилировать новый hex,там был прописан №29-освещение.
    Добавил #include .Задержку 700 мс поставил в конце цикла while(1):

    while(1)
    {
    if (rc5.dataOK) // если получены данные с ПДУ
    {
    if (rc5.command==1) // если это кнопка 1
    {
    if (CheckBit(PIND, 0)) cbi(PORTD, 0); //если канал 1 включен, выключаем
    else sbi(PORTD, 0); // если канал 1 выключен, включаем
    }
    rc5.dataOK = 0; // сбрасываем флаг

    if (rc5.command==2) // если это кнопка 2
    {
    if (CheckBit(PIND, 1)) cbi(PORTD, 1); //если канал 2 включен, выключаем
    else sbi(PORTD, 1); // если канал 2 выключен, включаем
    }
    rc5.dataOK = 0; // сбрасываем флаг

    if (rc5.command==3) // если это кнопка 3
    {
    if (CheckBit(PIND, 2)) cbi(PORTD, 2); //если канал 3 включен, выключаем
    else sbi(PORTD, 2); // если канал 3 выключен, включаем
    }
    rc5.dataOK = 0; // сбрасываем флаг

    if (rc5.command==4) // если это кнопка 4
    {
    if (CheckBit(PIND, 3)) cbi(PORTD, 3); //если канал 4 включен, выключаем
    else sbi(PORTD, 3); // если канал 4 выключен, включаем
    }
    rc5.dataOK = 0; // сбрасываем флаг
    }
    _delay_ms(700); //задержка 700 мс
    }

    Правильно ли это?Работает нормально,но иногда замечается нечеткое срабатывание.Я еще бью на пульт,надо покупать заводской...

  • rastamanoff

    Так я ставил ее в конце цикла if (rc5.dataOK)после последнего rc5.dataOK = 0 — было еще хуже.Может в начале цикла поставить,первым после скобки.

    • Kibermaster

      когда задержка стоит в цикле while(1), то наличие принятой команды проверяется каждые 700мс, есл иперенести эту задержку в if (rc5.dataOK) (в конец), то наличие принятой команды будет производиться постоянно и когда она появится, то сначала будет выполнение нужных функций, затем, через 700мс девайс будет опять реагировать на комманду с пду

    • Kibermaster

      а, бля, rc5.dataOK = 0; нужно поставьт после задержки. Вобщем, так:
      while(1)
      {
      if (rc5.dataOK) // если получены данные с ПДУ
      {
      if (rc5.command==1) // если это кнопка 1
      {
      if (CheckBit(PIND, 0)) cbi(PORTD, 0); //если канал 1 включен, выключаем
      else sbi(PORTD, 0); // если канал 1 выключен, включаем
      }

      if (rc5.command==2) // если это кнопка 2
      {
      if (CheckBit(PIND, 1)) cbi(PORTD, 1); //если канал 2 включен, выключаем
      else sbi(PORTD, 1); // если канал 2 выключен, включаем
      }

      if (rc5.command==3) // если это кнопка 3
      {
      if (CheckBit(PIND, 2)) cbi(PORTD, 2); //если канал 3 включен, выключаем
      else sbi(PORTD, 2); // если канал 3 выключен, включаем
      }

      if (rc5.command==4) // если это кнопка 4
      {
      if (CheckBit(PIND, 3)) cbi(PORTD, 3); //если канал 4 включен, выключаем
      else sbi(PORTD, 3); // если канал 4 выключен, включаем
      }

      _delay_ms(700); //задержка 700 мс
      rc5.dataOK = 0; // сбрасываем флаг
      }

      }

  • rastamanoff

    Я понял Вас конечно.Но я изначально так и сделал с задержкой,при этом при нечетком нажатии светодиод вспыхивал и потухал.Возможно увеличить задержку до 1сек.
    Та и пульт может давать погрешности,нужен заводской,хотя я делал его для аудиоусилителя — работал отлично.

  • rastamanoff

    Ой извените я неувидел предпоследнее сообщение.

  • rastamanoff

    Да Вы были правы,перепрошил все заработало.Да и флаг надо сбрасывать один раз в конце цикла.
    Большое спасибо.

  • rastamanoff

    Добрый вечер Kibermaster.
    Подскажите,а как быть,если я хочу увеличить частоту МК Atmega8 до 8 МГц?
    Я так думаю нужно перещитывать RC5_T в файле rc5.h.Но как понять:


    // RC5_T нужно расчитать вручную (особенности компилятора)
    #define RC5_T 1778 //((F_CPU/PRESCALER/1000)*1.778)

    ???

  • Atabek

    здравствуйте. как получить сигнал от ИК приемника(38 КГц) его data подключен в PB0 у.
    не знаю как настроит таймеры .
    помогите пожалуйста.
    за ранние спасибо.

  • Sherl

    Здравствуйте! Не могли бы Вы привести пример этого кода для CAVR — никак не получается портировать самостоятельно(((((

  • Atabek

    здравствуйте. я собрал USB-HID устройство (прошивка под 12МГц внешний кварц).
    а вашей случей прошивка под 1МГц можно сделать 12МГц.(проверил не роботала )
    она будет работать?
    мой USB-HID устройство я хотел посмотреть команды пульта.
    свой USB-HID устройство не работает 1МГц.
    что делать помогите пожалуйста.

  • Atabek

    я не знаю как будет частоту 12МГц.
    напишите пожалуйста.

  • Atabek

    напишите пожалуйста что меня и значения .

  • Atabek

    спасибо вам большое что вы помогайте мне.
    всё работает.
    Вы очень добрый человек.
    как вы расшитовали эта #define RC5_T 2667 ?
    меня тоже научите пожалуйста.
    за ранние спасибо.

  • Atabek

    я хотел управлять часы с помощью пулта.
    я не знаю как будет частоту 32768 Гц. (часовой кварц )
    научите пожалуйста.

  • Atabek

    спасибо я всё понял значения PRESCALER=8

  • sergejus

    добрый день, hex в архиве работает, как только я закомпиливаю код в атмел студио 6 работать перестаёт хоть и компилит без ошибок. в чём может быть проблема? я вообще с cvavr работал, может что не так делаю? создаю проект GCC C++ Executable Project потом с боку в solution explorer выбираю Atmegu8 добавляю файлы main.c rc5.c main.h rc5.h в проект и жму Buil All, соданный hex не работает 🙁

  • sergejus

    исправил все пред идущие ошибки появилась одна последняя http://s24.postimg.org/4n4eitqgl/posledniaja.png в чём тут может быть проблема?

    • Kibermaster

      замените структуру на:
      struct rc5_t{
      unsigned char control_bit;
      unsigned char system;
      unsigned char command;
      unsigned char flag;
      unsigned char dataOK;
      unsigned char error;
      } ;
      struct rc5_t rc5;

      • sergejus

        всё равно тоже самое, не понимаю что за фигня, компилирует без ошибок, а Buil All при создании hex кидает эту ошибку. пробовал вообще удалять куски кода и вообще всё оставляя тот rc5.h и всё равно та ошибка

  • Sherl

    Подтверждаю наблюдение sergejus’a — под AVR Studio 6.1 компилится, но не работает. Буду пробовать под 4-ой…

  • Sherl

    Уважаемый Kibermaster, возник следующий вопрос: в доке по rc5 сказано, что часть команд (напр. громкость) передается в виде строки. Правильно ли я понял? И поддерживает ли Ваш код возврат значения этого типа?

  • johndoe

    Мужики. не работает. компилится. но кнопки на пульте жму — не работает.
    компилил и под 6.1 авр студио и под 4й. результат один.

    у меня вместо 8й меги стоит 32я. порты в функции мейн поменял под свои. мб что менять надо еще в коде?

    и ик-приемник стоит 536aa3p. работоспособность проверена.

    в чем может быть дело?

  • Strideman

    Автор, спасибо за статью и подскажите что за чудеса творятся..
    Главный код. Вот так не работает (Ваш код):

    while(1)
    {
    if (rc5.dataOK) { // если получены данные с ПДУ
    PORTD = 0; // тушим все светодиоды
    sbi(PORTD, rc5.command); // зажигаем светодиод, соответствующий комманде с ПДУ

    rc5.dataOK = 0; // сбрасываем флаг
    }
    }

    А вот так работает:

    int i=0;
    while(1)
    {
    if (rc5.dataOK) { // если получены данные с ПДУ
    PORTA = 0; // тушим все светодиоды
    sbi(PORTA, rc5.command); // зажигаем светодиод, соответствующий комманде с ПДУ

    rc5.dataOK = 0; // сбрасываем флаг
    }
    if (i++>20000) //Считаем 20к прохождения кода
    {
    i=0; //сбрасываем переменную счета
    PORTA = 0; // тушим все светодиоды
    }
    }

    Эта штука просто выключает порт с задержкой. Но почему она влияет на работу главного кода? Без нее вообще не работает.
    Если вместо всего этого моего ифа поставить i=0; (что тоже бессмысленно и не влияет на работу кода), то работает, но оочень тупит. Очень долго нужно жать на кнопку пульта чтобы состояние светодеодов изменилось.
    Такое чувство, что нужно писать какой нибудь код после кода if(rc5.dataOK), всё равно какой, но лишь бы чтоб он был..
    Просто чудеса..
    Микроконтроллер AtMega-16.
    Спасибо.

    • Kibermaster

      Получается так:
      При нажатии кнопки на пду он отправляет комманду, мк ее принимает и обрабатывает, так как после кода обработки ничего нет, то он сразу же опять реагирует на комманду с пду (при зажатой кнопке она отправляется несколько раз в секунду). Вобщем, после обработки программы сделайте задержку 1 секунду.

  • Strideman

    И еще вопрос. Можно каким-то чудом сделать это всё на кварце 16 мгц? Может как-то прескейлер настроить.. Пробовал, ничего не вышло.
    PS. Дефайны пересчитывал..

    • Kibermaster

      в rc5.h переопределить дефайны.

      • Strideman

        Спасибо заработало. Тогда не получилось. Всё так же сделал. Может та проблема повлияла.
        Может кому понадобится:
        настройки под 16мГц

        в rc5.h :
        #define RC5_T 111 //((F_CPU/PRESCALER/1000)*1.778) //хотя я думаю ничего страшного что получилось 111,125

        в rc5.с
        TCCR1B = _BV(CS12) | _BV(ICNC1); //Предделитель: 256

        На делителе 1024 не получилось.

  • Valaster

    Здравствуйте, Kibermaster!
    Как правильно написать код, чтобы при нажатии на кнопку «1» пульта выполнялась первая программа (несколько комбинаций светодиодов), при нажатии на кнопку «2» — вторая программа…
    а то у меня кучу ошибок выдает типа: ../main.c:33: error: lvalue required as left operand of assignment

  • Valaster

    я хочу написать программку для гирлянды

    • Valaster

      не могу кирилицу выставить…
      я только учусь и пытаюсь такой код написать:

      #include
      #include
      #include
      #include «rc5.h»
      #include «main.h»

      int main (void)
      {
      PORTB = 0b00000000; DDRB = 0b00000000;
      PORTC = 0b00000000; DDRC = 0b11111111;
      PORTD = 0b00000000; DDRD = 0b11111111; // òóò ñâåòîäèîäû

      Rc5_SetRx(); // èíèöèàëèçèðóåì òàéìåð 1

      sei(); // ãëîáàëüíî ðàçðåøàåì ïðåðûâàíèÿ

      while(1)
      {
      if (rc5.dataOK) { // Если получены данные с пульта
      {
      if (rc5.command==1) // åñëè ýòî êíîïêà 1
      {

      PORTD = 0; // òóøèì âñå ñâåòîäèîäû
      sbi(PORTD, 0); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTD, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTD, 2); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTD, 3); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b00011111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b00111111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b01111111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b11111111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ

      }

      rc5.dataOK = 0; // ñáðàñûâàåì ôëàã
      }

      {
      if (rc5.command==2) // åñëè ýòî êíîïêà 2
      {
      PORTB = 0; // òóøèì âñå ñâåòîäèîäû
      PORTC = 0; // òóøèì âñå ñâåòîäèîäû
      PORTD = 0; // òóøèì âñå ñâåòîäèîäû
      sbi(PORTC = 0b00001111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b00011111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b00101111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b01001111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b10001111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b01001111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b00101111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ
      sbi(PORTC = 0b00011111, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
      _delay_ms(500); //çàäåðæêà 500 ìñ

      }
      rc5.dataOK = 0; // ñáðàñûâàåì ôëàã

      }

      }

      }

      • Kibermaster

        while(1)
        {
        if (rc5.dataOK) { // если получены данные с ПДУ
        if (rc5.command==1) {
        // программа по нажатию 1
        }
        else if (rc5.command==2) {
        // программа по нажатию 2
        }
        }
        }

        • Valaster

          спасибо, а саму программку и сброс флага где записать?

        • Valaster

          Подскажите пожалуйста, как можно сократить запись задержки, чтобы не под каждой строкой ее писать?

          #include «avr/io.h»
          #include «avr/interrupt.h»
          #include «avr/delay.h»
          #include «rc5.h»
          #include «main.h»

          int main (void)
          {
          PORTB = 0b00000000; DDRB = 0b00000000;
          PORTC = 0b00000000; DDRC = 0b11111111;
          PORTD = 0b00000000; DDRD = 0b11111111; // òóò ñâåòîäèîäû

          Rc5_SetRx(); // èíèöèàëèçèðóåì òàéìåð 1

          sei(); // ãëîáàëüíî ðàçðåøàåì ïðåðûâàíèÿ

          while(1)
          {
          if (rc5.dataOK) { // åñëè ïîëó÷åíû äàííûå ñ ÏÄÓ
          if (rc5.command==1)
          {
          // ïðîãðàììà ïî íàæàòèþ 1
          PORTD = 0; // òóøèì âñå ñâåòîäèîäû
          sbi(PORTD, 0); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTD, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTD, 2); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTD, 3); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTC,0b00011111); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTC, 0b00111111); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTC, 0b01111111); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTC, 0b11111111); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ

          }

          rc5.dataOK = 0; // ñáðàñûâàåì ôëàã
          }

          else if (rc5.command==2) {
          // ïðîãðàììà ïî íàæàòèþ 2

          PORTD = 0; // òóøèì âñå ñâåòîäèîäû
          sbi(PORTD, 0); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTD, 1); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTD, 2); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTD, 3); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTC,0b00011111); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTC, 0b00111111); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTC, 0b01111111); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ
          sbi(PORTC, 0b11111111); // çàæèãàåì ñâåòîäèîä, ñîîòâåòñòâóþùèé êîììàíäå ñ ÏÄÓ
          _delay_ms(500); //çàäåðæêà 500 ìñ

          }

          rc5.dataOK = 0; // ñáðàñûâàåì ôëàã
          }

          }

        • Valaster

          и последнее.
          У меня выдает ошибку, но не пойму чего от меня надо:
          c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/bin/ld.exe: rc5.elf section .text will not fit in region text
          c:/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/bin/ld.exe: region text overflowed by 608 bytes
          make: *** [rc5.elf] Error 1
          Build failed with 2 errors and 0 warnings…

  • Valaster

    Подскажите пожалуйста, почему так происходит?
    Я увеличиваю размер программы, соответственно вижу, что увеличивается объем файлов: main.c, Makefil, а после компиляции файл rc5.hex остается с прежним весом.

  • mrbin

    для code vizion avr,как этот код переделать?

  • mrbin

    а вы в каком компилировали?

  • mrbin

    а еще не подскажите avr studio выдает такую ошибку,,make: Makefile: No such file or directory,в чем может быть дело?

  • mrbin

    подскажитьте пожалуйста avr studio дает такую ошибку,код копирую

  • mrbin

    вот что пишет ../priem.c:1:17: fatal error: rc5.h: No such file or directory

  • mrbin

    как понять в пути не латинские символы?

  • mrbin

    папка с проектом лежит в локальном диске D ,AVR STUDIO4? а куда лучше положить?

  • mrbin

    https://mail.yandex.ru/neo2/#disk/disk/ вот здесь архив посмотрите что там может быть не так

  • mrbin

    програмирую hex файлом тоже от микроконтролера молчание

  • rastamanoff

    Добрый вечер.Вот бьюсь над одной проблемой,есть код,который включает/выключает канал 1-4,в зависимости от нажатой кнопки на пульте 1-4:

    #include
    #include
    #include
    #include "rc5.h"
    #include "main.h"

    int main (void)
    {
    PORTB = 0b00000000; DDRB = 0b00000000;
    PORTC = 0b00000000; DDRC = 0b00000000;
    PORTD = 0b00000000; DDRD = 0b11111111; // тут светодиоды

    Rc5_SetRx(); // инициализируем таймер 1

    sei(); // глобально разрешаем прерывания

    while(1)
    {
    if (rc5.dataOK) // если получены данные с ПДУ
    {
    if (rc5.command==1) // если это кнопка 1
    {
    if (CheckBit(PIND, 0)) cbi(PORTD, 0); //если канал 1 включен, выключаем
    else sbi(PORTD, 0); // если канал 1 выключен, включаем
    }
    if (rc5.command==2) // если это кнопка 2
    {
    if (CheckBit(PIND, 1)) cbi(PORTD, 1); //если канал 2 включен, выключаем
    else sbi(PORTD, 1); // если канал 2 выключен, включаем
    }
    if (rc5.command==3) // если это кнопка 3
    {
    if (CheckBit(PIND, 2)) cbi(PORTD, 2); //если канал 3 включен, выключаем
    else sbi(PORTD, 2); // если канал 3 выключен, включаем
    }
    if (rc5.command==4) // если это кнопка 4
    {
    if (CheckBit(PIND, 3)) cbi(PORTD, 3); //если канал 4 включен, выключаем
    else sbi(PORTD, 3); // если канал 4 выключен, включаем
    }
    _delay_ms(700); //задержка 700 мс
    rc5.dataOK = 0; // сбрасываем флаг
    }
    }
    }

    Все бы хорошо,но вот если нажатую кнопку пульта "передержать" соответствующий канал включается/выключается.А хотелось чтобы канал включился,и контролер ждал отпускания кнопки пульта,а уже потом обрабатывал следующее нажатие.
    Пробовал вставлять

    ...
    _delay_ms(700); //задержка 700 мс
    rc5.dataOK = 0; // сбрасываем флаг

    while (rc5.dataOK) ;//ждем отпускания кнопки

    Результат нулевой,канал вкл/выкл.
    Я начинающий прошу не судить строго если чего не так.

  • rastamanoff

    Strideman
    14.09.2013 at 3:33 дп · Ответ
    Спасибо заработало. Тогда не получилось. Всё так же сделал. Может та проблема повлияла.
    Может кому понадобится:
    настройки под 16мГц

    в rc5.h :
    #define RC5_T 111 //((F_CPU/PRESCALER/1000)*1.778) //хотя я думаю ничего страшного что получилось 111,125

    в rc5.с
    TCCR1B = _BV(CS12) | _BV(ICNC1); //Предделитель: 256

    На делителе 1024 не получилось.

    Вот перещитал на 16 МГц ,предделитель на 8

    // RC5_T нужно расчитать вручную (особенности компилятора)
    #define RC5_T 3556 //((F_CPU/PRESCALER/1000)*1.778)
    #define FAULT_TIME_RC5 RC5_T*17 // не должно быть более 65535

    Получается целое число,и главное работает в «метале» — проверенно.

  • ip_kanatov

    Kibermaster, я читал полностью все комментарии, но вопросов все же есть. Вы говорите что пульт передает цифру в посылке команды, а как сделать чтоб реагировал не на цифровые клавиши а на другие к примеру ON/OFF MUTE и т.д. У меня есть сомнение, привожу пример. Есть пульт первый от телевизора и второй тоже от другого телевизора, если скажем что оба пульта работают на устройстве при нажатии клавиш, значит МК думает что принимает один и тот же сигнал с обоих пульта, но в реальности эти сигналы не одинаковы же, потому что первый телевизор не принимает сигнал от второго. Объясните пожалуйста.

    • Kibermaster

      На счет кнопок MUTE и т.д., они тоже передают числовое значение (до 127 по-моему).
      Если поставить 2 одинаковых телевизора, у которых будут одинаковые пульты (с одинаковыми кодировками), то при нажатии кнопки на 1 пульте будут реагировать оба телевизора.

      • ip_kanatov

        Про телевизоры Вы не поняли наверное, но я только что читал про работу rc5 из других материалов. Пульт передает 14 бит, 2 бита стартовые 3-и дежурный и дальше 5 битов определены стандартом для разных устройств (тв, магнитофон и тд), а вот последние 6 бит отвечают за кнопки. Теперь я так думаю что, при приеме сигналов с разных пультов из разных устройств 5 бит могут быть разными, но последние 6 бит у всех одинаковы, я правильно понял?

  • ip_kanatov

    и еще, как привязать код только к одному пульту. чтоб другие пульты не реагировали.

    • Kibermaster

      в структуре rc5 есть system и command, первый отвечает за тип команды (для телика, проигрывателя и т.д.)

      • ip_kanatov

        Один пользователь написал в комментариях что хочет портировать из AVR studio в CodeVision, у него получился? Я тоже хочу перевести, мой проект уже написан на нем, теперь хочу добавить ИК прием.

        • Kibermaster

          это к нему вопрос)))))

          • mrbin

            кибермастер подскажите как в этой программе зделать что бы при нажатии кнопки 1 диод горел при отпускании тух

            #include
            #include
            #include

            // Временные пределы
            #define Tmin 40 // длинный промежуток
            #define Tmax 68
            #define TminK 22 // короткий промежуток
            #define TmaxK 34

            unsigned char sct_bit = 0; // Счетчик битов RC5
            unsigned char RC5_buffer [14]; // Буфер RC5
            unsigned char centre = 0; // Флаг центра
            unsigned char not_korr = 0; // Флаг попадания в промежутки
            unsigned char Timer = 0; // число в счетчике таймера
            unsigned char command = 0; // переменная для команды
            char s = 0;

            // Функция очистки буфера
            void rc5_cl_buf(void)
            {
            unsigned char i = 0;
            for (i=0; i<14; i++)
            {
            RC5_buffer = 0;
            }
            }

            // функция остановки таймера
            void rc5_ti_stop(void)
            {
            GICR = 0x00;
            TCCR0 = 0x00;
            TCNT0 = 0;
            sct_bit = 0;
            }

            // Обработчик прерывния по переполнению Т0
            ISR (TIMER0_OVF_vect)
            {
            rc5_ti_stop(); //останавливаем таймер
            rc5_cl_buf(); //очищаем буфер
            GICR |= (1 << INT0); //разрешаем прерывания по входу INT0
            GIFR |= (1 << INTF0); //сбрасываем флаг прерывания (если произошло)
            }

            // Обработчик внешнего прерывания INT0
            ISR(INT0_vect)
            {
            Timer = TCNT0; // запоминаем значение счетчика
            TCNT0 = 0; // обнуляем счетчик
            not_korr = 1;

            if(sct_bit==0)
            {
            TCCR0 |= (1 << CS02); // запускаем таймер (31.250 KHz)
            RC5_buffer [sct_bit] = !(PIND&(1 < TminK)&&(Timer < TmaxK))
            {
            if (centre)
            {
            centre = 0;
            not_korr = 0;
            }
            else
            {
            centre = 1;
            RC5_buffer [sct_bit] = !(PIND&(1 < Tmin)&&(Timer < Tmax))
            {
            RC5_buffer [sct_bit] = !(PIND&(1 << PD2));
            sct_bit++;
            not_korr = 0;
            }

            if (not_korr == 1)
            { // если не попали ни в один из промежутков то
            rc5_ti_stop(); // останавливаем таймер
            rc5_cl_buf(); // очищаем буфер
            }

            if (sct_bit == 14)
            { // если бит последний то
            rc5_ti_stop(); // останавливаем таймер

            // Формируем код команды
            command = (RC5_buffer [8] << 5)|(RC5_buffer [9] << 4)|
            (RC5_buffer [10] << 3 )|(RC5_buffer [11] << 2)|
            (RC5_buffer [12] < 1)
            s = 0;

            }
            GICR |= (1 << INT0); // разрешаем прерывания по входу INT0
            GIFR |= (1 << INTF0); // сбрасываем флаг прерывания по входу INT0
            }
            }

            int main(void)
            {
            DDRB = 0xFF; // выход
            PORTB = 0x00;
            DDRD &= ~(1 << PD2); // вход ИК
            PORTD = 0x00;

            TIMSK |= (1 << TOIE0); // разрешение прерывания по таймеру0

            GICR |= (1 << INT0); // разрешаем прерывания по входу INT0
            MCUCR |= (1 << ISC00); // прерывание по любому фронту
            GIFR |= (1 << INTF0); // сбрасываем флаг прерывания

            sei(); // глобально разрешаем прерывания

            while(1)
            {
            if(s == 1)
            PORTB |= (1 << PB0); // Включаем светодиод
            if(s == 0)
            PORTB &= ~(1 << PB0); // Выключаем светодиод
            }
            }

  • sannya

    Ссылка на файлы не работает.

  • mastech

    день добрый. какую функцию выполняет CheckBit? из перевода ясно, что проверка бита, а что он проверяет и как реализовать если мне нужно включить несколько каналов.

    if (rc5.command==1)
    {
    if (CheckBit(PINC, 0)) //это с одной командой
    {
    cbi(PORTC, 0);
    }
    else sbi(PORTC,0)
    }
    //////////////////////////////////////////////////////////////////////

    if (rc5.command==1)
    {
    if (CheckBit(PINC, 0)) //а как быть с несколькими портами? перечислять через запятую?
    {
    cbi(PORTA, 0);
    cbi(PORTB, 1);
    cbi(PORTC, 2);
    cbi(PORTD, 3); …

  • Valaster

    Здравствуйте, Кибермастер! Подскажите, пожалуйста, как реализовать следующий эффект. При нажатии кнопки 1, включается цикл с первой программой, при нажатии 2 — цикл второй программы и т.д. Я никак не могу выйти из цикла и перейти к следующей программе. Какое должно быть условие? И как определить код кнопки Power на пульте, чтобы можно было всю гирлянду просто потушить.

    #include «delay.h»
    #include «rc5.h»
    #include «main.h»

    void main (void)

    {
    PORTB = 0b00000000; DDRB = 0b00000000; // тут светодиоды и на РВ7 ИК-порт
    PORTC = 0b00000000; DDRC = 0b00000000;
    PORTD = 0b00000000; DDRD = 0b11111100; // тут светодиоды
    Rc5_SetRx();

    #asm («sei»)

    while(1)
    {
    if (rc5.dataOK) { // если получены данные с ПДУ
    if (rc5.command==1) { // программа по нажатию 1
    while (1) {
    PORTD=0b00000100;
    delay_ms(500);
    PORTD=0b00001000;
    delay_ms(500);
    PORTD=0b00000100;
    delay_ms(500);

    };

    }
    else if (rc5.command==2) { // программа по нажатию 2
    while (1) {
    PORTD=0b00001100;
    delay_ms(500);
    PORTD=0b00011000;
    delay_ms(500);
    PORTD=0b00010100;
    delay_ms(500);
    };
    }
    else if (rc5.command==3) { // программа по нажатию 3
    while (1) {
    PORTB=0b00000000;
    PORTD=0b00000100;
    delay_ms(100);
    PORTB=0b00000000;
    PORTD=0b00001100;
    delay_ms(100);
    PORTB=0b00000000;
    PORTD=0b00011100;
    delay_ms(100);
    PORTB=0b00000000;
    PORTD=0b00111100;
    delay_ms(100);
    PORTB=0b00000000;
    PORTD=0b01111100;
    delay_ms(100);
    PORTB=0b00000000;
    PORTD=0b11111100;
    delay_ms(100);
    PORTB=0b00000001;
    PORTD=0b11111100;
    delay_ms(100);
    PORTB=0b00000011;
    PORTD=0b11111100;
    delay_ms(100);
    };
    }

    delay_ms(700);
    rc5.dataOK = 0;
    }

    }
    }

    • Kibermaster

      while(1)
      {
      if (rc5.dataOK) {
      rc5.dataOK = 0;

      switch (rc5.command) {
      case 1: while (rc5.dataOK==0) {
      // программа по нажатию 1
      } break;
      case 2: while (rc5.dataOK==0) {
      // программа по нажатию 2
      } break;
      // и т.д.
      }
      }
      }

      Код кнопки power — 12

  • Valaster

    Здорово! Получилось! А то я уже все операторы цикла перебрал с различными условиями и результат = 0.
    А возможно ли после того как кнопкой power я потушил гирлянду, повторным нажатием на power включить гирлянду с того же case, на котором она была выключена?

    • Kibermaster

      Сделайте переменную, в которую будет записываться последний кейс, после включения перед switch устанавливайте значение этой переменной в rc5.command

      • Valaster

        Спасибо, сейчас поэкспериментирую.

      • Valaster

        Подскажите, а какой оператор присваивания применить к переменной, чтобы записывалось значение последнего кейса?

        • Kibermaster

          =. Вопрос сильно ламерский.

          • Valaster

            я имел в виду, как указать, что это именно последний кейс, который работал до выключения

          • Valaster

            просто указать i=case;

            • Kibermaster

              при входе в каждый кейс перед while записывайте в нужную переменную значение с rc5.command

              • Valaster

                Здравствуйте, Kibermaster!

                Уже много дней провел над решением своей задачи. Перечитывал Лебедева и Белова, пересмотрел массу обучающих роликов, но все же результат отрицательный.
                Я не понял подсказок, которые вы мне дали.

                Задача заключается в том, чтобы кнопкой power потушить гирлянду, а повторным нажатием на power включить гирлянду с того же case, на котором она была выключена?
                Чтобы программа продолжила работу после отключения питания я решил воспользоваться EEPROM.
                В ходе экспериментов наблюдал изменение EEPROM, но при подаче питания включения программы не происходит.
                Где у меня ошибки?

                #include «delay.h»
                #include «rc5.h»
                #include «main.h»

                eeprom char Canal_eep;
                unsigned char d;

                void main (void)

                {
                PORTB = 0b00000000; DDRB = 0b00000000; // тут светодиоды и на РВ7 ИК-порт
                PORTC = 0b00000000; DDRC = 0b00000000;
                PORTD = 0b00000000; DDRD = 0b11111100; // тут светодиоды
                Rc5_SetRx();

                d = Canal_eep;

                #asm («sei»)

                while(1)
                {

                if (rc5.dataOK) {
                rc5.dataOK = 0;

                Canal_eep = d;

                switch (rc5.command) {
                case 1:
                d = rc5.command;
                while (rc5.dataOK==0) { // программа по нажатию 1
                PORTD=0b00000100;
                delay_ms(500);
                PORTD=0b00001000;
                delay_ms(500);
                PORTD=0b00000100;
                delay_ms(500);
                } break;

                case 2:
                d = rc5.command;
                while (rc5.dataOK==0) { // программа по нажатию 2
                PORTD=0b00001100;
                delay_ms(500);
                PORTD=0b00011000;
                delay_ms(500);
                PORTD=0b00010100;
                delay_ms(500);
                } break;

                case 3:
                d = rc5.command;
                while (rc5.dataOK==0) { // программа по нажатию 3
                PORTB=0b00000000;
                PORTD=0b00000100;
                delay_ms(100);
                PORTB=0b00000000;
                PORTD=0b00001100;
                delay_ms(100);
                PORTB=0b00000000;
                PORTD=0b00011100;
                delay_ms(100);
                PORTB=0b00000000;
                PORTD=0b00111100;
                delay_ms(100);
                PORTB=0b00000000;
                PORTD=0b01111100;
                delay_ms(100);
                PORTB=0b00000000;
                PORTD=0b11111100;
                delay_ms(100);
                PORTB=0b00000001;
                PORTD=0b11111100;
                delay_ms(100);
                PORTB=0b00000011;
                PORTD=0b11111100;
                delay_ms(100);
                } break;

                }
                }

                }

                delay_ms(500);
                rc5.dataOK = 0;
                }

              • Kibermaster

                Тоесть, вам нужно сохранять последнее состояние даже после того, как будет полностью отключено питание микроконтроллера?

                • Valaster

                  Да, верно. Поэтому я и решил использовать EEPROM. Но, что-то не так. Смотрел различные ролики, пытался повторить, но видимо что-то упустил.

                  • Kibermaster

                    int lastCommand = 1; // последняя полученая комманда. Счиитываем её с eeprom
                    int state = 0; // состояние
                    while(1)
                    {
                    if (rc5.dataOK) {
                    rc5.dataOK = 0;

                    if (rc5.command == 12) { // нажатие кнопки POWER
                    if (state) { // если гирлянда включена
                    state = 0;
                    /// тушим гирлянду и сохраняем lastCommand в eeprom
                    }
                    else {
                    state = 1;

                    rc5.command = lastCommand;
                    }
                    }

                    if (state) // если включено
                    switch (rc5.command) {
                    case 1: while (rc5.dataOK==0) {
                    lastCommand = rc5.command; // сохраняем последнее нажатие
                    // программа по нажатию 1
                    } break;
                    case 2: while (rc5.dataOK==0) {
                    lastCommand = rc5.command; // сохраняем последнее нажатие
                    // программа по нажатию 2
                    } break;
                    // и т.д.
                    }
                    }
                    }

                    • Valaster

                      Спасибо, сейчас буду испытывать.

                    • Valaster

                      Есть ошибка Error: E:\Projects AVR\RC5_new\main.c(17): must declare first in block, ругается на

                      int lastCommand = 1; // последняя полученая комманда. Счиитываем её с eeprom
                      int state = 0; // состояние

                      lastCommand и state где надо объявить, в файле mail.c или в структоре rc5.h

                    • Valaster

                      Kibermaster, прости… не хватает моих скудных знаний.
                      Куда я только не пытался уже поставить эти строки кода:
                      int lastCommand = 1; // последняя полученая комманда. Счиитываем её с eeprom
                      int state = 0; // состояние

                      ругательства сплошные. То case1 включается при нажатии на POWER, то вообще не реагирует. При этом ошибок не выдает.
                      Помоги пожалуйста.

                    • Valaster

                      Добрый день, Kibermaster!
                      Что я не так делаю? Срабатывание от кнопки POWER не постоянное (иногда надо дважды нажать, чтобы произошло переключение программы или вызов программы после отключения питания). И не удается включить последнюю исполняемую программу после подачи питания (т.е. не задействую кнопку POWER, подать питание и сразу включилась бы последняя программа).

                      #include «delay.h»
                      #include «rc5.h»
                      #include «main.h»

                      eeprom int d_eep;

                      int lastCommand = 1; // последняя полученая комманда. Счиитываем её с eeprom
                      int state = 0; // состояние

                      void main (void)

                      {
                      PORTB = 0b00000000; DDRB = 0b00000000; // светодиоды и на РВ7 ИК-порт
                      PORTC = 0b00000000; DDRC = 0b00000000; // светодиоды
                      PORTD = 0b00000000; DDRD = 0b11111100; // светодиоды
                      Rc5_SetRx();

                      lastCommand = d_eep;

                      #asm («sei»)

                      while(1)
                      {
                      if (rc5.dataOK) {
                      rc5.dataOK = 0;

                      if (rc5.command == 12) { // нажатие кнопки POWER
                      if (state) { // если гирлянда включена
                      state = 0;
                      PORTD=0b00000000;
                      delay_ms(40);
                      d_eep = lastCommand; /// тушим гирлянду и сохраняем lastCommand в eeprom
                      }
                      else {
                      state = 1;
                      rc5.command = lastCommand;
                      }
                      }
                      if (state) // если включено

                      switch (rc5.command) {
                      case 1: while (rc5.dataOK==0) { // программа по нажатию 1
                      lastCommand = rc5.command; // сохраняем последнее нажатие
                      d_eep = lastCommand;
                      PORTD=0b00000100;
                      delay_ms(500);
                      PORTD=0b00001000;
                      delay_ms(500);
                      PORTD=0b00000100;
                      delay_ms(500);
                      } break;

                      case 2: while (rc5.dataOK==0) {
                      lastCommand = rc5.command; // сохраняем последнее нажатие
                      d_eep = lastCommand;
                      PORTD=0b00001100;
                      delay_ms(500);
                      PORTD=0b00011000;
                      delay_ms(500);
                      PORTD=0b00010100;
                      delay_ms(500);
                      } break;

                      case 3: while (rc5.dataOK==0) {
                      lastCommand = rc5.command; // сохраняем последнее нажатие
                      d_eep = lastCommand;
                      PORTB=0b00000000;
                      PORTD=0b00000100;
                      delay_ms(100);
                      PORTB=0b00000000;
                      PORTD=0b00001100;
                      delay_ms(100);
                      PORTB=0b00000000;
                      PORTD=0b00011100;
                      delay_ms(100);
                      PORTB=0b00000000;
                      PORTD=0b00111100;
                      delay_ms(100);
                      PORTB=0b00000000;
                      PORTD=0b01111100;
                      delay_ms(100);
                      PORTB=0b00000000;
                      PORTD=0b11111100;
                      delay_ms(100);
                      PORTB=0b00000001;
                      PORTD=0b11111100;
                      delay_ms(100);
                      PORTB=0b00000011;
                      PORTD=0b11111100;
                      delay_ms(100);
                      } break;
                      }
                      }
                      }

                      delay_ms(700);
                      rc5.dataOK = 0;
                      }

  • skif2509

    можно ли эту прошивку с некоторыми переделками закинуть на atmega 16a ножки и всё остальное вроде подходят?

  • skif2509

    ещё вопрос,это можно сразу в atmel studio перекомпилировать или код нужно менять?

  • skif2509

    нет разницы какой ик-приёмник использовать?у меня TL1838 VS1838B 38 кГц

  • Mr.Hublots

    Ресет обязательно подтягивать к +. А то что-то не хочет работать. Прошил хексом из папки дебаг.

  • Mr.Hublots

    Подскажите, пожалуйста, например кнопка «1» пульта — это команда «rc5.command==1». Т.е. 1 соответствует кнопке, а если это VOL_UP или CH_UP и т.д., то как быть? Как определить их???

  • Space

    Здравствуйте Kibermaster.
    У меня на Atmel Studio 6 (Version: 6.2.1563 — Service Pack 2) при попытке сбилдить код выскакивает во такая ошибка Error 2 undefined reference to `Rc5_SetRx’, и еще вот такая Error 3 ld returned 1 exit status collect2.exe 0 0 PreAmp_RC5
    В чем может быть причина?

  • Space

    Подключены только эти:
    #include
    #include
    #include
    #include «rc5.h»
    #include «main.h»

    а остальные лежат в папке проекта, там, где папка Debug.
    Что то еще нужно подключать в основном коде?

    • Kibermaster

      В сам проект нужно подключить *.с файлы.
      Пишите через ответ (reply).

      • Space

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

  • Michael

    Привет всем.
    А можно заставить эту схему работать с протоколом NEC?
    Может делал кто?
    Пульт от RGB контроллера, 24 кнопки.
    Нужно чтобы работали только 8.

    Всего хорошего.

Leave a Reply