Машинка на ДУ управлении своими руками — передатчик и приёмник. PIC

На этом уроке мы портируем программную реализацию интерфейса передатчика и приёмника с формированием импульсов переменной длительности на микроконтроллер PIC.

Начнём с передатчика. Инициализируем периферию, настраиваем порты…

 TRISAbits.TRISA0 = 1; //Вход ручки газа TRISAbits.TRISA2 = 0; //Выход интерфейса  TRISBbits.TRISB1 = 1; //Вход кнопки заднего хода TRISBbits.TRISB2 = 1; //Вход кнопки поворот вправо TRISBbits.TRISB4 = 1; //Вход кнопки поворот влево

Настройка таймера 0 не требуется. Модули CCP не используем. Включаем АЦП…

 ADON = 1;

Конфигурируем порт А следующим образом: линия AN0 — аналоговый вход, линии AN1 — AN5 цифровые, двунаправленные линии порта ввода вывода.

 PCFG0 = 0; PCFG1 = 1; PCFG2 = 1; PCFG3 = 1;

Настроим прерывания: разрешаем прерывания периферийных модулей…

 PEIE = 1;

Включаем прерывания таймера 0…

 T0IE = 1;

Разрешаем все прерывания…

 GIE = 1;

В основном цикле запускаем измерение АЦП и опрашиваем клавиши пульта…

  while(1) //Основной цикл { GO_DONE = 1; //Начать измерение __delay_us(100); //Ждём окончание измерения  //Направление движения if (PORTBbits.RB1 == 0) direction_of_motion = 255; else direction_of_motion = 127;  //Направление поворота if (PORTBbits.RB2 == 0) direction_of_rotation = 3; //Влево if (PORTBbits.RB4 == 0) direction_of_rotation = 255; //Вправо if (PORTBbits.RB2 == 1 && PORTBbits.RB4 == 1) direction_of_rotation = 127; //Прямо }

Теперь про обработчик прерывания. У нашего МК один вектор прерывания! Поэтому внутри обработчика необходимо опрашивать флаги прерываний, чтобы выяснить что именно вызвало прерывание. Нам проще, т.к. прерывание у нас одно, поэтому проверять флаг T0IF нам нет смысла. Содержание обработчика прерывания идентично варианту для AVR, код говорит сам за себя…

 interrupt void entry_point() //Точка входа в прерывание { OPTION_REGbits.T0CS = 1; //Выключить таймер  //Первый импульс, мощьность двигателя if (counter_cycles == 400) PORTAbits.RA2 = 1; //Формируем фронт if (counter_cycles == (400 + ADRESH)) PORTAbits.RA2 = 0; //Формируем срез  //Второй импульс, направление движения if (counter_cycles == 705) PORTAbits.RA2 = 1; //Формируем фронт if (counter_cycles == (705 + direction_of_motion)) PORTAbits.RA2 = 0; //Формируем срез  //Третий импульс, направления поворота if (counter_cycles == 1010) PORTAbits.RA2 = 1; //Формируем фронт if (counter_cycles == (1010 + direction_of_rotation)) PORTAbits.RA2 = 0; //Формируем срез  counter_cycles++; //Инкремент счётчика отсчётов  if (counter_cycles > 1265) counter_cycles = 0; //Проверяем признак окончания кадра  TMR0 = 0; //"Калибровочная константа" OPTION_REGbits.T0CS = 0; //Включить таймер INTCONbits.T0IF = 0; //Сбросить флаг прерывания }

Теперь разберёмся с приёмником. Инициализируем периферию, настраиваем порты…

 TRISAbits.TRISA2 = 1; //Вход интерфейса  TRISBbits.TRISB1 = 0; //Выход кнопки заднего хода TRISBbits.TRISB2 = 0; //Выход кнопки поворот вправо TRISBbits.TRISB4 = 0; //Выход кнопки поворот влево  TRISCbits.TRISC2 = 0; //Выход PWM

Настраиваем таймер 1, выберем предделитель на 4…

 T1CKPS0 = 0; T1CKPS1 = 1;

Настраиваем таймер 2 для работы с CCP модулем. Выберем предделитель на 16…

 T2CKPS0 = 0; T2CKPS1 = 1;

Включаем таймер…

 TMR2ON = 1;

Настроим модуль CCP. Выберем частоту ШИМ в 1,22кГц, для этого запишем в регистр уставку…

 PR2 = 255;    //Установка периода 1,22кГц

Включаем CCP модуль в режиме ШИМ…

 CCP1M0 = 0; CCP1M1 = 0; CCP1M2 = 1; CCP1M3 = 1;

Несмотря не то, что АЦП не используется конфигурируем порт А следующим образом: линии AN0 — AN5 цифровые, двунаправленные линии порта ввода вывода…

 PCFG0 = 0; PCFG1 = 1; PCFG2 = 1; PCFG3 = 0;

Рассмотрим программу. В основном цикле декодируем стартовую паузу…

 //Начало декодирования посылки while(PORTAbits.RA2); //Ждём логического ноля  TMR1 = 0; //Сбросить счётчик отсчётов  TMR1ON = 1; //Включить таймер while(!PORTAbits.RA2); //Считаем, пока принимаем логический ноль TMR1ON = 0; //Выключить таймер

Проверяем длительность…

 if (TMR1 < 38000) continue; //Если пауза не выдержана...

…если длительность соответствует, декодируем первый импульс…

 //Декодирование первого импульса TMR1 = 0; //Сбросить счётчик отсчётов  TMR1ON = 1; //Включить таймер while(PORTAbits.RA2); //Считаем, пока принимаем логическую единицу TMR1ON = 0; //Выключить таймер

Загружаем измеренное значение скважности, предварительно масштабировав его…

 CCPR1L = TMR1/96; //Загружаем значение скважности

Аналогично декодируем второй импульс. Основываясь на измеренной длительности определяем направление движения…

 if (TMR1 > 18000) PORTBbits.RB1 = 1; else PORTBbits.RB1 = 0;

Аналогично декодируем третий импульс. Основываясь на измеренной длительности определяем направление поворота…

 if (TMR1 < 1000) PORTBbits.RB2 = 1; else PORTBbits.RB2 = 0; if (TMR1 > 18000) PORTBbits.RB4 = 1; else PORTBbits.RB4 = 0; 

На сегодня всё! До новых встреч!

ПРОЕКТ С ИСХОДНЫМ КОДОМ И СИМУЛЯЦИЯ В PROTEUS во вложении.