Olá,
Vamos trabalhar com medição de tensão e corrente usando o ATmega328P, como ele possui um sensor de temperatura interno a gente já mata dois coelhos com um tiro só.
A primeira coisa que se deve fazer é configurar o hardware pra isso, é preciso estar atento a entrada Aref(referência analógica), para não ter problemas na configuração faça assim: coloque o pino Avcc ligado ao +5V,o pino Aref ligado um capacitor de 100nf que estará com o outro teminal ligado ao terra(dessa forma ele funciona como um filtro, o que reduz e muito ruídos),nunca ligue este pino ao GND pois pode inutilizar este chip para a função de leitura de tensão. Para este exemplo vou usar um cristal de 16Mhz e um circuito com o max232 para enviar os dados a um PC.
Para fazer a leitura de tensão de 0 a 55V usei um divisor resistivo igual o da figura abaixo:
Ou seja a razão de saída é 11:1(se entra 55V sai 5V na saída), no código deixei uma linha comentada para o caso de alguém querer usar para medir de 0 a 5V.Na simulação do proteus não deu certo colocar o divisor resistivo então optei por usar 2 potenciômetro para conseguir um resultado aproximado.Outro detalhe é que na simulação o sensor interno não é simulador então lá ele assume valor 0 o que acaba resultado em -65°C.
A equação para medir a temperatura foi retirada deste site http://www.embarcados.com.br/arduino-uno-sensor-de-temperatura/ .
O código fonte:
//***********************************************************************************************************// Usando o conversor analógico/digital//// no gravador configurar os fuses assim:// EXTENDED 0XFF // HIGH 0XD8 - neste modo funciona com qualquer valor de cristal usei um de 16Mhz // LOW 0XC7// LOKBITS 0XFF - sem proteção////// versão : 1.1// descrição : Voltimetro e leitor de temperatura// Autor : Aguivone// microcontrolador : ATmega328P// compilador : AVR-GCC / Atmel AVR Studio 6.1// Data do projeto : 07/08/2014 // Data de atualização : 07/08/2015 - adicionado leitura de temperatura e melhoria para ler tensão//*************************************************************************************************************
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>// AVRJazz Mega328 SPI I/O////////////////////////funçoes auxiliares/////////////////////////////#define alterna_pino(x,y) x ^= _BV(y)
#define LED PD2
#define TENSAO PC2
char caracter;
void RS232_inicializa(unsigned int BAUD)
{
unsigned int velocidade = F_CPU/16/BAUD-1;
//veja que na simulação do proteus dá erros nas velocidade diferentes de 9600 mas na pratica funciona.
UCSR0A = 0X20;
/* habilita receiver and transmitter buffers */
UBRR0H = (unsigned char)(velocidade>>8);
UBRR0L = (unsigned char)velocidade;
UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador/* 8 bits , 1 stop bit, assincrono , sem paridade,modo nornal */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void escreve_caracter(unsigned char carac)
{
_delay_loop_1(1);//tempo para estabilizar tensão
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
UDR0 = carac;
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
_delay_loop_1(2);//tempo para garantir o envio
}
void impri_serial(constchar frase[80])
{
unsigned int indice=0;
unsigned int tamanho = strlen(frase);
while(indice<=tamanho)///veja que o programa pode travar se aqui não tiver as duas aspas
{
escreve_caracter(frase[indice]);
indice++;
}
}
//////////////////////////interrupções requerida para usar a recepção serial///////////////////////////////////
ISR(USART_RX_vect)
{
caracter = (char)UDR0;
escreve_caracter(caracter);
}
///long para charvoid long_to_char(unsigned int quant, int inicio)
{
char texto[6];
texto[1] = '0';
texto[2] = '0';
texto[3] = ',';
texto[4] = '0';
texto[5] = '0';
if(quant>9999)//valor maior que 100V
{
texto[1] = 'F';
texto[2] = 'A';
texto[3] = 'L';
texto[4] = 'H';
texto[5] = 'A';
}
else
{
while(quant>=1000)
{
quant=quant-1000;
texto[1]++;
}
while(quant>=100)
{
quant=quant-100;
texto[2]++;
}
while(quant>=10)
{
quant=quant-10;
texto[4]++;
}
while(quant>=1)
{
quant=quant-1;
texto[5]++;
}
}
int cont = inicio;
while(cont<=5)
{
escreve_caracter(texto[cont]);
cont++;
}
}
////////////rotina de leitura de tensão /////////////////////////////////void ler_adc() {
ADCSRA |= _BV(ADSC);//inicia conversão analogico/digital
while ( (ADCSRA & _BV(ADSC)) );//espera terminar leiturafloat valor = ADC;
//valor = ((ADC*50)/102);//mede de 0 a 5V
valor = ((ADC*50)/102)*11;//mede de 0 a 55V - colocando um resitor de 10K e outro de 1K(entre o pino de entrada e gnd)
long_to_char(valor,1);
return;
}
void ler_temperatura() {
ADCSRA |= _BV(ADSC);//inicia conversão analogico/digital
while ( (ADCSRA & _BV(ADSC)) );//espera terminar leiturafloat valor = ADC;
// a formula é temperatura = (ADC - 324,31)/1,22 , mas vou arrendondar para 324if(valor < 324)
{
//temperatura negativa
valor = (324.31-valor)/1.22;;
escreve_caracter('-');
}
else
{ //temperatura positiva
valor = (valor-324.31)/1.22;;
escreve_caracter('+');
}
long_to_char(valor,4);
return;
}
void inicializa_adc(int valor)
{
if(valor == 0)///Modo ler tensão
{
ADMUX = 0X42;// vai usar o pino PC2 como entrada, justificado a direita e com capacitor externo no pino de referencia(estabiliza leitura)
ADCSRA = 0XA7;//habilita o conversor adc clock dividido por 128(para 16MHZ - pois o range deve ser de 50-200khz) e trigger
ADCSRB = 0X41;//habilita o comparador e o trigger usará a saida dele
DIDR0 = 0XFB;////desabilita entrada analógica(reduz consumo), deixa apenas PC2 como analógica
}
if(valor == 1)///Modo ler temperatura
{
//deve ser alterado somente esses dois registradores pois
ADMUX = 0XC8;// sensor de temperatura, justificado a direita e capacitor externo no pino de referencia//ADCSRA = 0XA7;//habilita o trigger e o conversor adc clock dividido por 128(para 16MHZ - pois o range deve ser de 50-200khz)
ADCSRB = 0X41;//habilita o comparador e o trigger usará a saida dele//DIDR0 = 0XFF;////desabilita entrada analógica(reduz consumo)
}
}
////////////////////função principal/////////////////////////////////////int main(void)
{
//////////////////inicializa port D /////////////////////////////////////////////////////////////////////
DDRD = 0XFE; //inicializa portD,4 a 7 entrada
DDRC = 0x18;//configura port C como entradas exceto C3 e C4
PORTD = 0x00;//desabilita pull ups
DDRB = 0x2F;//configura port B
PORTB = 0x02;//inicia com o pino de reset e desliga wiznet em nivel alto
RS232_inicializa(9600);
inicializa_adc(0);
sei();//habilita interrupções
impri_serial("Lendo tensão e temperatura ... \n\r");
///////////////////////////////////////////////////////for(;;)
{
impri_serial("Tensão = ");
ler_adc();
inicializa_adc(1);//ler temp
_delay_ms(50);//estabilizar tensão
impri_serial(" Temp = ");
ler_temperatura();
impri_serial(". \n\r ");
inicializa_adc(0);//volta a ler tensão //não sei por que em alguns terminais seriais o valor não é impresso,//mas na simulação e em um aplicativo que fiz mostra normalmente
_delay_ms(500);
alterna_pino(PORTD,LED);//led
}//chave do laço infinito (for)
}//chave de main
Olá, hoje vou postar este exemplo de como usar o conversor analógico digital do ATmega328P.
O código fonte:
//***********************************************************************************************************// Usando o conversor analogico/digital//// no gravador configurar os fuses assim:// EXTENDED 0XFF // HIGH 0XD8 - neste modo funciona com qualquer valor de cristal usei um de 16Mhz // LOW 0XC7// LOKBITS 0XFF - sem proteção////// versão : 1// descrição : Voltimetro// Autor : Aguivone// microcontrolador : ATmega328P// compilador : AVR-GCC / Atmel AVR Studio 6.1// Data do projeto : 07/08/2014 //*************************************************************************************************************
#include <avr/io.h>
#include <string.h>
#include <stdio.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>// AVRJazz Mega328 SPI I/O////////////////////////funçoes auxiliares/////////////////////////////#define alterna_pino(x,y) x ^= _BV(y)
#define LED PD2
#define TENSAO PC2
char caracter;
void RS232_inicializa(unsigned int BAUD)
{
unsigned int velocidade = F_CPU/16/BAUD-1;
//veja que na simulação do proteus dá erros nas velocidade diferentes de 9600 mas na pratica funciona.
UCSR0A = 0X20;
/* habilita receiver and transmitter buffers */
UBRR0H = (unsigned char)(velocidade>>8);
UBRR0L = (unsigned char)velocidade;
UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador/* 8 bits , 1 stop bit, assincrono , sem paridade,modo nornal */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void escreve_caracter(unsigned char carac)
{
_delay_loop_1(1);//tempo para estabilizar tensão
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
UDR0 = carac;
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
_delay_loop_1(1);//tempo para garantir o envio
}
void impri_serial(constchar frase[80])
{
unsigned int indice=0;
unsigned int tamanho = strlen(frase);
while(indice<=tamanho)///veja que o programa pode travar se aqui não tiver as duas aspas
{
escreve_caracter(frase[indice]);
indice++;
}
}
//////////////////////////interrupções requerida para usar a recepção serial///////////////////////////////////
ISR(USART_RX_vect)
{
caracter = (char)UDR0;
escreve_caracter(caracter);
}
///long para charvoid long_to_char(unsigned int quant)
{
char texto[6];
texto[1] = '0';
texto[2] = '0';
texto[3] = ',';
texto[4] = '0';
texto[5] = '0';
if(quant>9999)//||(quant<10))
{
texto[1] = 'F';
texto[2] = 'A';
texto[3] = 'L';
texto[4] = 'H';
texto[5] = 'A';
}
else
{
while(quant>=1000)
{
quant=quant-1000;
texto[1]++;
}
while(quant>=100)
{
quant=quant-100;
texto[2]++;
}
while(quant>=10)
{
quant=quant-10;
texto[4]++;
}
while(quant>=1)
{
quant=quant-1;
texto[5]++;
}
}
escreve_caracter(texto[1]);
escreve_caracter(texto[2]);
escreve_caracter(texto[3]);
escreve_caracter(texto[4]);
escreve_caracter(texto[5]);
}
////////////rotina de leitura de tensão /////////////////////////////////void ler_adc() {
ADCSRA |= _BV(ADSC);//inicia conversão analogico/digital
while ( (ADCSRA & _BV(ADSC)) );//espera terminar leiturafloat valor = ADC*5/10.23;
long_to_char(valor);
return;
}
void inicializa_adc()
{
ADMUX = 0X02;// vai usar o pino PC2 como entrada, justificado a direita// ADMUX = 0X08;// sensor de temperatura, justificado a direita
ADCSRA = 0XA0;//habilita o conversor adc clock dividido por 2 e trigger
ADCSRB = 0X41;//habilita o comparador e o trigger usará a saida dele
DIDR0 = 0XFB;////desabilita entrada analogico(reduz consumo), deixa apenas PC2 como analogico
}
////////////////////função principal/////////////////////////////////////int main(void)
{
//////////////////inicializa port D /////////////////////////////////////////////////////////////////////
DDRD = 0XFE; //inicializa portD,4 a 7 entrada
DDRC = 0x18;//configura port C como entradas exceto C3 e C4
PORTD = 0x00;//desabilita pull ups
DDRB = 0x2F;//configura port B
PORTB = 0x02;//inicia com o pino de reset e desliga wiznet em nivel alto
RS232_inicializa(9600);
inicializa_adc();
sei();//habilita interrupções
impri_serial("Voltimetro serial ... \n\r");
///////////////////////////////////////////////////////for(;;)
{
impri_serial("->");
ler_adc();
impri_serial(".\n\r");
_delay_ms(1000);
alterna_pino(PORTD,LED);//led
}//chave do laço infinito (for)
}//chave de main
A simulação do proteus, veja no detalhe o valor lido na serial e no multímetro do programa:
Comprei um DVR da marca Intelbras para gravar umas imagem e monitorar remotamente minha residencia dai tive a ideia de fazer uma placa que se conecte a este DVR e então acionar dispositivos ligados a rele desta placa de modo remoto.Para isto usei a saída RS-485 que controla a "Pan tilt"(aquelas câmeras que é possível movimentar sua posição).
A primeira coisa a fazer é saber qual é o protocolo utilizado! Então ao ver os tipos de comunicação utilizado achei muito material sobre o protocolo PELCO-D, uma vez com este protocolo montei o programa que será disponibilizado logo abaixo,no link para download que tem um manual e um software desenvolvido para configurar a placa depois de pronta: https://drive.google.com/file/d/0Bx9JeN0dmzXxb1FPUm12MGxLQmc/edit?usp=sharing .
Coloquei também os arquivos gerber e um esquemático da placa além de ter um arquivo que foi feito no Kicad 2012 para gerar a placa, nesta pasta tem muita informação sobre o projeto.Para controlar os reles basta selecionar qual será a câmera configurada para utilizar a pan tilt e então pra cada comando da câmera irá acionar um rele(isso vai depender da configuração feita pelo software do projeto ),não testei em outros DVR´s que não seja o Intelbras.
Finalmente vou disponibilizar aqui o código completo do projeto, ficou gigante:
//***********************************************************************************************************// acesso remoto com dvr// versão : 1.0// descrição : acesso remoto usando protocolo pelco D// Autor : Aguivone// micropcontrolador : ATmega 328P// compilador : AVR-GCC / AtmelStudio 6.1// Data do projeto : 10/12/2013// finalizado : 20/12/2013// EFUSE = 0XFF | LOCK BIT = 0XFF(sem cod. proteção) | FUSE HBIT = 0XDE | FUSE LBIT = 0XCF//*************************************************************************************************************#define F_CPU 16000000 // 16 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
#include <avr/eeprom.h> ///para usar a eeprom#define ALTERNA_PINO(x,y) x ^= _BV(y)
#define LIGA_PINO(x,y) x |= _BV(y)
#define DESLIGA_PINO(x,y) x &= ~(_BV(y))
#define LED PD3
#define CONTROL_RS485 PD2
#define RELE1 PB1
#define RELE2 PB2
#define RELE3 PB3
#define RELE4 PB4
#define RELE5 PB5
#define RELE6 PC0
#define RELE7 PC1
char gcRs232_caracter;
long glTeste;
int gbRs232_pacote_recebido = 0;
int giRs232_pos=0;
//variaveis dos releschar gcRele[7][6];//onde: byte 0=comando1_ligar,1=comando2_ligar,2=comando1_desligar,3=comando2_desligar,4=tempo,5='P' ou 'E'(pulso ou estado).char gcEnd_placa = 0x01;//endereço da placachar gcTemp_pulso[7];//tempo de pulsochar gcRs232_buffer[20];//o tamanho do buffer é 20 caractereschar gcChecksum = 0;
char v1,v2; //variaveis de retornochar convert_char[2];//variavels de retorno do tempoint tempo_pisca=0;
int teste=0;
///////////////////////////////////////////////funçoes usadas pela usart////////////////////////////////////////////////void RS485_inicializa(unsigned int BAUD)
{
unsigned int velocidade = F_CPU/16/BAUD-1;
//veja que na simulação do proteus dá erros nas velocidade diferentes de 9600 mas na pratica funciona.
UCSR0A = 0X20;
/* habilita receiver and transmitter buffers */
UBRR0H = (unsigned char)(velocidade>>8);
UBRR0L = (unsigned char)velocidade;
UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador/* 8 bits , 1 stop bit, assincrono , sem paridade,modo nornal */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
DESLIGA_PINO(PORTD,CONTROL_RS485);
}
void escreve(unsigned char carac)
{
LIGA_PINO(PORTD,CONTROL_RS485);//pino de controle da RS-485
_delay_loop_1(1);//tempo para estabilizar tensão
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
UDR0 = carac;
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
_delay_loop_1(20);//tempo para garantir o envio
DESLIGA_PINO(PORTD,CONTROL_RS485);//pino de controle da RS-485
}
void imprime(constchar frase[20],int taman)
{
unsigned int indice=0;
while(indice<=taman)///veja que o programa pode travar se aqui não tiver as duas aspas
{
escreve(frase[indice]);
indice++;
}
}
////////////////controla os reles//////////////void muda_rele(int rel,int estado)
{
switch(rel)
{
case 0:
{
if(estado == 1)
{
LIGA_PINO(PORTB,RELE1);
}
else
{
DESLIGA_PINO(PORTB,RELE1);
}
}break;
case 1:
{
if(estado == 1)
{
LIGA_PINO(PORTB,RELE2);
}
else
{
DESLIGA_PINO(PORTB,RELE2);
}
}break;
case 2:
{
if(estado == 1)
{
LIGA_PINO(PORTB,RELE3);
}
else
{
DESLIGA_PINO(PORTB,RELE3);
}
}break;
case 3:
{
if(estado == 1)
{
LIGA_PINO(PORTB,RELE4);
}
else
{
DESLIGA_PINO(PORTB,RELE4);
}
}break;
case 4:
{
if(estado == 1)
{
LIGA_PINO(PORTB,RELE5);
}
else
{
DESLIGA_PINO(PORTB,RELE5);
}
}break;
case 5:
{
if(estado == 1)
{
LIGA_PINO(PORTC,RELE6);
}
else
{
DESLIGA_PINO(PORTC,RELE6);
}
}break;
case 6:
{
if(estado == 1)
{
LIGA_PINO(PORTC,RELE7);
}
else
{
DESLIGA_PINO(PORTC,RELE7);
}
}break;
}
}
void rotina_rs485()
{
char conta=0;
while(conta < 7)
{
if(gcRele[conta][5]=='P')//esse rele é por pulso?
{
if((gcRele[conta][0] == gcRs232_buffer[2])&&(gcRele[conta][1] == gcRs232_buffer[3]))
{//verifica se o comando é pra dar pulso
muda_rele(conta,1);//liga o rele
gcTemp_pulso[conta] = gcRele[conta][4];
conta = 20;//com isso sai do laço imediatamente
}
}
else
{
if((gcRele[conta][0] == gcRs232_buffer[2])&&(gcRele[conta][1] == gcRs232_buffer[3]))
{//verifica se o comando é pra ligar?
muda_rele(conta,1);
conta = 20;//com isso sai do laço imediatamente//escreve('L');
}
else{
if((gcRele[conta][2] == gcRs232_buffer[2])&&(gcRele[conta][3] == gcRs232_buffer[3]))
{//verifica se o comando é pra desligar?
muda_rele(conta,0);
conta = 20;//com isso sai do laço imediatamente//escreve('D');
}
}
}
conta++;
}
}
void limpa_buffer()
{
int conta = 0;
while(conta<20)
{
gcRs232_buffer[conta]=0;
conta++;
}
giRs232_pos=0;
}
long char_to_long(char val1,char val2,char val3,char val4)
{
long retorno=0;
long gcValor3 = val4 -'0';//faz virar um longlong gcValor2 = val3 -'0';//faz virar um longlong gcValor1 = val2 -'0';//faz virar um longlong gcValor0 = val1 -'0';//faz virar um long
retorno = gcValor3+(gcValor2*10)+(gcValor1*100)+(gcValor0*1000);
return(retorno);
}
//=================================================//funçao: _string_to_char//parametros: char val1 - centena,char val2 - dezenas,char val3 - unidades//retorno://=================================================char string_to_char(char val2,char val3)
{
char retorno=0;
char Valor2 = val3 -'0';//faz virar um longchar Valor1 = val2 -'0';//faz virar um long
retorno = Valor2+(Valor1*10);
return(retorno);
}
char char_to_hex( char car)
{
char retorno;
switch(car)
{
case'0':
{
retorno = 0;
}break;
case'1':
{
retorno = 1;
}break;
case'2':
{
retorno = 2;
}break;
case'3':
{
retorno = 3;
}break;
case'4':
{
retorno = 4;
}break;
case'5':
{
retorno = 5;
}break;
case'6':
{
retorno = 6;
}break;
case'7':
{
retorno = 7;
}break;
case'8':
{
retorno = 8;
}break;
case'9':
{
retorno = 9;
}break;
case'A':
{
retorno = 10;
}break;
case'B':
{
retorno = 11;
}break;
case'C':
{
retorno = 12;
}break;
case'D':
{
retorno = 13;
}break;
case'E':
{
retorno = 14;
}break;
case'F':
{
retorno = 15;
}break;
}
return(retorno);
}
char hex_char( char car)
{
char retorno;
switch(car)
{
case 0x00:
{
retorno = '0';
}break;
case 0x01:
{
retorno = '1';
}break;
case 0x02:
{
retorno = '2';
}break;
case 0x03:
{
retorno = '3';
}break;
case 0x04:
{
retorno = '4';
}break;
case 0x05:
{
retorno = '5';
}break;
case 0x06:
{
retorno = '6';
}break;
case 0x07:
{
retorno = '7';
}break;
case 0x08:
{
retorno = '8';
}break;
case 0x09:
{
retorno = '9';
}break;
case 0x0A:
{
retorno = 'A';
}break;
case 0x0B:
{
retorno = 'B';
}break;
case 0x0C:
{
retorno = 'C';
}break;
case 0x0D:
{
retorno = 'D';
}break;
case 0x0E:
{
retorno = 'E';
}break;
case 0x0F:
{
retorno = 'F';
}break;
}
return(retorno);
}
char char_para_hexa(char vl1, char vl2)
{
char resultado = (char_to_hex(vl1)*16)+char_to_hex(vl2);
return(resultado);
}
void hexa_to_char(char hexad)
{
if(hexad > 0x0F)
{
v2= hexad&0X0F;
v2 = hex_char(v2);
v1 = (hexad>>4);
v1 = hex_char(v1);
}
else
{
v1='0';
v2=hex_char(hexad);
}
}
void int_to_char(int quant)
{
convert_char[0]='0';
convert_char[1]='0';
//convert_char[2]='0';/* while(quant>=100) { quant=quant-100; convert_char[0]++; }*/
while(quant>=10)
{
quant=quant-10;
convert_char[0]++;
}
while(quant>=1)
{
quant=quant-1;
convert_char[1]++;
}
}
//////////////////////////interrupções requerida para usar a recepção serial///////////////////////////////////
ISR(USART_RX_vect)
{
gcRs232_caracter = (char)UDR0;
// if(giRs232_pos == 0)if(((gcRs232_caracter == '<')||(gcRs232_caracter == 0XFF))&&(gbRs232_pacote_recebido == 0))//inicia a recepção se já tiver lido o buffer
{
//if(((gcRs232_caracter == '<')||(gcRs232_caracter == 0XFF))&&(gbRs232_pacote_recebido == 0))//inicia a recepção se já tiver lido o buffer//{
gcRs232_buffer[0]=gcRs232_caracter;
gcChecksum=0;
giRs232_pos=1;
//}
}
else
{
if(giRs232_pos < 18)
{
if(gcRs232_buffer[0] == 0XFF)
{
if(giRs232_pos == 2)
{//pos2if(gcRs232_buffer[1]!= gcEnd_placa)
{//já zera
gbRs232_pacote_recebido = 0;
limpa_buffer();
}
else
{//sim é igual
gcRs232_buffer[giRs232_pos]=gcRs232_caracter;
gcChecksum += gcRs232_caracter ;
giRs232_pos++;
// }
}
//}
}
else
{
gcRs232_buffer[giRs232_pos]=gcRs232_caracter;
if(giRs232_pos == 6)//se chegou até aqui é porque o endereço confere
{
if(gcChecksum == gcRs232_caracter )
{
gbRs232_pacote_recebido = 2;//sinaliza que tem dados
}
}
else
{
gcChecksum += gcRs232_caracter ;
}
giRs232_pos++;
}
}
else
{
if((gcRs232_caracter == '>')&&(gcRs232_buffer[0] == '<'))
{
gbRs232_pacote_recebido = 3;//sinaliza que tem dados
}
gcRs232_buffer[giRs232_pos]=gcRs232_caracter;
giRs232_pos++;
}
}
else
{//já zera pois pacote é muito grande,é erro
gbRs232_pacote_recebido = 0;
limpa_buffer();
}
}
}
//////////////////////////////////////ler e escreve um inteiro na eeprom//////////////////////////void escreve_memoria(int ende,char dados)
{
_EEPUT(ende,dados);
}
char ler_memoria(int ende)
{
char temp;
_EEGET(temp,ende);//local a ser lido return(temp);
}
void ler_memo()
{
gcEnd_placa = ler_memoria(1);
gcRele[0][4] = ler_memoria(2);//tempo
gcRele[1][4] = ler_memoria(3);
gcRele[2][4] = ler_memoria(4);
gcRele[3][4] = ler_memoria(5);
gcRele[4][4] = ler_memoria(6);
gcRele[5][4] = ler_memoria(7);
gcRele[6][4] = ler_memoria(8);
gcRele[0][5] = ler_memoria(9);//estado
gcRele[1][5] = ler_memoria(10);
gcRele[2][5] = ler_memoria(11);
gcRele[3][5] = ler_memoria(12);
gcRele[4][5] = ler_memoria(13);
gcRele[5][5] = ler_memoria(14);
gcRele[6][5] = ler_memoria(15);
gcRele[0][0] = ler_memoria(16);//comando1 ligar
gcRele[1][0] = ler_memoria(17);
gcRele[2][0] = ler_memoria(18);
gcRele[3][0] = ler_memoria(19);
gcRele[4][0] = ler_memoria(20);
gcRele[5][0] = ler_memoria(21);
gcRele[6][0] = ler_memoria(22);
gcRele[0][1] = ler_memoria(23);//comando2 ligar
gcRele[1][1] = ler_memoria(24);
gcRele[2][1] = ler_memoria(25);
gcRele[3][1] = ler_memoria(26);
gcRele[4][1] = ler_memoria(27);
gcRele[5][1] = ler_memoria(28);
gcRele[6][1] = ler_memoria(29);
gcRele[0][2] = ler_memoria(30);//comando1 desligar
gcRele[1][2] = ler_memoria(31);
gcRele[2][2] = ler_memoria(32);
gcRele[3][2] = ler_memoria(33);
gcRele[4][2] = ler_memoria(34);
gcRele[5][2] = ler_memoria(35);
gcRele[6][2] = ler_memoria(36);
gcRele[0][3] = ler_memoria(37);//comando2 desligar
gcRele[1][3] = ler_memoria(38);
gcRele[2][3] = ler_memoria(39);
gcRele[3][3] = ler_memoria(40);
gcRele[4][3] = ler_memoria(41);
gcRele[5][3] = ler_memoria(42);
gcRele[6][3] = ler_memoria(43);
}
void gravar_memoria(void)
{
cli();
escreve_memoria(1,gcEnd_placa);
escreve_memoria(16,gcRele[0][0]);//comando1 ligar
escreve_memoria(17,gcRele[1][0]);
escreve_memoria(18,gcRele[2][0]);
escreve_memoria(19,gcRele[3][0]);
escreve_memoria(20,gcRele[4][0]);
escreve_memoria(21,gcRele[5][0]);
escreve_memoria(22,gcRele[6][0]);
escreve_memoria(23,gcRele[0][1]);//comando2 ligar
escreve_memoria(24,gcRele[1][1]);
escreve_memoria(25,gcRele[2][1]);
escreve_memoria(26,gcRele[3][1]);
escreve_memoria(27,gcRele[4][1]);
escreve_memoria(28,gcRele[5][1]);
escreve_memoria(29,gcRele[6][1]);
escreve_memoria(30,gcRele[0][2]);//comando1 desligar
escreve_memoria(31,gcRele[1][2]);
escreve_memoria(32,gcRele[2][2]);
escreve_memoria(33,gcRele[3][2]);
escreve_memoria(34,gcRele[4][2]);
escreve_memoria(35,gcRele[5][2]);
escreve_memoria(36,gcRele[6][2]);
escreve_memoria(37,gcRele[0][3]);//comando1 desligar
escreve_memoria(38,gcRele[1][3]);
escreve_memoria(39,gcRele[2][3]);
escreve_memoria(40,gcRele[3][3]);
escreve_memoria(41,gcRele[4][3]);
escreve_memoria(42,gcRele[5][3]);
escreve_memoria(43,gcRele[6][3]);
escreve_memoria(2,gcRele[0][4]);//escreve tempo
escreve_memoria(3,gcRele[1][4]);//escreve tempo
escreve_memoria(4,gcRele[2][4]);//escreve tempo
escreve_memoria(5,gcRele[3][4]);//escreve tempo
escreve_memoria(6,gcRele[4][4]);//escreve tempo
escreve_memoria(7,gcRele[5][4]);//escreve tempo
escreve_memoria(8,gcRele[6][4]);//escreve tempo
escreve_memoria(9,gcRele[0][5]);//tipo de acionamento
escreve_memoria(10,gcRele[1][5]);
escreve_memoria(11,gcRele[2][5]);
escreve_memoria(12,gcRele[3][5]);
escreve_memoria(13,gcRele[4][5]);
escreve_memoria(14,gcRele[5][5]);
escreve_memoria(15,gcRele[6][5]);
escreve_memoria(50,'G');//indica que houve gravação
sei();
}
/////////////////////////////////config.padrao//////////////////////////void padrao(void)
{
int ende = 0;
gcEnd_placa = 0x01;//endereço padrão é 01
while(ende < 7)//limpa registros
{
gcRele[ende][0]=0x00;//comando1 da pan ligar
gcRele[ende][1]=0x00;//comando2 da pan ligar
gcRele[ende][2]=0x00;//comando1 da pan desligar
gcRele[ende][3]=0x00;//comando2 da pan desligar
gcRele[ende][4]=0;//tempo
gcRele[ende][5]='E';//tipo de acionamento por estado do rele*/
ende++;
}
// seta registros
gcRele[0][1]=0x08;// sobe/comando2 da pan ligar
gcRele[0][3]=0x10;// desce/comando2 da pan desligar
gcRele[1][1]=0x04;// esquerda/comando2 da pan ligar
gcRele[1][3]=0x02;// direita/comando2 da pan desligar
gcRele[2][1]=0x20;// zoom+/comando2 da pan ligar
gcRele[2][3]=0x40;// zoom-/comando2 da pan desligar
gcRele[3][1]=0x80;// foco+/comando2 da pan ligar
gcRele[3][2]=0x01;// foco-/comando1 da pan desligar
gcRele[4][0]=0x02;// iris+/comando1 da pan ligar
gcRele[4][2]=0x04;// iris-/comando1 da pan desligar
gcRele[5][1]=0x0C;// ne/comando2 da pan ligar
gcRele[5][3]=0x12;// so/comando2 da pan desligar
gcRele[6][1]=0x0A;// no/comando2 da pan ligar
gcRele[6][3]=0x14;// se/comando2 da pan desligar
gravar_memoria();
}
void rotina_configura()
{
int erro = 1;
if((gcRs232_buffer[2]=='S')&&(giRs232_pos == 4))//envia todos os estados da placa
{
int cont=0;
escreve('<');
escreve('S');
while(cont<7)
{
unsigned char temp[13];
temp[0]=(char)'1'+cont;//numero do rele - assim compensa a não existencia do rele 0
hexa_to_char(gcRele[cont][0]);//comando ligar os rele B1
temp[1]= v1;
temp[2]= v2;
hexa_to_char(gcRele[cont][1]);//comando ligar os rele B2
temp[3]= v1;
temp[4]= v2;
hexa_to_char(gcRele[cont][2]);//comando desligar os rele B1
temp[5]= v1;
temp[6]= v2;
hexa_to_char(gcRele[cont][3]);//comando desligar os rele B2
temp[7]= v1;
temp[8]= v2;
int_to_char(gcRele[cont][4]);
// temp[9]= convert_char[0];
temp[9]= '0';
temp[10]= convert_char[0];
temp[11]= convert_char[1];
temp[12]= gcRele[cont][5];
temp[13]='>';
imprime(temp,13);
cont++;
}
hexa_to_char(gcEnd_placa);//endereço
escreve(v1);
escreve(v2);
escreve('>');
erro = 0;
}
if((gcRs232_buffer[2]=='P')&&(giRs232_pos == 4))//restaura todos os valores padrão
{
padrao();
imprime("<P>",2);
erro = 0;
}
if((gcRs232_buffer[2]=='E')&&(giRs232_pos == 6))//muda endereço do equipamento
{
gcEnd_placa = char_para_hexa(gcRs232_buffer[3],gcRs232_buffer[4]);//string_to_char('0',gcRs232_buffer[3],gcRs232_buffer[4]);
escreve_memoria(1,gcEnd_placa);
escreve_memoria(50,'G');
imprime("<M>",2);
erro = 0;
}
if((gcRs232_buffer[2]=='-')&&(giRs232_pos == 17))//comando de gravação
{
unsigned int ende = (int)gcRs232_buffer[3] - '0';//faz virar um long
ende--;//assim não vai existir rele 0if(ende < 7 )
{
gcRele[ende][0]=char_para_hexa(gcRs232_buffer[4],gcRs232_buffer[5]);
gcRele[ende][1]=char_para_hexa(gcRs232_buffer[6],gcRs232_buffer[7]);
gcRele[ende][2]=char_para_hexa(gcRs232_buffer[8],gcRs232_buffer[9]);
gcRele[ende][3]=char_para_hexa(gcRs232_buffer[10],gcRs232_buffer[11]);
gcRele[ende][4]=string_to_char(gcRs232_buffer[13],gcRs232_buffer[14]);//tempo
gcRele[ende][5]=gcRs232_buffer[15];//tipo de acionamento*/
imprime("<C>",2);
erro = 0;
gravar_memoria();
}
else
{//rele inexistente
imprime("<E1>",3);
erro = 0;//não precisa escrever erro pois já foi escrito
}
}
if(erro > 0 )
{
imprime("<E2>",3);//falha qualquer
}
}
void led()
{
tempo_pisca = 0;
ALTERNA_PINO(PORTD,LED);
int contas=0;
while(contas<7)//verifica se tem algum rele pra desligar
{
if(gcTemp_pulso[contas] > 0)
{
if(gcTemp_pulso[contas]== 0x01)
{
muda_rele(contas,0); //desliga rele
}
gcTemp_pulso[contas]--;
}
contas++;
}
}
//////////////////////////////////////////////função principal///////////////////////////////////////////int main(void)
{
DDRD = 0XFE; //inicializa portD como saida exceto pino D0(rx)
DDRB = 0XFF; //inicializa portB como saida
DDRC = 0XFF; //inicializa portC como saida
RS485_inicializa(9600);
if(ler_memoria(50)!= 'G')//testa se a memoria foi alterada alguma vez?
{//não
padrao();
escreve('P');
}
else
{//sim
ler_memo();//busca valores
escreve('G');
}
sei();//habilita interrupções////////////////////////// for(;;)
{
if(gbRs232_pacote_recebido > 0)
{//tem dados pra ler
cli(); //desabilita interrupçõesif(gbRs232_pacote_recebido == 3)//config
{
if(gcRs232_buffer[1]=='C')//comando de gravação
{
rotina_configura();
}
}
if(gbRs232_pacote_recebido == 2)//config
{//dados da rs-485
rotina_rs485();
}
gbRs232_pacote_recebido = 0;//reseta buffer
limpa_buffer();
sei();//habilita interrupções
}
/////////////////////////////////
tempo_pisca++;
if(tempo_pisca == 13000)//alterna led a cada 100ms
{
led();
}
}
}
Olá, hoje vou demonstrar como controlar 3 motores de forma simultânea e ao mesmo tempo você pode mudar o comportamento de cada um de forma independentes,para isto criei um aplicativo serial para monitorar e testar o funcionamento deste projeto, embora esse programa pode ser usado para outras finalidades.
Vamos começar exemplificando como funciona o software do projeto(por ser mais simples) e logo em seguida vamos ao projeto do firmware.
O software do projeto:
O aplicativo de controle do motor de passo é descrito na figura a seguir:
Na figura pode ser visualizado 2 botões de envio de dados, sendo possível enviar o comando de velocidade e de giro de forma alternada sem ter que ficar reescrevendo na caixa de texto, sempre que uma porta serial virtual(geralmente quando se usa um emulador usb/serial) for conectada não é necessário reiniciar o aplicativo pois ao clicar para ver as portas de comunicação disponível o aplicativo já busca no windows quais estão ativas.Para que ele rode perfeitamente no seu computador você deve estar com o framework(a partir da versão 3.5) da microsoft atualizado.
Quando fiz este projeto eu tinha em mente fazer algo que pudesse ser usado em uma CNC qualquer(pois A CNC pode ser de furação,deposição(impressora 3D) ou fresagem) logo os comando enviados devem controlar os três motores de forma independente e ao mesmo tempo ter a possibilidade de mudar a velocidade,mas para que os motores não extrapolem o limite físico da CNC, já previ a utilização de seis chaves fim de curso para sinalizar os limites de cada eixo(inicio e fim).
O comando são enviados por pacotes com a seguinte formatação <XAAYAAZAA> a cada envio de dados o hardware irá devolver um '*' para indica que o comando foi recebido pelo microcontrolador, o carácter 'X' corresponde ao comando a ser efetuado pelo eixo X, o carácter 'Y' corresponde ao comando a ser efetuado pelo eixo Y e o carácter 'Z' corresponde ao comando a ser efetuado pelo eixo Z, já os caracteres 'AA' correspondem ao valor referente ao comandos.A lista de comandos é:
N ->Este comando não faz nada, somente para fechar o pacote.
P ->Este comando manda parar o motor imediatamente.
I ->Este comando manda o motor ir até o inicio do eixo,gira até chegar na chave fim de curso.
F ->Este comando manda o motor ir até o fim do eixo,gira até chegar na chave fim de curso.
H ->Gira um numero de pulsos ('AA' ) no sentido horário, varia de 00 a 99.
A ->Gira um numero de pulsos ('AA' ) no sentido anti-horário, varia de 00 a 99.
V ->Configura a velocidade do motor para um valor qualquer('AA'), varia de 00 a 99.
Por exemplo vamos supor que eu queira a velocidade motor no eixo 'X' igual a 10 do eixo 'Y' igual a 50 e do eixo 'Z' igual a 1, então basta enviar o comando "<V10V50V01>" , vamos supor agora que eu queira que o motor do eixo 'X' dê 10 passos no sentido horário, do eixo 'Y' dê 90 passos no sentido horário e do eixo 'Z' dê 50 passos no sentido anti-horário, então é só enviar o comando "<H10H90A50>", se por ventura eu decidir parar o motor do eixo 'Y' enquanto o comando anterior é executado basta enviar "<N00P00N00>" . Para melhor ilustrar isso veja o vídeo:
O Código fonte:
///************************************************************************/// Placa de controle de uma CNC com 3 eixos// EFUSE = 0XFF | LOCK BIT = 0XFF(sem cod. proteção) | FUSE HBIT = 0XD8 | FUSE LBIT = 0XC7
// Version : 1.0// microcontrolador : AVR ATMega328P// Autor : Aguivone// descrição : CNC via porta serial.// data : 25/05/2014.////AVISOS:
// DESABILITAR OTIMIZAÇOES - 01, Se não dasabilitar pode fazer o programa travar ou rodar de modo errado.// Atenção ao pino de reset sempre deve estar ligado ao +5V. //************************************************************************/#define F_CPU 16000000UL // 16 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
#include <avr/eeprom.h>//usado para acessar memoria// definições auxiliaries#define liga_pino(x,y) x |= _BV(y)
#define desliga_pino(x,y) x &= ~(_BV(y))
#define alterna_pino(x,y) x ^= _BV(y)
#define estado_pino(x,y) ((x & _BV(y)) == _BV(y)) //o pino deve estar como entrada ,testa se está em nivel logico 1// definições dos pinos de entrada#define SI_X PC0//sensor de inicio da posição no eixo X#define SF_X PC1//sensor de fim da posição no eixo X#define SI_Y PC2//sensor de inicio da posição no eixo Y#define SF_Y PC3//sensor de fim da posição no eixo Y#define SI_Z PC4//sensor de inicio da posição no eixo Z#define SF_Z PC5//sensor de fim da posição no eixo Z// definições dos pinos de saidas(motores)#define MX_D PB2//motor de delocamento no eixo X#define MX_C PB3
#define MX_B PB4
#define MX_A PB5
#define MY_A PD6//motor de delocamento no eixo Y#define MY_B PD7
#define MY_C PB0
#define MY_D PB1
#define MZ_D PD2//motor de delocamento no eixo Z#define MZ_C PD3
#define MZ_B PD4
#define MZ_A PD5
///variaveis usadas na comunicação serial
unsigned char caracter;//
unsigned int tam_buffer;//usado para contar o tamanho do buffer de recepção
unsigned char buffer_serial[12];//buffer da serialvolatilechar rec_buffer ='S';//usado para ler o buffer de recepção (volatile para funcionar pois sempre ira retornar mesmo valor)//variaveis dos motores
unsigned char comandos[]={'P','P','P'};
unsigned int num_passo[]={0,0,0};
unsigned int pos_motor[]={0,0,0};
unsigned char sent_giro[]={'A','A','A'};//sentido da ultima rotação//variaveis de tempo
unsigned int tempo[]={0,0,0};//tempo de comparação
unsigned int vel_motor[]={50,50,50};
//variaveis dos sensores
unsigned char status_sensor[]={0,0,0};//sensores de 0 a 2.// I- inicio,F- fim,C- em area de deslocamento///////////////////////////////////////////////funçoes usadas pela usart////////////////////////////////////////////////void serial_inicializa(int BAUD)
{
int valor = ((F_CPU/16)/BAUD)-1; //verifique se na simulação não está habilitado pra divir por oito o clock do microcontrolador/* baud rate */
UCSR0A = 0X20;
/* habilita receiver and transmitter buffers */
UBRR0H = (unsigned char)(valor>>8);
UBRR0L = (unsigned char)valor;
/* habilita receiver and transmitter buffers */
UCSR0B = 0X98;//deve se habilitar somente a interrupção de recepção para não travar o microcontrolador/* modo assicrono,8 bits , 1 stop bit, assincrono , sem paridade */
UCSR0C = 0X06;
//UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void impri_serial(constchar frase[20])//já tem caracter null embutido
{
unsigned int indice=0;
unsigned int tamanho = strlen(frase);
while(indice<=tamanho)///veja que o programa pode travar se aqui não tiver as duas aspas
{
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
UDR0 =frase[indice];
indice++;
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
}
}
void escreve_caracter(constchar carac)
{
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir para enviar um novo
UDR0 =carac;
while ( !( UCSR0A & (1<<UDRE0)) ); //espera transmitir desabilita a transmissão
}
void inicializa_timer0(void)
{
TCCR0A = 0X00;//não tem uso para o timer,configura para modo normal// TCCR0B = 0x01; //pre escaler dividido por 1// TCCR0B = 0x02; //pre escaler dividido por 8// TCCR0B = 0x03; //pre escaler dividido por 64
TCCR0B = 0x04; //pre escaler dividido por 256// TCCR0B = 0x05; //pre escaler dividido por 1024//uma interrupção a cada 64ms
TIMSK0 = 0x01; //habilita interrupção do timer 0(estouro do contador)
}
void parar_timer(void)
{
TIMSK0 = 0x00; //desabilita interrupção do timer 0(estouro do contador)
}
void reiniciar_timer(void)
{
TIMSK0 = 0x01; //habilita interrupção do timer 0(estouro do contador)
}
//////////////////////////interrupção requerida para usar a serial///////////////////////////////////
ISR(USART_RX_vect)
{
caracter = (char)UDR0;
if(caracter == '>')
{
if((tam_buffer<12)&&(tam_buffer>9))//max do display
{
rec_buffer ='F';//dados
}
else
{
rec_buffer = 'S';//pede pra ignorar vetor - zera
}
}
if((caracter != '>')&&(rec_buffer == 'I'))
{
buffer_serial[tam_buffer]=caracter;
tam_buffer++;
}
if(caracter == '<')
{
rec_buffer ='I';
buffer_serial[0]='<';
tam_buffer=1;
}
}
void parar_motor(int eixo)
{
if(eixo == 0)
{//eixo X
desliga_pino(PORTB,MX_A);
desliga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_D);
}
else
{
if(eixo == 1)
{// eixo Y
desliga_pino(PORTD,MY_A);
desliga_pino(PORTD,MY_B);
desliga_pino(PORTB,MY_C);
desliga_pino(PORTB,MY_D);
}
else
{//eixo Z (2)
desliga_pino(PORTD,MZ_A);
desliga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_D);
}
}
if((comandos[eixo]=='A')||(comandos[eixo]=='F'))
//isso compensa o ultimo decremento que não foi usado
{
if(pos_motor[eixo]== 3)
{
pos_motor[eixo]= 0 ;
}
else
{
pos_motor[eixo]++;
}
}
if((comandos[eixo]=='I')||(comandos[eixo]=='H'))
//isso compensa o ultimo incremento que não foi usado
{
if(pos_motor[eixo]== 0)
{
pos_motor[eixo]= 3 ;
}
else
{
pos_motor[eixo]--;
}
}
num_passo[eixo]=0;
tempo[eixo]=0;//zera tempo
}
void atualiza_sensores()
{
if((estado_pino(PINC,SI_X)==1)&&(estado_pino(PINC,SF_X)==1))
{
status_sensor[0] = 'C';//indica que está no curso do eixo
}
else
{
if(estado_pino(PINC,SI_X)==1)
{
status_sensor[0] = 'I';//indica que está no inicio do eixo
}
else
{
status_sensor[0] = 'F';//indica que está no fim do eixo
}
}
if((estado_pino(PINC,SI_Y))&&(estado_pino(PINC,SF_Y)))
{
status_sensor[1] = 'C';//indica que está no curso do eixo
}
else
{
if(estado_pino(PINC,SI_Y))
{
status_sensor[1] = 'I';//indica que está no inicio do eixo
}
else
{
status_sensor[1] = 'F';//indica que está no fim do eixo
}
}
if((estado_pino(PINC,SI_Z))&&(estado_pino(PINC,SF_Z)))
{
status_sensor[2] = 'C';//indica que está no curso do eixo
}
else
{
if(estado_pino(PINC,SI_Z))
{
status_sensor[2] = 'I';//indica que está no inicio do eixo
}
else
{
status_sensor[2] = 'F';//indica que está no fim do eixo
}
}
}
void giro_anti_horario(int eixo)
{
switch(pos_motor[eixo])
{
case 0:
{//passo 1if(eixo == 0)
{//eixo X
liga_pino(PORTB,MX_A);
desliga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_D);
}
else
{
if(eixo == 1)
{// eixo Y
liga_pino(PORTD,MY_A);
desliga_pino(PORTD,MY_B);
desliga_pino(PORTB,MY_C);
desliga_pino(PORTB,MY_D);
}
else
{//eixo Z (2)
liga_pino(PORTD,MZ_A);
desliga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_D);
}
}
pos_motor[eixo]=3;
}break;
case 1:
{//passo 2if(eixo == 0)
{//eixo X
liga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_A);
desliga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_D);
}
else
{
if(eixo == 1)
{// eixo Y
liga_pino(PORTD,MY_B);
desliga_pino(PORTD,MY_A);
desliga_pino(PORTB,MY_C);
desliga_pino(PORTB,MY_D);
}
else
{//eixo Z (2)
liga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_A);
desliga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_D);
}
}
pos_motor[eixo]=0;
}break;
case 2:
{//passo 3if(eixo == 0)
{//eixo X
liga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_A);
desliga_pino(PORTB,MX_D);
}
else
{
if(eixo == 1)
{// eixo Y
liga_pino(PORTB,MY_C);
desliga_pino(PORTD,MY_B);
desliga_pino(PORTD,MY_A);
desliga_pino(PORTB,MY_D);
}
else
{//eixo Z (2)
liga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_A);
desliga_pino(PORTD,MZ_D);
}
}
pos_motor[eixo]=1;
}break;
case 3:
{//passo 4if(eixo == 0)
{//eixo X
liga_pino(PORTB,MX_D);
desliga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_A);
}
else
{
if(eixo == 1)
{// eixo Y
liga_pino(PORTB,MY_D);
desliga_pino(PORTD,MY_B);
desliga_pino(PORTB,MY_C);
desliga_pino(PORTD,MY_A);
}
else
{//eixo Z (2)
liga_pino(PORTD,MZ_D);
desliga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_A);
}
}
pos_motor[eixo]= 2;
}break;
}
}
void giro_horario(int eixo)
{
switch(pos_motor[eixo])
{
case 0:
{//passo 1if(eixo == 0)
{//eixo X
liga_pino(PORTB,MX_A);
desliga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_D);
}
else
{
if(eixo == 1)
{// eixo Y
liga_pino(PORTD,MY_A);
desliga_pino(PORTD,MY_B);
desliga_pino(PORTB,MY_C);
desliga_pino(PORTB,MY_D);
}
else
{//eixo Z (2)
liga_pino(PORTD,MZ_A);
desliga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_D);
}
}
pos_motor[eixo]=1;
}break;
case 1:
{//passo 2if(eixo == 0)
{//eixo X
liga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_A);
desliga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_D);
}
else
{
if(eixo == 1)
{// eixo Y
liga_pino(PORTD,MY_B);
desliga_pino(PORTD,MY_A);
desliga_pino(PORTB,MY_C);
desliga_pino(PORTB,MY_D);
}
else
{//eixo Z (2)
liga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_A);
desliga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_D);
}
}
pos_motor[eixo]=2;
}break;
case 2:
{//passo 3if(eixo == 0)
{//eixo X
liga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_A);
desliga_pino(PORTB,MX_D);
}
else
{
if(eixo == 1)
{// eixo Y
liga_pino(PORTB,MY_C);
desliga_pino(PORTD,MY_B);
desliga_pino(PORTD,MY_A);
desliga_pino(PORTB,MY_D);
}
else
{//eixo Z (2)
liga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_A);
desliga_pino(PORTD,MZ_D);
}
}
pos_motor[eixo]=3;
}break;
case 3:
{//passo 4if(eixo == 0)
{//eixo X
liga_pino(PORTB,MX_D);
desliga_pino(PORTB,MX_B);
desliga_pino(PORTB,MX_C);
desliga_pino(PORTB,MX_A);
}
else
{
if(eixo == 1)
{// eixo Y
liga_pino(PORTB,MY_D);
desliga_pino(PORTD,MY_B);
desliga_pino(PORTB,MY_C);
desliga_pino(PORTD,MY_A);
}
else
{//eixo Z (2)
liga_pino(PORTD,MZ_D);
desliga_pino(PORTD,MZ_B);
desliga_pino(PORTD,MZ_C);
desliga_pino(PORTD,MZ_A);
}
}
pos_motor[eixo]= 0;
}break;
}
}
int valor_decimal(char dezena,char unidade)
{
int retorno=0;
dezena = dezena - 0X30;//converte para int
unidade = unidade - 0X30;
if(dezena == 0X00)
{
retorno = unidade;
}
else
{
retorno = (dezena*10)+unidade;
}
return(retorno);
}
void compensa_giro(int passo)
{
//como o valor que está na variavel seria a prox posição, mas o giro foi invertdo//logo deve voltar a posição atual e então colocar o proxima posição conforme a seguir:switch(pos_motor[passo])
{
case 0:
{
pos_motor[passo]=2;
}break;
case 1:
{
pos_motor[passo]=3;
}break;
case 2:
{
pos_motor[passo]=0;
}break;
case 3:
{
pos_motor[passo]=1;
}break;
}
}
void ger_motor(int rodar)
{
switch(comandos[rodar])
{
case'N':
{//não altera o estado atual do motor mas evita a perda de tempo checando as proximas possibilidades
}break;
case'P':
{//manda o motor pararif(num_passo > 0)//testa se motor está energizado?
{
parar_motor(rodar);
}
}break;
case'I':
{//manda motor voltar a origem do eixoif(status_sensor[rodar] != 'I')//ainda não chegou na origem do eixo
{
if(sent_giro[rodar]=='H')//verifica de qual lado foi o ultimo giro
{//isso indica que o giro deve ser invertido logo a proxima posição deve ser compensada
compensa_giro(rodar);
giro_anti_horario(rodar);
}else
{
giro_anti_horario(rodar);
}
sent_giro[rodar]='A';
}
else
{//se já estiver na origem não movimenta mais
parar_motor(rodar);
num_passo[rodar]=0;
comandos[rodar]='P';//troca o comando para não ficar executando essa rotina
}
}break;
case'F':
{//manda motor ir para o fim do eixoif(status_sensor[rodar] != 'F')//ainda não chegou no fim do eixo
{
if(sent_giro[rodar]=='H')
{
giro_horario(rodar);
}else
{//compensa inversão de giro
compensa_giro(rodar);
giro_horario(rodar);
}
sent_giro[rodar]='H';
}
else
{//chegou ao fim do eixo.
parar_motor(rodar);
num_passo[rodar]=0;
comandos[rodar]='P';//troca o comando para não ficar executando essa rotina
}
}break;
case'A':
{//manda motor girar em sentido anti-horario,rumo ao inicio de deslocamentoif(status_sensor[rodar] != 'I')//ainda não chegou na origem do eixo
{
if(sent_giro[rodar]=='H')//verifica de qual lado foi o ultimo giro
{//isso indica que o giro deve ser invertido logo a proxima posição deve ser compensada
compensa_giro(rodar);
giro_anti_horario(rodar);
}else
{
giro_anti_horario(rodar);
}
sent_giro[rodar]='A';
if(num_passo[rodar] <= 0)
{
parar_motor(rodar);
num_passo[rodar]=0;
comandos[rodar]='P';//troca o comando para não ficar executando essa rotina
}
else
{
num_passo[rodar]--;
}
}
else
{//se já estiver na origem não movimenta mais
parar_motor(rodar);
num_passo[rodar]=0;
comandos[rodar]='P';//troca o comando para não ficar executando essa rotina
}
}break;
case'H':
{//manda motor girar em sentido horario, rumo ao fim do deslocamento.if(status_sensor[rodar] != 'F')//ainda não chegou no fim do eixo
{
if(sent_giro[rodar]=='H')
{
giro_horario(rodar);
}else
{//compensa inversão de giro
compensa_giro(rodar);
giro_horario(rodar);
}
sent_giro[rodar]='H';
if(num_passo[rodar] <= 0)
{
parar_motor(rodar);
num_passo[rodar]=0;
comandos[rodar]='P';//troca o comando para não ficar executando essa rotina
}
else
{
num_passo[rodar]--;
}
}
else
{//chegou ao fim do eixo.
parar_motor(rodar);
num_passo[rodar]=0;
comandos[rodar]='P';//troca o comando para não ficar executando essa rotina
}
}break;
}
}
ISR(TIMER0_OVF_vect)
{//interrupção overflow// divisão: tempo de cada interrupção:// 1 -> 16s ;// 8 -> 128us ;// 64 -> 1,024ms// 256 -> 4,096ms// 1024 -> 16,38ms.int xis=0;
while(xis<3)
{
tempo[xis]++;
if(tempo[xis] >= vel_motor[xis])//compara tempo de acionar saida
{
atualiza_sensores();//checa o estado das chaves de inicio e fim de curso.
ger_motor(xis);
tempo[xis]=0;//zera tempo
}
xis++;
}
}
int main(void)
{
DDRB = 0XFF; //são saidas
PORTB = 0X00;//zera saidas
DDRC = 0X00; // configurado como entrada (sensores)
DDRD = 0XFE; //pinos como saida exceto D0(RX da serial)
PORTD = 0X00;//zera saidas
DIDR0 = 0X00;////desabilita entrada analogico(reduz consumo).evita problemas quando esse pino é usado como I/O
serial_inicializa(9600);// verifique se o clock não está dividido por 8!
inicializa_timer0();
//parar_timer();
reiniciar_timer();
sei(); //habilita interrupções
parar_timer();
impri_serial(" CNC - 3 Eixos.");
reiniciar_timer();
/*for(;;) { //impri_serial("teste \n\r "); //_delay_ms(500); }*/for(;;)
{
if(rec_buffer =='F')//tem dados pra ler
{
int temp=1;
int com=0;
parar_timer();
while(temp<9)
{
if(buffer_serial[temp]=='V')
{//altera velocidade
vel_motor[com]=valor_decimal(buffer_serial[temp +1],buffer_serial[temp +2]);
}
else
{
comandos[com]=buffer_serial[temp];
num_passo[com]=valor_decimal(buffer_serial[temp +1],buffer_serial[temp +2]);
}
com++;
temp=temp+3;
}
escreve_caracter('*');
reiniciar_timer();
rec_buffer ='S';//fim de processamento de dados
}
}
}