Машинка на ДУ управлении своими руками — Быстро-медленно (PIC)!

На очередном видеоуроке мы научимся регулировать скорость вращения нашего двигателя при помощи МК PIC.

Разберёмся чуть подробнее с нашей ручной газа. Рассмотрим реальное положение дел.

В крайнем левом положении, которое должно соответствовать мощности 0%, напряжение на бегунке переменного резистора не равно 0В. Допустим, около 0,1В. Значит, наш АЦП намеряет около 2-4ИЕ. Записав эти данные в регистр OCR2, мы видим с вами на осциллографе тонкие иголки.

Поворачивая переменный резистор, мы увеличиваем напряжение на бегунке переменного резистора и как следствие на входе АЦП. Измеренное значение записываем в регистр OCR2, тем самым увеличивая заполнение.

Достигнув крайнего правого положения, которое соответствует мощности 100%, напряжение на бегунке, в идеале, должно равняться 5В. На самом деле оно или немногим меньше, к примеру 4,91В или больше, к примеру 5,09.

В первом случае АЦП намеряет немногим меньше максимума, что-то около 251ИЕ. На осциллограмме мы видим длинный импульс и коротенькие паузы в виде иголок.

Во втором АЦП выдаст максимум 255ИЕ, несмотря на то, что напряжение в реальности больше. Загрузив это значение в регистр OCR2, на выходе получаем сплошной уровень +5В без переключений.

Настраивая периферию МК, я привык детально комментировать регистры, такой подход занимает много строк. Шапка программы разрастается. В предыдущем уроке инициализация периферии заняла 34 строки. В нашем уроке это уже 232 строки. Да и функций становится больше и больше. Лично мне трудно ориентироваться в таком длинном коде.

Спасение я нашёл в заголовочных файлах. Содержимое этих файлов автоматически добавляется препроцессором в исходный текст в том месте, где располагается директива include.

Файловая структура программы теперь выглядит следующим образом: основной код содержится в main.c, все строки инициализации периферии вынесены в файл initHard.c, в initHard.h размещены объявления функций содержащихся в initHard.c.

Итак разберём программу…

Ручку газа подключаем к АЦП – pin13, RC2/CPP1. Выход ШИМ последовательности наблюдаем на pin2, RA0/AN0.

Настроим соответствующие линии порта…

 TRISCbits.TRISC2 = 0; //Настраиваем RC2/CCP1 на вывод, ручка газа TRISAbits.TRISA0 = 1; //Настраиваем RA0/AN0 на ввод, АЦП 

Для того, чтобы запустить модуль CCP в режиме ШИМ, необходимо включить таймер 2. Настроим его…

В соответствии с даташитом выбираем частоту ШИМ последовательности 1,22кГц.

 //T2CKPS1:T2CKPS0: Timer2 Clock Prescale Select bits //00= Prescaler is 1 //01= Prescaler is 4 //1x= Prescaler is 16      T2CKPS0 = 0; T2CKPS1 = 1; 

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

 //TMR2ON: Timer2 On bit //1= Timer2 is on //0= Timer2 is off  TMR2ON = 1;

Запускаем модуль CCP1 в режиме ШИМ.

 //CCPxM3:CCPxM0: CCP1 Mode Select bits //… //11xx=PWM mode      CCP1M0 = 0;     CCP1M1 = 0;     CCP1M2 = 1;     CCP1M3 = 1; 

Загружаем в регистр периода таймера 2 значение, соответствующее частоте 1,22кГц.

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

Напоследок настроим АЦП. Выберем левое выравнивание результата.

 //ADFM: A/D Result Format Select bit //1= Right justified. 6 Most Significant bits of ADRESH are read as С0Т. //0= Left justified. 6 Least Significant bits of ADRESL are read as С0Т.     ADFM = 0; 

Выберем аналоговую линию.

 //PCFG3:PCFG0: A/D Port Configuration Control bits //Mode 1110: AN5-AN1 is digital, AN0 is analog     PCFG0 = 0;    PCFG1 = 1;    PCFG2 = 1;    PCFG3 = 1; 

Включим модуль АЦП.

 //ADON: A/D On bit //1= A/D converter module is operating //0= A/D converter module is shut-off  ADON = 1; 

Рассмотрим основной код. С заголовком вы уже знакомы.

 #define _XTAL_FREQ 20000000 //Указываем тактовую частоту процессора #include  //Содержит в себе макроопределения, в частности __CONFIG #include "pic16f876a.h" //Файл определения имён регистров, портов... #include "initHard.h" //Содержит в себе определение процедур инициализации периферии  __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & CP_OFF & BOREN_OFF & LVP_OFF & CPD_OFF & WRT_OFF); 

Теперь основная процедура main. Инициализируем периферию.

 //Инициализация периферии...     initPORTs();    //Инициализация портов     initTIMERs();   //Инициализация таймеров     initCCPs();     //Инициализация CCP-модулей     initADC();      //Инициализация АЦП 

Далее, в бесконечном цикле выполняем три действия: запускаем преобразование, ждём окончания цикла преобразования, загружаем значение скважности в CCP модуль

 //Бесконечный цикл     while(1)         {             GO_DONE = 1; //Запуск преобразования АЦП             __delay_us(100); //Пауза перед следующим измерением CCPR1L = ADRESH; //Загружаем значение скважности         } 

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