Controle de velocidade de eixo em levitação magnética com pic12F675


#1

Boa noite amigos.
Estou montando um motor estilo keppe motor com algumas modificações para estudos mas detalhados. desenhei este motor todo em 3D e depois subdividi as peças em 2D para usar um cortador a laser, obtive peças bastante precisas e com as medidas exatas para não haver erros na hora dos testes, o eixo está estável e levitando muito bem.
preciso montar um tacômetro para que com esses dados eu possa controlar alguns leds de informação.
montei o circuito no proteus e comprei um pickit 3, 5 pic12F675, e 2 sensores foto elétricos.
Ficaria muito grato se me dessem uma força apenas com a programação referente ao tacometro para o PIC12F675, vou usar um cristal de 4Mhz.


#2

Olá Murilo,

Qual a faixa de frequencia que você espera obter nesta medida elétrica, o sinal é uma onda quadrada 0 e 5V?


#3

sim, é uma onda quadrada, comprei esse sensor foto elétrico

https://www.aliexpress.com/item-img/Free-shipping-Line-Track-Sensor-TCRT5000-Infrared-Reflective-IR-Photoelectric-Switch-Barrier/32517344067.html?spm=2114.10010308.1000017.2.XZcadL

analisando melhor eu nem vou precisar do cristal oscilador, pois o cristal interno do pic12F675 já da conta.
preciso saber a velocidade do eixo para poder dar comandos baseado na velocidade.

basicamente eu preciso fazer esse eixo ficar entre 600rpm e 800rpm, se a velocidade estiver abaixo de 600rpm deve se mandar energia para as bobinas até atingir 800rpm, quando ficar outra vez com 600rpm liga-se outra vez as bobinas.

obs: Não quero usar onda quadrada no motor para controlar sua velocidade com precisão, pois com isso estaria gastando energia desnecessária.
acredito que pelo fato do eixo está levitando o atrito é minimo e a perda de velocidade também é minima.


#4

neste site o amigo usou o pic12f675 como tacômetro ecolocou um lcd, entretanto devido ele usar um cristal oscilador, não sobrou pinos para comandos esterno, pensei em tirar o cristal, mas não consegui arrumar os códigos para o que eu preciso, pois sou meio leigo na programação.
seria até interessante ter um LCD.


#5

Como a frequencia é baixa, 13,3 Hz, dá pra usar isto sem problemas e com uma boa precisão.
Eu recomendo você implementar um contador do sinal do tacômetro, e utilizar o Módulo Timer1 (vide datasheet) para controlar o tempo, a partir daí você pode estabelecer uma relação entre o número de pulsos do tacômetro e dividindo pelo tempo de estouro do Timer1, tem-se a frequencia em Hz ou rpm.


#6

Obrigado amigo
Vou tentar


#7

Boa tarde amigos,
tentei usar o timer0 do PIC12F675 para usar como tacômetro, mas ta dando errado, quando testo no proteus não funciona.

    char numflancos=0;
    int rpm;

void main()
{
ANSEL = 0x00; //desliga as entradas AD
CMCON = 7; //desliga os comparadores
OPTION_REG = 0X10111000;
TMR0 = 0;

trisio=0b11000000;
GPIO = 0;

while(1)
{
TMR0=0; //Inicializa o registro TMR0 com o valor 0.
Delay_ms(1000); //Conta durante 1 segundo.
numflancos=TMR0; //numflancos=velocidade em rps.
rpm=60*numflancos; //Transforma para rpm.

   if(rpm < 600)
   {
     GPIO.F4 = 1;
     GPIO.F5 = 0;
   }
   else
   {
    GPIO.F4 = 1;
    GPIO.F5 = 0;
   }

}
}


#8

Olá Murilo,

Está chegando próximo, mas notei algumas falhas no seu código:

  1. A função Delay_ms(1000) faz com que o microcontrolador “pare” por 1 segundo, não realizando nenhuma operação de leitura, nem de contagem neste tempo, apenas um estouro de interrupção o tiraria deste estado antes dos 1000 ms.

  2. Não identifiquei nenhuma função de contador no código, algo que monitore alguma porta e detecte se houve mudança de nível, caso haja então encrementar contador.

  3. Não estou familiriazado com o Proteus, mas não encontrei as instruções de configuração dos registradores de interrupções.


#9

Obrigado pela valiosa ajuda amigo
Vou aplicar suas dicas.
Desculpe o encomodo


#10

andei estudando e cheguei mais perto rsrsr
amanha eu acredito que termino essa programação

int rpm, P, I,numflancos;

Void interrupt
{
numflancos++; //Conta o numero de pulços
TMR0 = 0x00; //Inicia a contagem no 0
}

void main()
{
ANSEL = 0x00; //desliga as entradas AD
CMCON = 7; //desliga os comparadores
OPTION_REG = 0X10111000; //Modo contador
//Desabilita os registradores de pull-up internos
INTCON = 0b01110000; //Habilita a interrupção global
//Habilita a interrupção por perifericos
//Habilita a interrupção por estouro do TMR0
TMR0 = 0x00;

TRISIO2_bit = 1;
TRISIO4_bit = 0;
TRISIO5_bit = 0;
GPIO = 0;

while(1)
{

      if(rpm > 800)
   {
    I=1;
    P=1;
   }


if(rpm < 800, rpm > 600)
   {
    {
     if(P != 4)
     I=2;
     P=2;
    }
   }


   if(rpm < 600)
   {
    I=3;
   }


   if(I == 3, P != 1, GPIO.F2 == 1)
   {
    GPIO.F4 = 1;
   }
   if(I == 2,P != 1, GPIO.F2 == 1)
   {
    GPIO.F4 = 1;
   }
    if(P == 1, GPIO.F2 == 1, rpm > 600)
   {
    P=4;
   }

    if(P == 4, GPIO.F2 == 1, rpm < 600)
   {
    GPIO.F4 = 1;
    P=2;
    I=2;
   }
    if(rpm < 800, rpm > 600)
   {
    GPIO.F5 = 1;
   }

}
}

preciso que o motor acelere e depois que chegar a 800rpm pare e só acelere quando estiver em 600rpm


#11

Olá Murilo,
Ainda falta uma instrução para utilizar os dados armazenados em “numflancos” e dividir pelo tempo, após isso, deve-se atribuir o valor a numflandos = 0; e recomeçar a contagem.
Mas melhorou muito o código e em pouco tempo, parabéns.


#12

Obrigado amigo
com sua ajuda está cada vez vais fácil estudar e entender como funciona a programação.
vou fazer as alterações.


#13

Finalmente consegui
muito obrigado pela ajuda amigos

vou usar um cristal de 16MHz
usei o TIMER1 para poder contar 65536
e o TIMER0 para temporizador
com overflow de 1s

// Lcd pinout settings
sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D7 at RB7_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D4 at RB4_bit;

// Pin direction
sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D7_Direction at TRISB7_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB4_bit;

int pe, ie;
unsigned counter = 0x00; //Conta até 1000
unsigned pulse = 0x00; //Armazena o número de pulsos
char txt[7]; //String de texto auxiliar

void interrupt()
{
counter++; //Incremento a cada interrupção

TMR0 = 56; //Inicia otimer0 56

INTCON.T0IF = 0x00; //Limpa a flag de interrupção
}

void main()
{
CMCON = 0x07; // Desabilita os comparadores
T1CON = 0x03; // Habilita o Timer1 e Clock Externo
TMR1L = 0x00; // Inicia o Timer1 em 0000
TMR1H = 0x00;

INTCON.GIE = 0X01;     //Ativa a interrupção global
INTCON.PEIE = 0X01;    //Ativa a interrupção por perifericos
INTCON.T0IE = 0X01;    //Ativa a interrupção do TMR0

TMR0 = 0x00;

OPTION_REG = 0b10000001;       //Modo de temporização, prescaler 1:4

//Cristal = 16MHz PIC = 4MHz/4 PIC = 4MHz
//f = 1/4000000
//Tempo =  0,00000025
//Overflow = 0,00000025 * 4 * 200 = 0,0002

TRISB = 0;         // Todo PORTB será saída (Exceto RB0 e RB1)
TRISC = 0b11001111;         // 1110 0111   Apenas o RC4 como saída

PORTB = 0x00;         // Inicia todo PORTB em low
PORTC = 0b00000000;         // RC4 em low

Lcd_Init();           // Inicializa Display
Lcd_Cmd(_LCD_CURSOR_OFF); //Apaga o cursor
Lcd_Cmd(_LCD_CLEAR);  // Limpa o display


// TMR1H     TMR1L
// 00000000  00000000            2^16 = pode contar até 65536

while(1)
{
    if(counter == 5000)             //Quando a contagem chegar em 0,0002 * 5000 = 1s
    {
      pulse = (TMR1H << 8) + TMR1L; //Armazena o valor de 16 bits do Timer1 em pulse
    
      IntToStr(pulse, txt);          //Converte o valor inteiro para string

      Lcd_Out(1,1,"FREQUENCIA:");         //Escreve na linha 1
      Lcd_Out(2,1,txt);            //Imprimir o número da frequancia

      
      
       if ((pulse <= 6)||(pulse >= 3))
        {
         RC5_bit = 0x01;
        }
       if ((pulse > 6)||(pulse < 3))
        {
         RC5_bit = 0x00;
        }
    
       RB0_bit = ~RB0_bit;           //Inverte o RB0
       counter = 0x00;               //Zera o counter
       TMR1H = 0x00;                 //Zera o TMR1H
       TMR1L = 0x00;                 //Zera o TMR1L
    }
     if(RC0_bit == 0x01)
              {

                  if(pulse > 6)
                 {
                  ie=1;
                  pe=1;
                 }


                 if ((pulse <= 6)&&(pulse >= 3))
                 {
                   if(pe != 4)
                  {
                   ie=2;
                   pe=2;
                  }
                 }


                 if(pulse < 3)
                 {
                  ie=3;
                  pe=3;
                 }


                if ((ie == 3)&&(pe != 1))
                 {
                  RC4_bit = 0x01;
                 }

                 if ((ie == 2)&&(pe != 1))
                 {
                  RC4_bit = 0x01;
                 }

                  if ((ie == 1)&&(pulse >= 3))
                 {
                  pe=4;
                 }

                  if ((pe == 4)&&(pulse < 3))
                 {
                  RC4_bit = 0x01;
                  pe=2;
                  ie=2;
                 }


              }
        if(RC0_bit == 0x00)
        {
         RC4_bit = 0x00;
        }
}

} //end main


#14

Parabéns, muito bem.