На этом уроке мы портируем программную реализацию интерфейса передатчика и приёмника с формированием импульсов переменной длительности на микроконтроллер 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 во вложении.
Прикрепленные файлы:
- atmel.rar (146 Кб)
- microchip.rar (328 Кб)