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.
Boa tarde, vocês estão de parabéns ao disponibilizar conhecimento para todos .
ResponderExcluirEstou precisando transformar este deslocamento em medida ou seja atraves de um teclado entro com 500mm e o motor desloca 500
ResponderExcluirOlá, para isto basta ver quantos mm seu motor vai deslocar a cada passo dai vc calcula , o numero de passo por deslocamento desejado.
ExcluirBoa sorte!
show de bola, parabéns !!!!!!!!!!!
ResponderExcluirObrigado! isso serve de estimulo para que eu continue este trabalho.
ExcluirParabéns meus amigos, obrigado por compartilhar conhecimento!
ResponderExcluir