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

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.

Olá Murilo,

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

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.

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.

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.

Obrigado amigo
Vou tentar

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;
   }

}
}

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.

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

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

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.

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

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

1 Curtida

Parabéns, muito bem.