В данной статье мы рассмотрим подключение к микроконтроллеру PIC сервомотора (серводвигателя) с помощью программ MPLAB and XC8. Ранее на нашем сайте мы уже рассматривали серию обучающих статей по микроконтроллерам PIC – если вы начинающий в изучении микроконтроллеров PIC, то советуем их прочитать прежде чем приступать к изучению данной статьи.
В предыдущей статье на нашем сайте мы рассмотрели основы использования ШИМ в микроконтроллерах PIC – если вы ее успешно освоили, то поздравляем, вы практически готовы к подключению к микроконтроллеру PIC сервомотора.
Что такое сервомотор
Сервомотор (Servo Motor) – это тип исполнительного механизма, который допускает управление углом поворота. Существует много типов сервомоторов, некоторые из них представлены на следующем рисунке.
Любительские сервомоторы пользуются достаточно большой популярностью, поскольку они дешевы и позволяют производить управление движением. Особенной популярностью они пользуются в различных радиоуправляемых моделях. Они устраняют необходимость разработки системы управления для каждого приложения.
Большинство любительских сервомотора имеют угол поворота 0-180°, но вы можете найти в продаже и сервомоторы с углом поворота до 360° если вам это необходимо. Существует два типа сервомоторов: первый – с пластмассовой коробкой передач (Plastic Gear Servo Motor), второй – с металлической коробкой передач. Сервомоторы с металлической коробкой передач используются преимущественно в "жестких" условиях эксплуатации, но, как правило, они имеют более высокую цену.
Мощность серводвигателей измеряется в кг/см (килограмм на сантиметр), большинство любительских серводвигателей имеют мощность 3 кг/см, 6 кг/см или 12 кг/см. Данная характеристика (кг/см) свидетельствует о том, вес какой величины ваш сервомотор может поднять на определенное расстояние. Например, 6 кг/см говорит о том, что сервомотор может поднять 6 кг если этот груз находится на расстоянии 1 см от оси сервомотора. Чем дальше груз находится от оси сервомотора тем, соответственно, меньший вес может поднять сервомотор.
Подключение сервомоторов к микроконтроллерам
Подключение сервомоторов к микроконтроллерам
Подключение любительских сервомоторов к современным микроконтроллерам достаточно просто. Они имеют всего три провода, два из которых используются для подачи питания, а третий – для приема управляющих сигналов от микроконтроллера. В данном проекте мы будем использовать сервомотор с металлической коробкой передач MG995, который широко применяется в современных радиоуправляемых моделях. Его внешний вид показан на следующем рисунке.
Цвет проводов для вашего сервомотора может отличаться от приведенных на рисунке (см. даташит на конкретную модель серводвигателя).
Все сервомоторы работают от напряжения питания +5V, но необходимо обращать пристальное внимание на потребляемый сервомотором ток.
Ранее на нашем сайте мы рассматривали подключение сервомотора к следующим микроконтроллерам (платам):
- к микроконтроллеру AVR;
- к плате Arduino Uno;
- к плате Raspberry Pi;
- к плате Raspberry Pi Pico;
- к плате STM32F103C8 (Blue Pill).
Программирование работы с сервомотором на микроконтроллере PICF877A
Прежде чем приступать к программированию работы с сервомотором необходимо знать что управляющим сигналом для него является ШИМ сигнал и угол поворота оси сервомотора зависит от коэффициента заполнения ШИМ сигнала как показано на следующем рисунке.
Частота управляющего сигнала ШИМ для каждого сервомотора разная и ее необходимо уточнять в даташите на конкретную модель серводвигателя, однако для большинства используемых в настоящее время сервомоторов она равна 50 Гц.
Параметры ШИМ сигнала для сервомотора MG995 приведены на следующем рисунке.
То есть если частота ШИМ сигнала для этого сервомотора равна 50 Гц, то период данного сигнала равен 20ms. В нашей предыдущей статье про ШИМ в микроконтроллерах PIC мы использовали частоту ШИМ сигнала равную 5 кГц. Поэтому для управления сервомотором MG995 такой ШИМ сигнал не подойдет.
И здесь существует определенная проблема, которая заключается в том, что микроконтроллер PIC16F877A не может формировать ШИМ сигналы с такой низкой частотой как 50 Гц используя модуль CCP. В соответствии с даташитом на него минимальная частота ШИМ сигнала в данном случае равна 1,2 кГц. Поэтому модуль CCP нам в данном проекте ничем не поможет.
Поэтому в данном проекте для формирования ШИМ сигнала с частотой 50 Гц мы будем использовать таймер. Более подробно об использовании таймеров в микроконтроллерах PIC вы можете прочитать в данной статье.
Мы установим для нашего таймера частоту предделителя 32 и сделаем так чтобы он переполнялся каждую 1 мкс. В этом случае общее время on и off для нашего ШИМ сигнала составит величину 20ms – то, что нам необходимо.
1 2 3 4 5 |
OPTION_REG = 0b00000100; // Timer0 with external freq and 32 as prescaler TMR0=251; // Load the time value for 1us delayValue can be between 0-256 only TMR0IE=1; //Enable timer interrupt bit in PIE1 register GIE=1; //Enable Global Interrupt PEIE=1; //Enable the Peripheral Interrupt |
Таким образом, внутри нашей функции обработки прерывания от таймера мы будем подавать уровень high на контакт RB0 на определенное время time и подавать на него уровень low на оставшееся время периода (20ms – on_time). Значением этого времени time мы будем управлять с помощью потенциометра, сигнал с которого будет подавать на модуль АЦП микроконтроллера.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
oid interrupt timer_isr() { if(TMR0IF==1) // Timer has overflown { TMR0 = 252; /*Load the timer Value, (Note: Timervalue is 101 instaed of 100 as the TImer0 needs two instruction Cycles to start incrementing TMR0 */ TMR0IF=0; // Clear timer interrupt flag count++; } if (count >= on_time) { RB0=1; // complement the value for blinking the LEDs } if (count >= (on_time+(200-on_time))) { RB0=0; count=0; } } |
А внутри нашей функции loop мы просто будем считывать значение с потенциометра и в соответствии с ним обновлять значение переменной on_time, которая и будет задавать коэффициент заполнения формируемого нами ШИМ сигнала.
1 2 3 4 5 |
while(1) { pot_value = (ADC_Read(4))*0.039; on_time = (170-pot_value); } |
Таким образом мы сформируем ШИМ сигнал с периодом 20ms и переменным коэффициентом заполнения, задаваемым с помощью потенциометра. Полный код программы проекта вы можете посмотреть в конце статьи.
Схема проекта
Схема подключения сервомотора к микроконтроллеру PIC представлена на следующем рисунке.
Данная схема почти такая же как в статье про использование ШИМ в микроконтроллерах PIC, только в ней вместо светодиода подключен сервомотор.
Тестирование работы проекта
Перед сборкой проекта в реальном "железе" мы проверили работу схемы в симуляторе Proteus. Смоделированная в Proteus схема проекта приведена на рисунке ниже. С помощью нее мы проверили различные углы поворота сервомотора.
Как вы можете видеть на представленных рисунках угол поворота сервомотора изменяется в зависимости от положения ручки потенциометра.
При сборке проекта в реальном "железе" мы просто удалили плату со светодиодом из предыдущего проекта и вместо нее подключили сервомотор.
Внешний вид собранной конструкции проекта показан на следующем рисунке.
Более подробно тестирование работы проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#define _XTAL_FREQ 20000000 // CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #include <xc.h> //TIMER0 8-bit $$RegValue = 256-((Delay * Fosc)/(Prescalar*4))$$ char value = 0; int on_time ;//= 150; //On-Time for the PWM signal (время активного состояния ШИМ сигнала) int count; //count gets incremented for every timer overlap int pot_value; /*********ADC Functions*********/ void ADC_Init() { ADCON0 = 0x41; //включаем модуль АЦП и устанавливаем для него частоту ADCON1 = 0xC0; //All pins as Analog Input //With reference voltages VDD and VSS } unsigned int ADC_Read(unsigned char channel) { if(channel > 7) //если введен неправильный канал return 0; //возвращаем 0 ADCON0 &= 0xC5; //очищаем биты выбора канала АЦП ADCON0 |= channel<<3; //устанавливаем необходимый канал АЦП __delay_ms(2); //Acquisition time to charge hold capacitor GO_nDONE = 1; //запускаем процесс АЦП while(GO_nDONE); //ждем пока процесс АЦП не завершится return ((ADRESH<<8)+ADRESL); //возвращаем результат } //*************************************************// void interrupt timer_isr() { if(TMR0IF==1) // Timer has overflown (таймер переполнился) { TMR0 = 252; /*Load the timer Value, (Note: Timervalue is 101 instaed of 100 as the TImer0 needs two instruction Cycles to start incrementing TMR0 */ TMR0IF=0; // очищаем флаг прерываний таймера count++; } if (count >= on_time) { RB0=1; // complement the value for blinking the LEDs } if (count >= (on_time+(200-on_time))) { RB0=0; count=0; } } void main() { /***************I/O PORT Initialization*************/ TRISB = 0x00; //RB0 используется для управления сервомотором TRISA = 0xFF; //режим работы на ввод данных //*************************************************// ADC_Init(); // инициализируем модуль АЦП OPTION_REG = 0b00000100; // Timer0 с внешней частотой и коэффициентом 32 для предделителя TMR0=251; // Load the time value for 1us delayValue can be between 0-256 only TMR0IE=1; //разрешаем прерывания от таймера в регистре PIE1 GIE=1; //глобальное разрешение прерываний PEIE=1; //разрешение прерываний от периферийных устройств while(1) { pot_value = (ADC_Read(4))*0.039; on_time = (170-pot_value); } } |