terça-feira, 28 de maio de 2013

controlando motor de passo via serial com MBlab XC8

 Hoje vou demonstrar como controlar um motor de passo via serial,note que o motor usado tem
 4 passos logo 90° por enrolamento, os comando para o controle são:
letra "A" - faz motor girar no sentido anti horário. 
letra "H" - faz girar no sentido horário.
letra "P" - para o motor
 
e os comandos :
"E****" - faz girar no sentido anti horário **** graus ,por exemplo  E0090, faz girar 90°. 
"D****" - faz girar no sentido horário **** graus ,por exemplo  E0180, faz girar 180°.
"V****" - altera a velocidade do motor, quanto menor o valor mais rápido, Ex. V0100.
 
O código fonte: 
 
/*
 *                            controlando motor de passo no MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F648A
 * Autor: aguivone
 * Versão: 1
 * Data :  28 de maio de 2013
 */
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 4000000    // apesar de não usar cristal devo configurar pois esse define é usado para rotinas de tempo e da serial
#include <xc.h>

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
//#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

/////////////////////defines///////////////////////////////////////////////////////////////////////////////////////////////
#define A RA0     //enrolamento 1
#define B RA1     //enrolamento 2
#define C RA2     //enrolamento 3
#define D RA3     //enrolamento 4


////////////////////////////////////////////////variaveis globais///////////////////////////////////////////////////////////
char caracter,comando;
bit flag_interrupcao = 0;
int posi_atual=1;//se colocar zero ira travar
long velocidade =500;
char valor[4];
int conta_pos=0;
bit recebendo = 0;
int girando=0;
///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt RS232(void)//vetor de interrupção
 {
     caracter = RCREG;
     RCIF = 0;//  limpa flag de interrupção de recepção
     if((caracter == 'A')||(caracter == 'H')||(caracter=='P'))
     {
          comando = caracter;
          flag_interrupcao = 1; //indica interrupção
     }
     else
     {
         if((caracter == 'E')||(caracter == 'D')||(caracter=='V'))
         {
          comando = caracter;
          conta_pos=0;//prepara buffer
          recebendo = 1;
         }
         else
         {
            if((recebendo == 1)&&(conta_pos<4))
            {
                valor[conta_pos]=caracter;
                if(conta_pos == 3)
                {
                  recebendo = 0;//finaliza recepção
                  flag_interrupcao = 1; //indica interrupção
                }
                conta_pos++;
            }
            else
            {//houve algum erro ou caracter invalido
                recebendo = 0;//finaliza recepção
                flag_interrupcao = 0;
            }
         }

     }
 }

/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
void inicializa_RS232(long velocidade,int modo)
{////por padrão é usado o modo 8 bits e sem paridade, mas se necessario ajuste aqui a configuração desejada.
    //verifique datasheet para ver a porcentagem de erro e se a velocidade é possivel para o cristal utilizado.
    RCSTA = 0X90;//habilita porta serial,recepção de 8 bit em modo continuo,assincrono.
    int valor;
        if(modo == 1)
        {//modo = 1 ,modo alta velocidade
         TXSTA = 0X24;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-16)/16);//calculo do valor do gerador de baud rate
        }
        else
        {//modo = 0 ,modo baixa velocidade
         TXSTA = 0X20;//modo assincrono,trasmissao 8 bits.
         valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);//calculo do valor do gerador de baud rate
        }
    SPBRG = valor;
    RCIE = 1;//habilita interrupção de recepção
    TXIE = 0;//deixa interrupção de transmissão desligado(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void escreve(char valor)
{
    TXIF = 0;//limpa flag que sinaliza envio completo.
    TXREG = valor;
    while(TXIF ==0);//espera enviar caracter
}
void imprime(const char frase[])
{
     char indice = 0;
     char tamanho = strlen(frase);
      while(indice < tamanho ) ///veja que o programa pode travar se aqui não tiver as duas aspas
       {
           escreve(frase[indice]);
           indice++;
       }
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////
/*
 *  if(flag_interrupcao ==  1)
        {//tem dados para ler
         imprime(" \n\r caracter digitado :");
         escreve(caracter);
         flag_interrupcao = 0;
        }

 */
//aprox 1 ms para clok interno

void delay_ms(long mili) {
    while (mili > 0) {
        _delay(1000); //aprox. 1ms com clock de 1mhz(oscilador interno)
        mili--;
    }
    // no caso do 18F o valor fica bem acima então é melhor montar essa funcão para que trabalhe bem
   //////////
}

//////////////rotinas do motor de passo//////////////////////////////////////////////////////////////////////
void desliga_motor(void)
{
             A=0;B=0;C=0;D=0; //desliga todos os enrolamentos
}

void graus_horario(long valor)
{
    valor = valor/90;//assim acha numero de pulsos necessarios
    while((valor>0)&&(comando != 'P'))//isso faz ele parar se receber o comando 'P'
    {
        posi_atual++;
        if(posi_atual > 4)
        {
          posi_atual = 1;
        }
         switch(posi_atual)
        {
            case 1:
            {
             A=0;B=0;C=0;D=1; //desliga todos os enrolamentos
            }break;
            case 2:
            {
             A=0;B=0;C=1;D=0; //desliga todos os enrolamentos
            }break;
            case 3:
            {
             A=0;B=1;C=0;D=0; //desliga todos os enrolamentos
            }break;
            case 4:
            {
             A=1;B=0;C=0;D=0; //desliga todos os enrolamentos
            }break;
        }
        delay_ms(velocidade);
        valor--;

    }
}
void graus_antihorario(long valor)
{
    valor = valor/90;//assim acha numero de pulsos necessarios
    while((valor>0)&&(comando != 'P'))//isso faz ele parar se receber o comando 'P'
    {
        posi_atual--;
        if(posi_atual == 0)
        {
          posi_atual = 4;
        }
        switch(posi_atual)
        {
            case 1:
            {
             A=0;B=0;C=0;D=1; //desliga todos os enrolamentos
            }break;
            case 2:
            {
             A=0;B=0;C=1;D=0; //desliga todos os enrolamentos
            }break;
            case 3:
            {
             A=0;B=1;C=0;D=0; //desliga todos os enrolamentos
            }break;
            case 4:
            {
             A=1;B=0;C=0;D=0; //desliga todos os enrolamentos
            }break;
        }
        delay_ms(velocidade);
        valor--;
    }
}
void girar_horario(void)
{
      graus_horario(360);
}
void girar_antihorario(void)
{

      graus_antihorario(360);
}
long char_to_long(void)
{
    long retorno=0;
    long valor3 = valor[3]-'0';//faz virar um long
    long valor2 = valor[2]-'0';//faz virar um long
    long valor1 = valor[1]-'0';//faz virar um long
    long valor0 = valor[0]-'0';//faz virar um long
    retorno = valor3+(valor2*10)+(valor1*100)+(valor0*1000);
    return(retorno);
}
///////////////////////////////////////////////////////////////////////////////
void main(void)
{
    TRISB = 0X02;//configura portB  B1 (pino RX) como entrada
    TRISA = 0X00;//configura portA como saida
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    inicializa_RS232(9600,1);//modo de alta velocidade
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //habilita interrupção global 
    CMCON = 7;//desliga modulo comparador
    imprime("Controlador de motor de passo \n\r");
    desliga_motor();
    for(;;)
    {
        if(flag_interrupcao == 1)//tem dados na serial
        {
            switch(comando)
            {
                case 'A':
                {
                  girando = 1;
                }break;
                case 'H':
                {
                  girando = 2;
                }break;
                case 'P':
                {
                  girando = 0;
                }break;
                case 'V':
                {
                    velocidade = char_to_long();
                }break;
                case 'E':
                {
                    graus_antihorario(char_to_long());
                    girando = 0;
                }break;
                case 'D':
                {
                    graus_horario(char_to_long());
                    girando = 0;   
                }break;
            }
         comando = ' ' ;//zera comando
         flag_interrupcao = 0;//limpa flag
        }
        if(girando == 0)
        {
           desliga_motor();
        }
        else
        {
            if(girando == 1)
            {
             girar_antihorario();
            }
            else
            {
              girar_horario();
            }
        }
    }//loop infinito

}
 
A simulação: 
 
para a simulação use o motor-stepper. 
 
 

6 comentários :

  1. Boa tarde, vocês estão de parabéns ao disponibilizar conhecimento para todos .

    ResponderExcluir
  2. Estou precisando transformar este deslocamento em medida ou seja atraves de um teclado entro com 500mm e o motor desloca 500

    ResponderExcluir
    Respostas
    1. Olá, para isto basta ver quantos mm seu motor vai deslocar a cada passo dai vc calcula , o numero de passo por deslocamento desejado.
      Boa sorte!

      Excluir
  3. show de bola, parabéns !!!!!!!!!!!

    ResponderExcluir
    Respostas
    1. Obrigado! isso serve de estimulo para que eu continue este trabalho.

      Excluir
  4. Parabéns meus amigos, obrigado por compartilhar conhecimento!

    ResponderExcluir

olá,digite aqui seu comentário!