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

Обновлено 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

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

Вливайтесь в общение

216 комментариев

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

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

      _delay_ms(700);
      }

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

    1. их менять не надо, (если применяешь атмегу), прошивка заточена под 1МГц

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

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

      замени на PORTD = 0xFF;

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

    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; // сбрасываем флаг
    }

    1. На 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; // сбрасываем флаг
      }
      }

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

    1. а это дефайны такие, чтобы было более удобно писать код.
      Задержку лучше ставить в конце бесконечного цикла (while(1))

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

    1. ну так я же готовый исходник привел. просто вставь тот текст и скомпилируй

  7. 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

    1. 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

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

  9. как я понял в этом месте с погрешностью не более 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%

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

  10. я сразу прошу прощения за свой быдло код))) когда я делаю так(см.код) то отклики не стабильны либо сразу включится и выключится или вкл. но с 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; // сбрасываем флаг

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

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

  11. появилось время опять вернулся к 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;
    }
    }
    }

    1. просто нужно после выполнения алгоритма по нажатию кнопки (в конце if (rc5.dataOK)) ставить задержку где то на 0,7-1 секунду

      1. А что за кнопка?
        На схеме ее нету.
        И для чего она?

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

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

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

    1. да ни как привязывать не надо, просто прошить. После прошивки девайс должен реагировать на нажатие кнопок пульта

        1. struct {
          unsigned char control_bit;
          unsigned char system;
          unsigned char command;
          unsigned char flag;
          unsigned char dataOK;
          unsigned char error;
          } rc5;

          можно поподробнее про это?

      1. Кстати, каким пультом вы пользуетесь? Мой подойдет?

        1. я просто пришел на базар и попросил пульт rc5:)

  15. #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; // сбрасываем флаг
    }
    }

    }

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

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

    1. ну при нажатии цифровых кнопок пульт передает цифру, которая написана на кнопке, а МК при приеме включает этот бит на порте МК

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

    1. так в инете же куча инфы как заливать прошивку с подробным описанием

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

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

      1. програмировать нужно фаилом rc5.HEX (выложенным вами) ,или нужно кодом из темы???

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

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

    1. попробовать его на рабочем устройстве:)

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

    1. ну к схеме подходит пулmт с командами RC5. Если не написано на пульте, то разберите его и посмотрите, какая там стоит микра

      1. микросхема хз какая, залика компаундом (капля так называемая)

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

    1. вообще, должен подойти, только распиновку проверьте. И еще частота может отличаться, из-за чего сигнал будет приниматься немного хуже

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

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

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

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

  26. Здравствуйте.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 мс
    }

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

    1. установите задержку внутрь цикла if (rc5.dataOK), тогда срабатывание будет четким

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

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

    2. а, бля, 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; // сбрасываем флаг
      }

      }

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

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

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

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


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

    ???

    1. частоту поделить на пределитель таймера, поделить на 1000 и все это умножить на 1.778

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

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

    1. сорри, но я в нем никогда не писал, но на 90% уверен, что код будет тот же

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

    1. в rc5.h сверху 2 макроса, которые надо под свою частоту пересчитать

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

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

    1. #define RC5_T 2667
      а в функции Rc5_SetRx нужно установить делитель на 8:
      TCCR1B= _BV(CS11)|_BV(ICNC1);

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

    1. напротив этого макроса есть формула, по которой можно посчитать.

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

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

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

    1. лично у меня студия 5 и 6 как то криво работают. Я использую студию 4 и последний тулчейн

        1. ошибки, во первый, из-за того, что обработчики прерывания в CVAVR пишутся не так, как в WinAVR, а во вторых, из-за того, что в этих компиляторах разные макросы для битовых операций, ну и main должен объявлять по-ином, что и указано в ошибках на вашем скрине.
          int main(void) замените на void main(void)
          _BV(CS10) на (1<

          1. вот что вычитал в нете, но не доходит как точно нужно переписать это ISR(TIMER1_CAPT_vect) ? :/

            в CodeVision:

            interrupt [прерывание] void adc_isr(void)
            { }

            #include

            ISR(прерывание_vect)
            { }

            В примерах слово «прерывание» нужно заменить на название прерывания из ДатаШита либо из заголовочного файла *.h для используемого МК.

    2. Попробуйте что то типа
      interrupt [TIM1_ICMP] void timer1_icmp_isr(void)

    1. замените структуру на:
      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;

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

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

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

    1. не строки, а набора импульсов. Фактически, там просто 3 байта

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

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

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

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

    1. если приемник подключили правильно (распиновка не как у TSOP1736)? то советую перекомпилировать в 4 студии

      1. приемник подключен правильно проверял его. подключал к int0. работает.
        в 4й студии компилил результат тот же.
        а может дело в пульте? я от телека беру самсунга. aa59-00581a
        такой
        http://www.displayland.ru/images/pdu/AA59-00581A.jpg
        мож он сигналы какие не те посылает?

        1. от самсунга не подойдет, так как там кодировка другая

    2. Ой. получилось. сначала купил пульт горизонт rc-5 mini. не работало. потом заменил ик-приемник на sm3374. и все заработало) кстати компилил в атмел студио 6.1

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

    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.
    Спасибо.

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

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

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

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

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

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

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

    1. вы писали, что у вас куча ошибок, откуда они взялись?
      Пишите через reply, иначе буду удалять

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

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

      #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; // ñáðàñûâàåì ôëàã

      }

      }

      }

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

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

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

          #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; // ñáðàñûâàåì ôëàã
          }

          }

        3. и последнее.
          У меня выдает ошибку, но не пойму чего от меня надо:
          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…

          1. думаю, что проблемы с кодировкой. Установите ANSI

          2. а где поменять кодировку?
            не могу ее найти…

          3. Наверно, где то в настройках редактора. Но у меня всегда изначально была установлена кодировка ANSI, менять ее никогда не приходилось

          4. Нашел проблему!
            В пути к папке проекта была папка с русским наименованием.
            Как только перенес проект в корень диска — ошибки пропали.

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

    1. это сложно сказать. Makefile практически не влияет на размер (кроме некоторых опций), но в этом проекте он не используется (генерируется автоматом). А hex меняется, но не значительно. напишите в коде volatile int ttt[1000] и увидите, как увеличится hex

      1. Пробовал установить volatile int ttt[1000] в разных участках кода, но на размер hex это не повлияло.
        К стати, а что за файл .elf ? Он тоже не меняет свой размер.
        А файлы rc5.cci и rc5.hci вообще у меня не формируются.

        1. об elf почитайте в инете. А в проекте есть еще какие то hex файлы?

          1. сегодня постараюсь проверить на работоспособность программку.

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

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

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

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

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

    1. возможно, в пути есть не латинские символы. Пишите через REply, иначе буду удалять

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

    1. по какому пути лежит папка с проектом?

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

    1. Скиньте архив с проектом.
      На счет reply — последнее предупреждение, далее добавляю в блэклист

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

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

    1. дайте хотя бы какие то файлы с вашим проектом. Я не экстрасенс.

        1. мне нужны файлы, а не ссылка на яндекс диск

          1. кибермастер,как вам отправить файлы,тут только по ссылке

  56. Добрый вечер.Вот бьюсь над одной проблемой,есть код,который включает/выключает канал 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) ;//ждем отпускания кнопки

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

    1. сделайте задержку не 700 мс, а, к примеру, 1500

      1. кибермастер объясните мне пожалуйсто почему у меня авр студии все проекты компилируются ,а вот именно этот нет,что я не так делаю? хекс файл на отладочной плате работает,в чем может быть причина?

          1. не существующая деректива «rc-5» и main.h

          2. выше 2 человека задавали этот вопрос

          3. а толчейн он туда же устанавливается,просто у меня все на диске d папок с русским названием нигде нет,а ошибка все равно вылазиит,у вас какая авр студия?

          4. тулчейн последний. Попробуйте добавить в опции коомпилятора __PROG_TYPES_COMPAT__

          5. нет не идет,незнаю что ей надо,все программы компилирует а эту не хочет.

          6. Кибермастер как вот это по другому прописать? #include «rc5.h»
            #include «main.h» и sbi.

  57. 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

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

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

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

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

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

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

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

          1. кибермастер подскажите как в этой программе зделать что бы при нажатии кнопки 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); // Выключаем светодиод
            }
            }

  60. день добрый. какую функцию выполняет 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); …

    1. Можно включать по отдельности.
      CheckBit(reg, b) — проверить бит регистра.
      sbi — установить бит регистра.
      cbi — сбросить бит регистра.

  61. Здравствуйте, Кибермастер! Подскажите, пожалуйста, как реализовать следующий эффект. При нажатии кнопки 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;
    }

    }
    }

    1. 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

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

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

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

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

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

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

          3. Здравствуйте, 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;
            }

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

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

          6. 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;
            // и т.д.
            }
            }
            }

          7. Есть ошибка 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

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

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

          9. Добрый день, 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;
            }

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

    1. Можно. По сути, просто перекомпилируй под мегу16. Подключение к тем же пинам.

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

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

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

    1. Не обязательно, но очень желаетльно

      1. А почему может не работать, все как на схеме, но не реагирует? Прошивал codevision.

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

  68. Здравствуйте 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
    В чем может быть причина?

    1. Файлы rc5.h и rc5.c подключены с проект?

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

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

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

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

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

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

  71. Доброго времени.
    Столкнулся с такой проблемой, в AtmelStudio7 старый проект компилируется не выдает никаких варнингов и ошибок но Хекс весит 4КБ и естественно не работает, а в AVRstudio 4.19 весит 34КБ и работает. До этого с другими проектами такой проблемы не было. Пробовал компилировать на двух компах.

    1. Здравствуйте! 34 кб явно не может весить, смотрите настройки оптимизации. И, скорей всего, ты хекс с бином путаете. Наверное, 4 кб весит бинарник, а 34 — хекс.

      1. С объемом Вы правы, но думаю это винда округляет, иначе он просто в контроллер не влез бы.
        Но проблема остается, старый хекс(4.19) работает, но таже самая библиотека RC5, и тот же майн(проект собран заново) в студии 7 компилируется но не работает. Попробую сейчас через импрорт попробовать.

        1. Разобрался, Ваш код работает только на нулевой оптимизации

  72. Добрый день!!!Как бы переделать код под CodeVisionAVR :

    переделал но работать не хочет????

    #include

    #include
    #include

    #define vuchar volatile unsigned char
    #define vuint volatile unsigned int

    #define sbi(reg,bit) reg |= (1<<bit)
    #define cbi(reg,bit) reg &= ~(1<<bit)
    #define ibi(reg,bit) reg ^= (1<<bit)
    #define CheckBit(reg,bit) (reg&(1<<bit))

    #define _BV(BIT_NUMBER) (1<<BIT_NUMBER)

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

    #define FL_RC5_RESET 0 // _BV(0) // сброс приемника
    #define FL_STBIT_1 1 // _BV(1) // первый стартовый бит
    #define FL_SAMPLE 128 // _BV(7) // резрешение выборки
    #define FL_FAULT 4 // _BV(2) // ошибка приема

    #define CAPT_ON_FALLING TCCR1B&=~0x40// (TCCR1B,ICES1)
    #define CAPT_ON_RISING TCCR1B|=0x40// (TCCR1B,ICES1)

    static unsigned int period, receive;
    static unsigned char counter_bit;
    unsigned int capture;

    unsigned char control_bit;
    unsigned char system;
    unsigned char command;
    unsigned char flag;
    unsigned char dataOK;
    unsigned char error;

    //void Rc5_SetRx(void);

    void Rc5_SetRx(void)
    {
    //TCCR1B|= _BV(CS10); //без предделителя
    //TCCR1B|= _BV(ICNC1); //Вкл. подавитель шума на входе захвата
    //TCCR1B&= ~_BV(ICES1); //Выбор детектируемого фронта на входе захвата
    //Если ICESn =0, то падающий фронт приводит к захвату, ICESn = 1, то нарастающий фронт.

    TCCR1B =0x81;// _BV(CS10) | _BV(ICNC1);//
    //TCCR1B = _BV(CS10) | _BV(ICNC1);//
    //TCCR1B = ((1<<0) | (1<<7));//

    //Регистр маски прерываний таймера-счетчика
    //_BV(TICIE1) Разрешение прерывания по захвату состояния таймера-счетчика 1;
    //_BV(OCIE1A);// Разрешение прерывания по совпадению

    TIMSK |=0x30;// _BV(TICIE1) | _BV(OCIE1A);
    //TIMSK |=_BV(TICIE1) | _BV(OCIE1A);
    //TIMSK |=((1<<5) |(1< period-TOLERANCE)&&(capture < period+TOLERANCE) )// середина бита (пропускаем значение capture меньше периода)
    {
    TCNT1=0;
    receive<>6;//6
    command = receive&0b111111;
    sbi(dataOK, 0);
    //dataOK|=0;
    flag &= ~FL_FAULT;
    //////////////////////////////////////////////////////////
    ReceivingOver();
    //////////////////////////////////////////////////////////
    /***********Receiving over***********/
    printf(«%u%u\n»,dataOK); // вывод данных
    }
    }
    ibi(TCCR1B,0x40);// ICESn = 1, то нарастающий фронт. ICESn =0, то падающий фронт //if ( TCCR1B & _BV(ICES1) ) TCCR1B &= ~_BV(ICES1); else TCCR1B|= _BV(ICES1);
    //TCCR1B^=0x40;
    }
    else
    {
    if ( (flag & FL_STBIT_1)==0 )
    {//инициализация приема
    OCR1A = FAULT_TIME_RC5;
    TCNT1 = 0;
    flag = FL_STBIT_1|FL_RC5_RESET;
    }
    else
    {
    if ( flag & FL_STBIT_1 )
    {// измерение периода
    period=capture;
    if (( period > RC5_T-TOLERANCE )&&( period < RC5_T+TOLERANCE ))
    {
    TCNT1=0;
    flag = FL_SAMPLE|FL_RC5_RESET|FL_FAULT;
    receive=counter_bit=0;
    sbi(TCCR1B,0x40);//ICESn =0, падающий фронт, ICESn = 1, нарастающий фронт.
    //TCCR1B|=0x40;
    }}}}
    }
    // ISR (TIMER1_COMPA_vect)
    // Timer 1 output compare A interrupt service routine
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
    //#asm("sei") // глобально разрешаем прерывания
    if ( flag & FL_RC5_RESET )
    {//
    if (flag & FL_FAULT )
    {
    error=1;
    }//
    flag = 0;
    cbi(TCCR1B,0x40);//ICESn =0, падающий фронт; ICESn = 1, нарастающий фронт.
    //TCCR1B&=~0x40;
    }
    }

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

    // USART initialization
    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART Receiver: Off
    // USART Transmitter: On
    // USART Mode: Asynchronous
    // USART Baud Rate: 9600
    UCSRA=0x00;
    UCSRB=0x08;
    UCSRC=0x86;
    UBRRH=0x00;
    UBRRL=0x06;

    TIMSK|=0x30;

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

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

    while(1)
    {
    //if (FL_FAULT==0x04) {PORTD.2=1;};

    //Rc5_SetRx(); // инициализируем таймер 1
    if (dataOK) // если получены данные с ПДУ
    {
    // printf("Tem:%u%u\r",TCCR1B); // вывод данных
    //printf("Tem:%u%u\r",TCCR1B); // вывод данных
    if (command==3); // если это кнопка 1
    {
    if (CheckBit(PIND, 2)) cbi(PORTD, 2); //если канал 1 включен, выключаем
    else sbi(PORTD, 2); // если канал 1 выключен, включаем
    //else sbi(PORTD, 0); // если канал 1 выключен, включаем
    }

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

  73. Всем привет.Вот наконец то я переделал под CodeVisionAVR 1.25.9
    кому интересно изучайте !
    ………………………………………………………………………….
    #include
    #include
    #include
    #define wer 200
    #define wera 500
    #define _BV(BIT_NUMBER) (1<<BIT_NUMBER)

    // RC5_T-расчитать самому должно соответствовать 1,778mSek
    #define RC5_T 1778
    #define FAULT_TIME_RC5 RC5_T*17
    #define TOLERANCE (RC5_T/10) // 10%

    #define FL_RC5_RESET _BV(0) // сброс приемника
    #define FL_STBIT_1 _BV(1) // первый стартовый бит
    #define FL_SAMPLE _BV(7) // резрешение выборки
    #define FL_FAULT _BV(2) // ошибка приема
    #define CheckBit(reg,bit) (reg&(1<<bit))
    #define sbi(reg,bit) reg |= (1<<bit)
    #define cbi(reg,bit) reg &= ~(1< period-TOLERANCE)&&(capture < period+TOLERANCE) )// середина бита (пропускаем значение capture меньше периода)
    {
    TCNT1=0;
    receive< RC5_T-TOLERANCE )&&( period < RC5_T+TOLERANCE ))
    {
    TCNT1=0;
    flag = FL_SAMPLE|FL_RC5_RESET|FL_FAULT;
    receive=counter_bit=0;
    TCCR1B |= _BV(6);//ICESn =0, падающий фронт, ICESn = 1, нарастающий фронт.
    }
    }
    }
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    interrupt [TIM1_COMPA] void timer1_compa_isr(void)
    {
    if ( flag & FL_RC5_RESET ){
    if ( flag & FL_FAULT ) error=1;
    flag = 0;
    TCCR1B &= ~_BV(6);//ICESn =0, падающий фронт; ICESn = 1, нарастающий фронт.
    }
    }
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    void main(void){
    unsigned char buffer[20], count=0, count_er=0;
    PORTD = 0b00000000; DDRD = 0b11111111; // тут светодиоды

    //TCCR1B|= _BV(CS10); //без предделителя
    //TCCR1B|= _BV(ICNC1); //Вкл. подавитель шума на входе захвата
    //TCCR1B&= ~_BV(ICES1); //Выбор детектируемого фронта на входе захвата
    //Если ICESn =0, то падающий фронт приводит к захвату, ICESn = 1, то нарастающий фронт.
    //TCCR1B= _BV(CS10)|_BV(ICNC1);
    TCCR1B =0x81;// _BV(CS10) | _BV(ICNC1);//
    //Регистр маски прерываний таймера-счетчика
    //_BV(TICIE1) Разрешение прерывания по захвату состояния таймера-счетчика 1;
    //_BV(OCIE1A);// Разрешение прерывания по совпадению
    //TIMSK|=_BV(TICIE1)|_BV(OCIE1A);
    TIMSK |=0x30;// _BV(TICIE1) | _BV(OCIE1A);
    OCR1A=RC5_T;
    //TCNT1=0;

    //UBRRL = 12;// Set baud rate 4800
    //UCSRB = 0x08;//|(1<<RXCIE)|(1<<RXEN);///* Enable transmitter */
    //UCSRC = 0x8A;/* Set frame format: 8data, 2stop bit */
    //UBRRL = 12;// Set baud rate 4800
    //UCSRB = 0x08;//|(1<<RXCIE)|(1<>6;
    delay_ms(wer); //задержка 100 мс
    command= (data&0b111111);
    delay_ms(wer); //задержка 100 мс
    printf(«%u%u\r»,command/10,command%10); delay_ms(100);
    }

    if (data_ok) // если получены данные с ПДУ
    {
    if (command==1)PORTD.2=1; //если канал 1 включен, выключаем // если это кнопка 1
    if (command==2)PORTD.3=1; //если канал 1 включен, выключаем // если это кнопка 1
    if (command==3)PORTD.4=1; //если канал 1 включен, выключаем // если это кнопка 1
    delay_ms(wera); //задержка 500 мс
    PORTD=0; //если канал 1 включен, выключаем
    data_ok=0;
    }}}
    ……………………………………………………………………………………………….

Оставьте комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *