Машинка на ДУ управлении своими руками — передатчик и приёмник. 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 во вложении.


Прикрепленные файлы:

Добавить комментарий

Ваш адрес email не будет опубликован.