Управление двигателем постоянного тока на PIC18

Двигатель постоянного тока

Двигатель постоянного тока преобразует электрическую энергию в виде постоянного тока в механическую энергию. Производимая механическая энергия представляет собой вращательное движение вала двигателя. Рассмотрим управление двигателем с помощью микроконтроллера PIC.

Направление вращения вала двигателя можно изменить, поменяв полярность на его выводах (изменить направление тока через двигатель).

Если подать на двигатель фиксированное напряжение, на нем установится определенная скорость. Если изменять напряжение, то скорость двигателя так же будет изменяться.

Также скоростью двигателя постоянного тока можно управлять, применяя ШИМ-сигнал (последовательность импульсов с заданной скважностью).

Для реверсирования тока мы можем использовать схему Н-моста или микросхему драйвера двигателя. Такие драйверы используют схему Н-моста или любые другие механизмы.

Для получения дополнительной информации о двигателях постоянного тока и способах их использования, конфигурации схемы Н-моста, методе ШИМ смотрите статью «Двигатели постоянного тока».


Рассмотрим пример подключения и управления двигателем постоянного тока через драйвер двигателя L293D. Управление двигателем будем осуществлять микроконтроллером PIC18 (PIC18F4550). Схема подключения драйвера и самого двигателя к микроконтроллеру представлена ниже.

Управление двигателем.Схема подключения драйвера и DC двигателя к микроконтроллеру PIC18F4550
Рисунок 1. Схема подключения драйвера и DC двигателя к микроконтроллеру PIC18F4550

Пример работы двигателя постоянного тока

В этом примере мы собираемся соединить двигатель постоянного тока с микроконтроллером PIC18F4550. Микроконтроллер будет управлять скоростью двигателя постоянного тока с помощью переменного резистора. Резистор подключим к к АЦП. Так же с помощью переключателя будем менять направление движения вала двигателя.

Для управления движением двигателя в обоих направлениях мы будем использовать микросхему драйвера двигателя L293D.

Как показано на рисунке 1, мы подключили потенциометр 1 кОм к каналу 0 АЦП платы PIC18F4550 для изменения скорости двигателя постоянного тока.

Переключатель подключен к выводу INT0, который управляет направлением вращения двигателя.

PORTD используется как порт выходного сигнала управления. Он обеспечивает управление входными контактами двигателя через драйвер двигателя L293D, который вращает двигатель по часовой стрелке и против часовой стрелки, изменяя полярность их клемм.

Алгоритм по программированию

  • Включить АЦП и сопоставить его выход с диапазоном 0-255.
  • Включить глобальное внешнее прерывание INT0 с режимом срабатывания по нарастающему фронту.
  • Установить соответствующий режим ШИМ.
  • Корректировать рабочий цикл с помощью значения АЦП, который служит для управления скоростью.
  • Постоянно проверяйте прерывание по направлению и при изменении менять направление.
#include <math.h>
#include <stdio.h>
#include <pic18f4550.h>
#include "ADC_Header_File.h"
#include "Configuration_header_file.h"
#define MINTHR              8000
#define RESOLUTION          488
#define InternalOsc_8MHz    8000000
#define InternalOsc_4MHz    4000000
#define InternalOsc_2MHz    2000000
#define InternalOsc_1MHz    1000000
#define InternalOsc_500KHz  500000
#define InternalOsc_250KHz  250000
#define InternalOsc_125KHz  125000
#define InternalOsc_31KHz   31000
#define Timer2Prescale_1    1
#define Timer2Prescale_4    4
#define Timer2Prescale_16   16

void MSdelay(unsigned int val)
{
 unsigned int i,j;
 for (i=0; i<=val; i++)
     for (j=0; j<165; j++); /* Задержка  1ms для частоты 8MHz */
}

void PWM_Init()             /* Инициализация ШИМ*/
{
    TRISCbits.TRISC1 = 0;   /* установим CCP2 пин как выход ШИМ */
    CCP2CON = 0x0C;         /* Установим режим ШИМ */
}

int setPeriodTo(unsigned long FPWM)/* Установка периода */
{
    int clockSelectBits, TimerPrescaleBits;
    int TimerPrescaleValue;
    float period;
    unsigned long FOSC, _resolution = RESOLUTION;

    if (FPWM < MINTHR)    {TimerPrescaleBits = 2; TimerPrescaleValue = Timer2Prescale_16;}
    else                  {TimerPrescaleBits = 0; TimerPrescaleValue = Timer2Prescale_1;}

    if (FPWM > _resolution)               {clockSelectBits = 7; FOSC = InternalOsc_8MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 6; FOSC = InternalOsc_4MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 5; FOSC = InternalOsc_2MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 4; FOSC = InternalOsc_1MHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 3; FOSC = InternalOsc_500KHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 2; FOSC = InternalOsc_250KHz;}
    else if (FPWM > (_resolution >>= 1))  {clockSelectBits = 1; FOSC = InternalOsc_125KHz;}
    else                                  {clockSelectBits = 0; FOSC = InternalOsc_31KHz;}

    period = ((float)FOSC / (4.0 * (float)TimerPrescaleValue * (float)FPWM)) - 1.0;
    period = round(period);

    OSCCON = ((clockSelectBits & 0x07) << 4) | 0x02;
    PR2 = (int)period;
    T2CON = TimerPrescaleBits;
    TMR2 = 0;
    T2CONbits.TMR2ON = 1;  /* Включаем таймер 2 */
    return (int)period;
}

void SetDutyCycleTo(float Duty_cycle, int Period
{
    int PWM10BitValue;
    
    PWM10BitValue = 4.0 * ((float)Period + 1.0) * (Duty_cycle/100.0);
    CCPR2L = (PWM10BitValue >> 2);
    CCP2CON = ((PWM10BitValue & 0x03) << 4) | 0x0C;
}

void External_Interrupt_Init()
{
    TRISBbits.TRISB0=1;        /* Вывод  INT0 pin настроим на вход*/

    /* Также выключите PBADEN в файле конфигурации или
    очистить ADON в ADCON0, чтобы установить аналоговый вывод как цифровой
 */
  
    INTCON2 = 0x40;             /* Настроим прерывание по нарастающему фронту*/
    INTCONbits.INT0IF = 0;      /* Очистим  INT0IF флаг*/
    INTCONbits.INT0IE = 1;      /* включим  внешнее прерывание INT0*/
    INTCONbits.GIE = 1;         /* включаем глобальные прерывания*/
}
void interrupt ISR()
{   
    LATD0 = ~LATD0;             
    LATD1 = ~LATD1;
    MSdelay(300);
    INTCONbits.INT0IF=0;
}

void main(void)
{
    float Duty_Scale;
    int Period;
    
    TRISD = 0x00;               /* PORTD выход */
    LATD0 = 0;                  /* начальная инициализация */
    LATD1 = 1;
    ADC_Init();
    PWM_Init();                 /* Инициализация ШИМ */
    External_Interrupt_Init();
    Period = setPeriodTo(10000);/* Частота ШИМ 10кГц */
    /* Обратите внимание, что размер шага периода будет постепенно увеличиваться с частотой ШИМ.*/
    while(1)
    {
        Duty_Scale = (((float)(ADC_Read(0)/4.0))/2.55); 
        SetDutyCycleTo(Duty_Scale, Period);
    }
}
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest
0 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии