quinta-feira, 30 de novembro de 2017

Girando motor de passo unipolar nos dois sentidos

     Olá, pessoal que acompanha o blog,para hoje temos uma postagem feita pelo nosso colaborador Renato Lôbo, que consiste em controlar um motor com o pic 12F675, neste projeto o motor de passo funcionará com  uma velocidade de 20 rpm.Projeto feito usado o compilador CCS.
O código fonte:

////////////////////////////////////////////////////////////////////////////////
// Projeto: Girando motor de passo unipolar (28byj-48) nos dois sentidos. //
// Nome: Renato Lôbo Rodrigues                                                //
// Data: 29/11/17                                                             //
// Email: lobosoft@oi.com.br                                                  //
////////////////////////////////////////////////////////////////////////////////

//http://giocarduino.altervista.org/e19-motore-passo-passo.pdf

//dois botões pulsadores no pino 3 e 4 do pic e GND
//0 pino 4 do pic (A3) deve ter um resistor de pull-up 

//pino 7 do pic em 1N1 da placa que acompanha o motor 28byj-48 
//pino 6 do pic em 1N2
//pino 5 do pic em 1N3
//pino 2 do pic em 1N4

//GND em - da placa
//12V em + da placa

//Configuração PIC
#include <12f675.h> 
//inicializando os fusiveis
#fuses INTRC_IO, NOMCLR, NOWDT,PROTECT,PUT,BROWNOUT,CPD
#use delay(clock=4Mhz)        //clock interno de 4mhz                 

#byte tris_portA     = 0x85   //sentido dos pinos do portA

#bit bot1= 0x05.3             //botão sentido horario
#bit bot2= 0x05.4             //botão sentido anti-horario


#bit bob_A1 = 0x05.0          //terminais do motor de passo bobina A e B
#bit bob_A2 = 0x05.1          //
#bit bob_B1 = 0x05.2          //
#bit bob_B2 = 0x05.5          //
                              //se 5 fios lique o center type no GND
                              //se 6 fios ligue os dois center type no GND

int1 roda = false;            //iniciando a variaval roda como falsa
int1 dir  = false;            //iniciando a variaval dir como falsa

int8 pulso =0;                //iniciando a pulso com zero

void motor(int8 num) //configuração de giro do motor em 0.5 passo
{
   switch(num)
   {
      case 0:  bob_A1=1;
               bob_A2=0;
               bob_B1=0;
               bob_B2=0;   
               break;
      case 1:  bob_A1=1;
               bob_A2=1;
               bob_B1=0;
               bob_B2=0;   
               break;
      case 2:  bob_A1=0;
               bob_A2=1;
               bob_B1=0;
               bob_B2=0;   
               break;
      case 3:  bob_A1=0;
               bob_A2=1;
               bob_B1=1;
               bob_B2=0;   
               break;
      case 4:  bob_A1=0;
               bob_A2=0;
               bob_B1=1;
               bob_B2=0;   
               break; 
      case 5:  bob_A1=0;
               bob_A2=0;
               bob_B1=1;
               bob_B2=1;   
               break;               
      case 6:  bob_A1=0;
               bob_A2=0;
               bob_B1=0;
               bob_B2=1;   
               break;
      case 7:  bob_A1=1;
               bob_A2=0;
               bob_B1=0;
               bob_B2=1;   
               break;
      case 8:  bob_A1=0;      //motor desligado
               bob_A2=0;
               bob_B1=0;
               bob_B2=0;   
               break;
   }
}

#int_timer1
void rotina_t1()              //na frenquência de 1khz esse motor gira a 20 rpm 
{
   if(roda)
   {   
      if(dir)
      {
         if(pulso < 7)pulso++;else pulso=0;  //gira anti-horário 
      }else{
         if(pulso > 0)pulso--;else pulso=7;  //gira horário
      }
      motor(pulso);                          //gira 0.5 passo a cada chamada
      roda=false;                            //avisa que terminou 0 0.5 passo
   }
   else
   {
      motor(8);
   }
   set_timer1(64536 + get_timer1());         //preset de contagem do timer1
}



void main ()
{            
   int1 st1 = false,st2 = false;             //status do botão
   
   setup_comparator(NC_NC_NC_NC);            //comparadores desligados
   setup_vref(FALSE);                        //sem valor de referencia
   port_a_pullups(0b00010000);               //pull-up para pino A3
   tris_portA=0b11011000;                    //entrada e saidos dos pinos
   
   bob_A1=0;                                 //todos pinos do motor inicia em zero
   bob_A2=0;
   bob_B1=0;
   bob_B2=0;    
   
   // Timer1 para estouro a cada 1 ms.(Frequência do Ocilador 4Mhz)
   enable_interrupts(global);
   setup_timer_1(t1_internal | t1_div_by_1);
   Enable_interrupts(int_timer1);
   set_timer1(64536);

   while (TRUE)
   {
      if(!roda)
      {
         if( bot1) st1 = false;               
         if(!bot1 && !st1)                   //gira horário 
         {
            dir=false;
            roda=true;
         }
         if( bot2) st2 = false;
         if(!bot2 && !st2)                   //gira anti-horário
         {
            dir=true;
            roda = true;
         }
      }
   }
}

Obrigado a todos. até a próxima!


segunda-feira, 21 de agosto de 2017

Contador 0-99 com pic - usando compilador CCS

Olá, para este post vamos ver como fazer um algoritmo que conta de 0 a 99 usando o compilador CCS, um projeto de Renato Lôbo. para isto vcs irão precisar: 

- Pic16F628 da Microchip
- Placa com display duplo de 7 segmentos de catodo comum
- Capacitor de 100nf para desacoplamento
- Cabinhos para ligação
- Matriz de contato
- Fonte de 5v 








O código fonte:

////////////////////////////////////////////////////////////////////////////////
// Projeto: Usando Varredura no acionamento de display de 7 segmentos.        //
// Nome: Renato Lôbo Rodrigues                                                //
// Data: 20/08/17                                                             //
// Email: lobosoft@oi.com.br                                                  //
////////////////////////////////////////////////////////////////////////////////
#include <16F628A.h>
#use delay (clock = 4Mhz)
//Configure os fusíveis em acordo com o pic selecionado
#fuses NOWDT
#fuses PUT
#fuses NOBROWNOUT
#fuses NOMCLR
#fuses INTRC_IO
#fuses PROTECT

#byte tris_portA     = 0x85
#byte tris_portB     = 0x86

#bit display0        = 0x05.0 //pino A0
#bit display1        = 0x05.1 //pino A1
#bit SegA            = 0x06.1 //pino B1
#bit SegB            = 0x06.2 //pino B2
#bit SegC            = 0x06.3 //pino B3
#bit SegD            = 0x06.4 //pino B4
#bit SegE            = 0x06.5 //pino B5
#bit SegF            = 0x06.6 //pino B6
#bit SegG            = 0x06.7 //pino B7


void digito(int8 num)
{
   switch(num)
   {
      case 0:  SegA=1;//  AAAA
               SegB=1;// F    B
               SegC=1;// F    B
               SegD=1;//   
               SegE=1;// E    C
               SegF=1;// E    C
               SegG=0;//  DDDD
               break;
      case 1:  SegA=0;//  
               SegB=1;//      B
               SegC=1;//      B
               SegD=0;// 
               SegE=0;//      C
               SegF=0;//      C
               SegG=0;//  
               break;
      case 2:  SegA=1;//  AAAA
               SegB=1;//      B
               SegC=0;//      B
               SegD=1;//  GGGG
               SegE=1;// E    
               SegF=0;// E    
               SegG=1;//  DDDD
               break; 
      case 3:  SegA=1;//  AAAA
               SegB=1;//      B
               SegC=1;//      B
               SegD=1;//  GGGG
               SegE=0;//      C
               SegF=0;//      C
               SegG=1;//  DDDD
               break; 
      case 4:  SegA=0;//  
               SegB=1;// F    B
               SegC=1;// F    B
               SegD=0;//  GGGG
               SegE=0;//      C
               SegF=1;//      C
               SegG=1;//  
               break; 
      case 5:  SegA=1;//  AAAA
               SegB=0;// F    
               SegC=1;// F    
               SegD=1;//  GGGG
               SegE=0;//      C
               SegF=1;//      C
               SegG=1;//  DDDD
               break;               
      case 6:  SegA=1;//  AAAA
               SegB=0;// F     
               SegC=1;// F     
               SegD=1;//  GGGG
               SegE=1;// E    C
               SegF=1;// E    C
               SegG=1;//  DDDD
               break; 
      case 7:  SegA=1;//  AAAA
               SegB=1;//      B
               SegC=1;//      B
               SegD=0;//
               SegE=0;//      C
               SegF=0;//      C
               SegG=0;//  
               break;
      case 8:  SegA=1;//  AAAA
               SegB=1;// F    B
               SegC=1;// F    B
               SegD=1;//  GGGG
               SegE=1;// E    C
               SegF=1;// E    C
               SegG=1;//  DDDD
               break;               
      case 9:  SegA=1;//  AAAA
               SegB=1;// F    B
               SegC=1;// F    B
               SegD=1;//  GGGG
               SegE=0;//      C
               SegF=1;//      C
               SegG=1;//  DDDD
               break;
   }
}
//___________________________________________
//Rotina principal
void main()
{
   int1        d = false;
   int8     dig0 = 0;
   int8     dig1 = 0;
   int8    valor = 0;
   int16   conta = 0;  
   
   tris_portA = 0b11111100;   
   tris_portB = 0b00000001;

 
   //DEFINE display0 e TODOS SEGMENTOS LIGADOS PARA TESTE DURANTE 1 SEGUNDO
   display0=1;display1=0;
   SegA=1;//  AAAA
   SegB=1;// F    B
   SegC=1;// F    B
   SegD=1;//   GG
   SegE=1;// E    C
   SegF=1;// E    C
   SegG=1;//  DDDD
   //aguarda 1 segundo
   delay_ms(1000);
   //DEFINE display1 e TODOS SEGMENTOS LIGADOS PARA TESTE DURANTE 1 SEGUNDO
   display0=0;display1=1;
   SegA=1;//  AAAA
   SegB=1;// F    B
   SegC=1;// F    B
   SegD=1;//   GG
   SegE=1;// E    C
   SegF=1;// E    C
   SegG=1;//  DDDD
   //aguarda 1 segundo
   delay_ms(1000);  
   
   while(true) //laço infinito
   {
      if(!d)                     //se d é falso
      {
         display0=1;display1=0;  //seleciona display0
         digito(dig0);           //chama rotina para digitos de 0 a 9
         d=1;                    //troca para display1
      }else{                     //se falso
         display0=0;display1=1;  //seleciona display1
         digito(dig1);           //chama rotina para digitos de 0 a 9
         d=0;                    //troca para display0
      }
      conta++;          //incremento de contagem para acertar um tempo de +/- 1S
      if(conta>=100)    //testa se ja venceu o tempo
      {
         if(valor<100){ //testa se o valor e maior que 100
            valor++;    //se verdadeiro incrementa o valor
         }else{ 
            valor=0;    // se falso atribui zero
         }
         
         dig0=valor%10; //extrai o resto da divisão para o display0
         dig1=valor/10; //extrai o inteiro da divisão para o display1
         
         conta=0;       //atribui zero para iniciar a contagem de tempo
      }
      delay_ms(10);     //tempo de espera para troca de display
   }
}

A demonstração:



segunda-feira, 31 de julho de 2017

Capacímetro com o pic(medidor de capacitância) - compilador CCS

Material para montagem em matriz de contato:
- Pic16F883 da Microchip
- Cristal de 20Mhz
- LCD de 16 x 2
- 2 Trimpot de 10K
- Resistencia de 180R
- Resistencia de 1k
- Resistencia de 10k
- Resistencia de 100k
- Resistencia de 1M
- Capacitor de 100nf
- 2 Capacitores de 15pF
- Vários capacitores para teste
- Cabinhos para licação
- Matriz de contato
- Fonte de 5v

Imagem do esquemático no simulador:


Protótipo do projeto:





O código Fonte:

////////////////////////////////////////////////////////////////////////////////
//Projeto:Capacimetro.c                                                       //
//data:27/07/2017                                                             //
//créditos: http://www.eletronite.com.br/projetos/capacimetro-com-arduino     //
//Convertido de arduino para pic: Renato Lobo Rodrigues                       //
//                                                                            //
//lobosoft@oi.com.br                                                          //
////////////////////////////////////////////////////////////////////////////////

#include <16F883.h>
#DEVICE ADC=10
#use delay (clock = 20Mhz)

//Configura os fusiveis
#fuses HS
#fuses NOWDT
#fuses PUT
#fuses BROWNOUT
#fuses NOMCLR
#fuses PROTECT

#bit carga_Pin1            =0x05.5 //pin_A5 pino para carga do capacitor com resistor de 1k
#bit carga_Pin1_tris       =0x85.5
#bit carga_Pin10           =0x05.4 //pin_A4 pino para carga do capacitor com resistor de 10k
#bit carga_Pin10_tris      =0x85.4
#bit carga_Pin100          =0x07.0 //pin_C0 pino para carga do capacitor com resistor de 100k
#bit carga_Pin100_tris     =0x87.0
#bit carga_Pin1000         =0x07.1 //pin_C1 pino para carga do capacitor com resistor de 1M
#bit carga_Pin1000_tris    =0x87.1
#bit descarga_Pin          =0x07.2 //pin_C2 pino para descarregar capacitor atraves de resistor de 1k
#bit descarga_Pin_tris     =0x87.2

#define Valor_resistor1    1000.0F     // valor do resistor de 1k
#define Valor_resistor10   10000.0F    // valor do resistor de 10k
#define Valor_resistor100  100000.0F   // valor do resistor de 100k
#define Valor_resistor1000 1000000.0F  // valor do resistor de 1M
#define auto_Capacitance   0.000228F

// Variáveis globais
unsigned int32    inicio_tempo;
unsigned int32    Tempo_total;
float             microFarads;
float             nanoFarads;
float             picoFarads;
unsigned char     carga_Pin = 0;
float             Valor_resistor;

void descarregaCap();

#include "lcd-4.c"

//Rotina de interrupção
#int_rtcc
void rotina_t0()
   {
   set_timer0(255) + get_timer0();
   inicio_tempo++;
   }

void main() 
{
   LCD_init();                                     //inicializa o LCD
   //configura a interrupção do timer0
   enable_interrupts(global);
   setup_timer_0(rtcc_internal | rtcc_ext_l_to_h);
   setup_timer_0(rtcc_8_bit | rtcc_div_1);
   Enable_interrupts(int_timer0);
   set_timer0(255);
   //configura o ADC do pic canal 0
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(sAN0);


   // Configura pinos como entrada
   carga_Pin10_tris        = 1; 
   carga_Pin100_tris       = 1; 
   carga_Pin1000_tris      = 1; 
   carga_Pin1_tris         = 1; 
   
   // imprime texto estático na tela
   lcd_gotoxy(1,1);
   printf (lcd_putc,"Lobosoft Ltda.  ");
   lcd_gotoxy(1,2);              
   printf (lcd_putc,"Cap = ");     
   

   while(true) 
   {
      // Seleciona melhor resistor para capacitor a ser medido
      carga_Pin = 0;
      do 
      {
         descarregaCap();
         switch (carga_Pin) 
         {
            case 0:
               carga_Pin10_tris   = 1; 
               carga_Pin100_tris  = 1; 
               carga_Pin1000_tris = 1; 
               carga_Pin1_tris    = 0; 
               carga_Pin1         = 1; 
               Valor_resistor = Valor_resistor1;
               break;
            case 1:
               carga_Pin1_tris    = 1; 
               carga_Pin100_tris  = 1; 
               carga_Pin1000_tris = 1; 
               carga_Pin10_tris   = 0; 
               carga_Pin10        = 1; 
               Valor_resistor = Valor_resistor10;
               break;
            case 2:
               carga_Pin1_tris    = 1;  
               carga_Pin10_tris   = 1; 
               carga_Pin1000_tris = 1; 
               carga_Pin100_tris  = 0; 
               carga_Pin100       = 1; 
               Valor_resistor = Valor_resistor100;
               break;
            case 3:
               carga_Pin1_tris    = 1; 
               carga_Pin10_tris   = 1; 
               carga_Pin100_tris  = 1; 
               carga_Pin1000_tris = 0; 
               carga_Pin1000      = 1; 
               Valor_resistor = Valor_resistor1000;
               break;
         }
         //seleciona canal zero do ADC para leitura
         set_adc_channel(0);
         delay_us(10);
         inicio_tempo = 0; 
         
         //aguarda carga de 63.2% do capacitor para calculo
         while (read_adc() < 648);      // 647 é 63.2% de 1023 (valor máximo da entrada analógica)
         
         //calcula tempo de carga com 39.82% de correção
         Tempo_total = (inicio_tempo*1.3982)*39.82;
         carga_Pin++;
      } while (Tempo_total < 1000 && carga_Pin != 4);
   
      // Converte valor de capacitor medido para unidade de engenharia e imprime no display LCD
   
      microFarads = ((float)Tempo_total / Valor_resistor) - auto_Capacitance;
      if(microFarads >0)
      {
         lcd_gotoxy(7,2);                          
         printf (lcd_putc,"            ");         
         lcd_gotoxy(7,2);                          
      if (microFarads > 1) 
      {
         printf (lcd_putc,"%fuf",microFarads);    
      } 
      else 
      {
         nanoFarads = microFarads * 1000.0;
         if (nanoFarads > 1) 
         {
            printf (lcd_putc,"%fnf ",nanoFarads);    
         } 
         else 
         {
            picoFarads = nanoFarads * 1000.0;
            printf (lcd_putc,"%fpf",picoFarads);    
         }
      }
      descarregaCap();
      delay_ms(500);
      }
      else
      {
         //Se o capacitor não estiver conectado diz que esta ausente
         lcd_gotoxy(7,2);
         printf (lcd_putc,"Ausente   ");
      }
   }
}
// Função para descarregar capacitor
void descarregaCap() {
  carga_Pin10_tris      = 1; 
  carga_Pin100_tris     = 1; 
  carga_Pin1000_tris    = 1; 
  carga_Pin1_tris       = 1; 
  descarga_Pin_tris     = 0; 
  descarga_Pin          = 0; 
  
  //Aguarda a descarga total do capacitor
  while (read_adc() > 0);

  descarga_Pin_tris     = 1;     
}

Biblioteca para LCD alfanumérico

////////////////////////////////////////////////////////////////////////////////
//                          BIBLIOTECA DO LCD                                 //
//                           data:27/07/2017                                  //
//                                                                            //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

// Modifique os pinos o quanto Quiser.

#define LCD_DB4   PIN_b4
#define LCD_DB5   PIN_b5
#define LCD_DB6   PIN_b6
#define LCD_DB7   PIN_b7

#define LCD_RS    PIN_b0
#define LCD_E     PIN_b1


// Se voce quiser uma interface de 6 pinos para seu LCD, então
// conecte o pino R/W do LCD ao terra, e comente a seguinte linha

//#define USE_LCD_RW   1     

//========================================

#define lcd_type 2        // 0=5x7, 1=5x10, 2=2 lines
//#define lcd_line_two 0x40 //LCD RAM address for the 2nd line
#define lcd_line_1 0x00 //LCD RAM address for the 1 line
#define lcd_line_2 0x40 //LCD RAM address for the 2 line
#define lcd_line_3 0x10 //LCD RAM address for the 3 line
#define lcd_line_4 0x50 //LCD RAM address for the 4 line

int8 const LCD_INIT_STRING[4] =
{
 0x20 | (lcd_type << 2), // Func set: 4-bit, 2 lines, 5x8 dots
 0xc,                    // Display on
 1,                      // Clear display
 6                       // Increment cursor
 };
                             

//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note:  !! converts an integer expression
// to a boolean (1 or 0).
 output_bit(LCD_DB4, !!(nibble & 1));
 output_bit(LCD_DB5, !!(nibble & 2)); 
 output_bit(LCD_DB6, !!(nibble & 4));   
 output_bit(LCD_DB7, !!(nibble & 8));   

 delay_cycles(1);
 output_high(LCD_E);
 delay_us(2);
 output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine.  For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.     

#ifdef USE_LCD_RW
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;
   
output_high(LCD_E);
delay_cycles(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);

output_low(LCD_E);
   
return(retval);   
}   
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_LCD_RW
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_LCD_RW
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60); 
#endif

if(address)
   output_high(LCD_RS);
else
   output_low(LCD_RS);
     
 delay_cycles(1);

#ifdef USE_LCD_RW
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}

//----------------------------
void lcd_init(void)
{
int8 i;

output_low(LCD_RS);

#ifdef USE_LCD_RW
output_low(LCD_RW);
#endif

output_low(LCD_E);

delay_ms(15);

for(i=0 ;i < 3; i++)
   {
    lcd_send_nibble(0x03);
    delay_ms(5);
   }

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
   {
    lcd_send_byte(0, LCD_INIT_STRING[i]);
   
    // If the R/W signal is not used, then
    // the busy bit can't be polled.  One of
    // the init commands takes longer than
    // the hard-coded delay of 60 us, so in
    // that case, lets just do a 5 ms delay
    // after all four of them.
    #ifndef USE_LCD_RW
    delay_ms(60);
    #endif
   }

}

/*------------duas linhas----------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;

if(y != 1)
   address = lcd_line_two;
else
   address=0;

address += x-1;
lcd_send_byte(0, 0x80 | address);
}
*/
//------------quatro linhas----------------
void lcd_gotoxy(int8 x, int8 y)
{
int8 address;

switch(y)
   {
   case 1:
      address = lcd_line_1;
      address += x-1;
      break;
   case 2:
      address = lcd_line_2;
      address += x-1;
      break;
   case 3:
      address = lcd_line_3;
      address += x-1;
      break;
   case 4:
      address = lcd_line_4;
      address += x-1;
      break;
   default:
      address = lcd_line_1;
      address += x-1;
      break;
   }
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
 switch(c)
   {
    case '\f':
      lcd_send_byte(0,1);
      delay_ms(2);
      break;
   
    case '\n':
       lcd_gotoxy(1,2);
       break;
   
    case '\b':
       lcd_send_byte(0,0x10);
       break;
   
    default:
       lcd_send_byte(1,c);
       break;
   }
}

//------------------------------
#ifdef USE_LCD_RW
char lcd_getc(int8 x, int8 y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7)); 

output_high(LCD_RS);
value = lcd_read_byte();
output_low(lcd_RS);

return(value);
}


#endif

//implementado por Renato Lôbo Rodrigues

#separate
void lcd_cursor_on()
    {
    lcd_send_byte(0,0x0E);
    }

#separate
void lcd_cursor_blink()
    {
    lcd_send_byte(0,0x0F);
    }

#separate
void lcd_cursor_off()
    {
    lcd_send_byte(0,0x0C);
    }

#separate
void lcd_shift_left()
    {
    lcd_send_byte(0,0x18);
    }

#separate
void lcd_shift_right()
    {
    lcd_send_byte(0,0x1C);
    }

sexta-feira, 21 de julho de 2017

Sistema de irrigação com pic 16F628

Olá, já algum tempo comprei umas válvulas para controlar um sistema de irrigação, dai coloquei três válvulas para decidir qual mangueira acionar (com pequenos pivôs(ou aspersores de irrigação)), o primeiro problema a ser resolvido era tentar umidecer ao máximo todo o jardim com esses aspersores, porém como eu não posso controlar a pressão da água que vem da rua, resolvi montar um circuito que   pudesse acionar fazendo combinações de modo a ter pelo menos 3 níveis de alcance(o alcance depende da pressão da água e esta depende do numero de micropivô).veja abaixo o esquemático do projeto,observe que terá um botão para ligar e outro para desligar(se necessário pois quando o programa for finalizado ele já desliga toda energia).

        Com a combinação consegui um resultado satisfatório; então depois de fazer toda a parte hidráulica era hora de colocar em pratica este circuito que montei, apesar de ter 2 reles para garantir que não existiria energia nos contatos das válvulas(para eliminar risco de choques quando o sistema não estiver acionado, ou caso um vazamento molhasse os contatos elétricos) resolvi separar a parte elétrica da hidráulica e acabei tendo que usar uma caixa de alarme(de uma sucata que eu tinha aqui em casa) para colocar todo o circuito, veja abaixo as fotos da placa e da montagem final:


Vamos agora ver como ficou o código fonte, ele é separado em 2 partes,o modo configuração usado pra gravar os tempos em que o sistema ficará em cada estagio(são 7)  e o modo de funcionamento onde rodará o programa uma vez e logo em seguida desliga tudo.Veja que será usado a comunicação serial pra configurar e guardar os dados na memoria.

O código fonte:

  /* projeto irrigador simples XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F628A
 * Autor: aguivone
 * Versão: 1
 * Data :  06 de julho de 2017
 * 
 * intruções:
 *  a programação deve ser feita usado #SXX* ; onde S=o ciclo que se quer alterar(1 a 7) e XX é um valor de 00 a 99
 *  note que a programação será por multiplos de 10s
 * 
 * 
 * mapa de endereços
 * posição de memoria - descrição.
 * 
 * 0 - posição de memoria rom que indica se houve gravação
 * 1 a 7 - relativo ao modo de funcionamento 1 a 7.
 * 
 */

#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 4000000    // vou usar o oscilador interno
#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  ///se for de 20mhz deve ser HS
#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)

#define BOT_CONFIG   RA4

#define RL_GERAL RB7

#define RL_1 RB4
#define RL_2 RB5
#define RL_3 RB6

#define LED_STATUS RB0


////////////////////////////////////////////////variaveis globais///////////////////////////////////////////////////////////
int modo=0;//modo de funcionamento
int tempo[7];//para guardar os tempos
int pos_prog=6;//posição inicial

//usadas na serial
char rs232[6];//guarda pacote recebido
char caracter;
int pos_serial=0;
bit flag_interrupcao = 0;

/////////////////////////////////funçoes usadas pela uart //////////////////////////////////////////////////////
//void inicializa_RS232(long velocidade,int modo)
void inicializa_RS232()
{////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.  
    TXSTA = 0X24;//modo assincrono,trasmissao 8 bits./alta velocidade
    SPBRG = 25;//9600
    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(TRMT==0);//resolvi usar este flag em vez de TXIF
   // while(TXIF ==0);//espera enviar caracter//alterei para 1 para testar 18/07/17
   // __delay_us(20); 
}
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++;
       }
}
void int_to_char(int quant)
{//converte para inteiro e imprime
     unsigned char ucDez='0', ucUn='0';
     while(quant>=10)
    {
      quant -= 10;  
      ucDez++;  
    }
    while(quant>=1)
    {
       quant -= 1; 
       ucUn++;  
    }
     escreve(ucDez);
     escreve(ucUn);
}
void delay_ms(long valor)//resolve um erro do conmpilador
{
    while(valor>0)
    {
     __delay_ms(1);   
     valor--;
    }        
}
void delay_seg(long valor)//rotina de 1s
{
    while(valor>0)
    {
     __delay_ms(1000); 
     //__delay_ms(100); //pra simular
     LED_STATUS = ~LED_STATUS;
     valor--;
    } 
    //para simular pode reduzir o tempo
}
void ler_dados()
{
    imprime(" \n\r tempos=");
    int var_auxi=0;
    while(var_auxi<7)
    {              
      tempo[var_auxi] = eeprom_read(var_auxi+1);
      int_to_char(tempo[var_auxi]); 
      escreve('0');
      escreve('|');
      var_auxi++;
    }
}


///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////
void interrupt RS232(void)//vetor de interrupção
 {
    if(RCIF)
    {//se pacote for de tamanho diferente ele descarta o pacote. formato #XXX*
     caracter = RCREG;
     if(flag_interrupcao == 0)
     {//verifica se está liberado para ler dados
     if(pos_serial>0)
     {               
            if(caracter == '*')
            {//pacote aceito
                if(pos_serial == 4)
                {
                 flag_interrupcao = 1;
                 rs232[pos_serial]=caracter; 
                 pos_serial = 0;//pra evitar que escreva antes de ler
                }
                else
                {//descarta pois é menor que o esperado
                    pos_serial = 10;//faz zerar tudo
                }
                 
            }
            else
            {
               rs232[pos_serial]=caracter; 
               pos_serial++;
            }            
        }
     if(pos_serial>4)
        {
            //erro no tamanho zera tudo
             rs232[0]='0';
             rs232[1]='0';
             rs232[2]='0';
             rs232[3]='0';
             rs232[4]='0';
             pos_serial = 0; 
        }
     if(caracter == '#')
     {
        pos_serial = 1;
        rs232[0]='#';
     }  
    }
     RCIF = 0;//  limpa flag de interrupção de recepção
    }    

 }


//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISB = 0X02;//configura portB como saida, B1 (pino RX) como entrada
    PORTB = 0;  // limpar as portas que estão configuradas como saidas
    TRISA = 0XFF;//configura portA   como entrada
    inicializa_RS232();//modo de alta velocidade
    PEIE = 1;//habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
    __delay_ms(200);
    imprime("Sistema de irrigação V.1.0.0 \n\r"); 
    //pega valores da memoria
    if(eeprom_read(0) != 'G')
    {//nunca foi gravada, então coloca valor padrão
        eeprom_write(0X00,0);
        eeprom_write(0X01,1);//endereço/valor
        eeprom_write(0X02,1);
        eeprom_write(0X03,1);
        eeprom_write(0X04,1);
        eeprom_write(0X05,1);
        eeprom_write(0X06,1);
        eeprom_write(0X07,1);
    }
    ////leitura 
    modo=1;
    if(BOT_CONFIG == 0)
    {   delay_ms(1000);
        if(BOT_CONFIG == 0)
        {
         imprime("Modo configuração \n\r");        
         modo=0;
       // eeprom_write(0X00,'G');//indica que houve gravação na memoria
         LED_STATUS =1;
        }        
    } 
    if(modo == 1)
        {
          RCIE = 0;//desabilita interrupção de recepção
          TXIE = 0;//desabilita interrupção de transmissao 
          ler_dados(); 
          LED_STATUS =0;
        }
   
    
//////////////
    for(;;)
    {   
        if(modo==0)
        {
            if(flag_interrupcao ==  1)
            {//tem dados para ler
             LED_STATUS =0;
             escreve(rs232[0]);
             escreve(rs232[1]);
             escreve(rs232[2]);//retorna o valor lido
             escreve(rs232[3]);
             escreve(rs232[4]);
             //////processa dados/////
             if((rs232[2]>0X2F)&&(rs232[2]<0X40)&&(rs232[3]>0X2F)&&(rs232[3]<0X40))//indica que foi recebido um numero valido
             {//trata pacote                 
                 if((rs232[1]>0X30)&&(rs232[1]<0X38))//indica que foi recebido um modo valido(entre 1 e 7)
                 {//verifica se o modo de programação tem caracter valido
                    int valor = (((rs232[2] - 0X30)*10)+(rs232[3] - 0X30));//converte pra int
                    int posicao = (rs232[1] - 0X30);//converte pra int 
                    eeprom_write(posicao,valor);//altera o valor na de memoria;                    
                    imprime("\n\r Alterado:\n\r");
                    for(int i=1;i<8;i++)
                    {//imprime valores da memoria
                     int_to_char(eeprom_read(i));
                     escreve('|');
                    }
                    eeprom_write(0X00,'G');//indica que houve gravação na memoria;
                 }
             }
             pos_serial = 0; 
             flag_interrupcao = 0;//libera pra pegar outro pacote 
             LED_STATUS =1;
            }  
            
        }
        else
        {   //a sequencia foi pensada de forma que cada valvula tenha pelo menos 1 ciclo de descanso a cada 2 ciclos(execto se o tempo for zero para uma das posicoes)          
              switch(pos_prog)
              {
                  case 0:
                  { //fim de programa
                     RL_1=0;
                     RL_2=0;
                     RL_3=0;
                     delay_ms(500);
                     RL_GERAL=0;
                  }break;
                  case 1:
                  {
                     if(tempo[0]>0)
                     {
                        RL_1=1;
                        RL_2=0;
                        RL_3=0;
                     } 
                     pos_prog=3;//vai para proxima posição
                     delay_seg(tempo[0]*10);
                  }break;
                  case 2:
                  {
                     if(tempo[1]>0)
                     {
                        RL_1=0;
                        RL_2=1;
                        RL_3=0;
                     } 
                     pos_prog=7;//vai para proxima posição
                     delay_seg(tempo[1]*10);
                  }break;
                  case 3:
                  {
                     if(tempo[2]>0)
                     {
                        RL_1=1;
                        RL_2=1;
                        RL_3=0;
                     } 
                     pos_prog=4;//vai para proxima posição
                     delay_seg(tempo[2]*10);
                  }break;
                  case 4:
                  {
                     if(tempo[3]>0)
                     {
                        RL_1=0;
                        RL_2=0;
                        RL_3=1;
                     } 
                     pos_prog=5;//vai para proxima posição
                     delay_seg(tempo[3]*10);
                  }break;
                  case 5:
                  {
                     if(tempo[4]>0)
                     {
                        RL_1=1;
                        RL_2=0;
                        RL_3=1;
                     } 
                     pos_prog=2;//vai para proxima posição
                     delay_seg(tempo[4]*10);
                  }break;
                  case 6:
                  {//como o programa inicia aqui é preciso ter uma atenção diferente neste ponto
                     RL_GERAL=1; //rele principal, mantem a placa energizada 
                     if(tempo[5]>0)
                     {
                        RL_1=0;
                        RL_2=1;
                        RL_3=1;
                     }
                     else
                     {
                        RL_1=0;
                        RL_2=0;
                        RL_3=0;
                     } 
                     pos_prog=1;//vai para proxima posição
                     delay_seg(tempo[5]*10);
                  }break;                  
                  case 7:
                  {
                     if(tempo[6]>0)
                     {
                        RL_1=1;
                        RL_2=1;
                        RL_3=1;
                     } 
                     pos_prog=0;//vai para proxima posição
                     delay_seg(tempo[6]*10);
                  }break;
              }
        }             
     }//loop infinito 

}

O esquemático de simulação no proteus ficou:


O vídeo de demonstração :



Até a próxima pessoal!







sábado, 15 de julho de 2017

Reproduzindo som MP3 com auxilio do PIC.

             Olá quando pensamos em reproduzir sons MP3 imaginamos sempre um chip ou talvez algum microcontrolador que possua isso em seu hardware(mas são caros e de difícil aquisição, o que prejudica o uso em pequenos projetos), mas existe uma outra possibilidade, estou me referindo aos módulos DSPLAYERS que pode ser controlados por qualquer microcontrolador, bastando para isso ter acesso ao seu set de instruções.
             Veja na figura abaixo a aparência de um modulo DSPLAYER,já vem equipado com entrada USB, comunicação rs_232 para fazer a interface e saída de som analógica(alto falantes) + saídas para fone de ouvido. Neste site tem um exemplo de como usa-lo com arduino além de explorar melhor seus aspectos construtivos https://www.dfrobot.com/wiki/index.php/DFPlayer_Mini_SKU:DFR0299.


            Graças ao meu parceiro Renato que tem me enviado vários materiais para postar (pois como já disse anteriormente em outros "post", estou tendo dificuldade para desenvolver novos projetos), este projeto conta com os recursos principais para fazer funcionar o modulo usando um microcontrolador PIC.Agradeço muito nosso colaborador por compartilhar conosco sua experiencia com este módulo.Ele ainda me deixou uma dica "Se alguém se interessar posso produzir o circuito impresso, só entrar em contato: -> Renato : lobosoft@oi.com.br".

A aparência do protótipo pronto ficou assim:



O código fonte:

 Programa principal: Código para compilação no CCS.

////////////////////////////////////////////////////////////////////////////////
//              Projeto: Aparelho de som com modulo DFPlayer Mini             //
//                 Nome: Renato Lôbo Rodrigues                                //
//                 Data: 12/07/17                                             //
//                Email: lobosoft@oi.com.br                                   //
////////////////////////////////////////////////////////////////////////////////

#include "config_pic675.h"

void main()
{
   int1 st1=false, st2 = false, st3=false, st4 = false, play = true, di = false;
   int8 equ = 1,disp = 1;
   tris_bot1 = 1;
   tris_bot2 = 1;
   tris_bot3 = 1;
   tris_bot4 = 1;
   tris_bot5 = 1;
   GPPU      = 0;
   delay_ms(2000);
   Uart_SendCMD(0x06 , 0 , 0x16 ) ;  //volume inicial
   delay_ms(200);
   sorteia();
   delay_ms(200);
   Tocar();   
   delay_ms(200);          
   Proxima_trilha();
   delay_ms(500);
 
   while(true)
   {
      if( bot1) st1 =false;         //Equalizador
      delay_ms(50);
      if(!bot1 && !st1)
      {
         st1 = true;
         equ++;
         if(equ>5)equ=1;
         if(equ==1)equaliza(1);
         if(equ==2)equaliza(2);
         if(equ==3)equaliza(3);
         if(equ==4)equaliza(4);
         if(equ==5)equaliza(5);
         delay_ms(1000);
      }
      if( bot2) st2 =false;         //troca o dispositivo: Memoria/Pendrive
      delay_ms(50);
      if(!bot2 && !st2)
      {
         st2 = false;
         di=~di;
         if(di) disp=2; else disp=1;
         dispositivo(disp);
         delay_ms(500);
      } 
 
      if(!bot3) st3 =false;         //toca tudo altomaticamente
      delay_ms(50);
      if( bot3 && !st3  && play)
      {
         st3 = true;
         Proxima_trilha();
         delay_ms(200);
      }

      if( bot4) st4 =false;         //tocar/pausa
      delay_ms(50);
      if(!bot4 && !st4)
      {
         st4 = true;
         play = ~play;
         if (play)Tocar();else Pausa();
         delay_ms(500);
      }         
   }
}

Configuração do PIC 12F675

////////////////////////////////////////////////////////////////////////////////
//              Projeto: configuração de cabeçalho de projeto com pic12F675   //
//                 Nome: Renato Lôbo Rodrigues                                //
//                 Data: 12/07/17                                             //
//                Email: lobosoft@oi.com.br                                   //
////////////////////////////////////////////////////////////////////////////////
#include "12F675.h"
#use delay(clock=4Mhz)
#include "DFPlayer.h"
//=======================================================================
//Configurando fusiveis
//=======================================================================
#fuses NOWDT
#fuses PUT
#fuses NOBROWNOUT
#fuses NOMCLR
#fuses INTRC_IO
#fuses PROTECT
//=======================================================================
//Configurando I/O de direção dos pinos
//=======================================================================
#bit  bot1        = 0x05.0
#bit  bot2        = 0x05.2
#bit  bot3        = 0x05.3
#bit  bot4        = 0x05.4
#bit  bot5        = 0x05.5

#bit  tris_bot1   = 0x85.0
#bit  tris_bot2   = 0x85.2
#bit  tris_bot3   = 0x85.3
#bit  tris_bot4   = 0x85.4
#bit  tris_bot5   = 0x85.5

#bit  GPPU        = 0x81.7


Biblioteca do DSPlayer Mini

////////////////////////////////////////////////////////////////////////////////
//              Projeto: Biblioteca para acessar o DFPlayer Mini              //
//                 Nome: Renato Lôbo Rodrigues                                //
//                 Data: 12/07/17                                             //
//                Email: lobosoft@oi.com.br                                   //
////////////////////////////////////////////////////////////////////////////////


#use rs232(baud=9600,xmit=PIN_A1,rcv=PIN_A2, ERRORS)

static unsigned INT8 Send_buf[10] = {0} ;


void SendCmd(unsigned INT8 leng)
{
INT8 i = 0 ;
putc(0x7E);
for(i=0; i<leng; i++)//dados
{
putc(Send_buf[i]);
}
putc(0xEF);
}

void DoSum( unsigned INT8 *Str, unsigned INT8 len)
{
   unsigned INT16 xorsum = 0;
   unsigned INT8 i;
   for(i=0; i<len; i++)
   {
      xorsum = xorsum + Str[i];
   }
   xorsum = 0 -xorsum;
   *(Str+i) = (unsigned INT8)(xorsum >>8);
   *(Str+i+1) = (unsigned INT8)(xorsum & 0x00FF);
}
void Uart_SendCMD(unsigned INT8 CMD ,unsigned INT8 feedback , unsigned INT16 dat)
{
   Send_buf[0] = 0xFF;                       //bytes reservados
   Send_buf[1] = 0x06;                       //comprimento
   Send_buf[2] = CMD;                        //instruções de controle
   Send_buf[3] = feedback;                   //A necessidade de feedback
   Send_buf[5] = (unsigned INT8)(dat);       //datal
   Send_buf[4] = (unsigned INT8)(dat >> 8);  //datah
   DoSum(&Send_buf[0],6);                    //Verifique
   SendCmd(8);                               //Esta transmissão da trama de dados
}

void Arquivo_musica(int8 pasta,int8 numero)
{
   int16 pasta_numero;
   pasta_numero = (pasta * 256) | numero ;
   Uart_SendCMD(15 , 0, pasta_numero);
}

void Proxima_trilha()
{
   Uart_SendCMD(1 , 0, 0);
}

void Trilha_anterior()
{
   Uart_SendCMD(2 , 0, 0);
}

void Diminuir_volume()
{
   Uart_SendCMD(5 , 0, 0);
}

void Aumentar_volume()
{
   Uart_SendCMD(4 , 0, 0);
}

void Volume(int8 vol)
{
   Uart_SendCMD(6 , 0, vol);
}

void Equaliza(int8 equa)
{
   Uart_SendCMD(7 , 0, equa);
}

Void Pausa()
{
   Uart_SendCMD(14 , 0, 0);
}

Void Tocar()
{
   Uart_SendCMD(13 , 0, 0);
}

void dispositivo(int8 disp)
{
   Uart_SendCMD(9 , 0, disp);
}
void sorteia()
{
   Uart_SendCMD(24 , 0, 3);
}
void sequencia()
{
   Uart_SendCMD(24 , 0, 1);
}

Até a próxima pessoal.


sábado, 1 de julho de 2017

Motor de passo Bipolar - no CCS



Olá pessoal que acompanha o blog, hoje temos mais uma postagem do senhor Renato Lôbo Rodrigues,e neste exemplo será demonstrado como acionar um motor de passo por fase.

lista de peças para montagem em bancada:


- matriz de contatos pequena
- pic12F675, microcontrolador da Microchip
- 2 resistor de 10k para pull-up dos botões
- 2 botões de pressão
- 1 capacitor de acoplamento 104
- cabinhos para ligações dos componentes
- fonte de 5V 2A.
- Uma ponte H L298
- Motor de passo pequeno de 1A por fase

O código fonte:


///////////////////////////////////////////////////////////////////////
//              Projeto: Motor de passo Bipolar                      //
//                 Nome: Renato Lôbo Rodrigues                       //
//                 Data: 28/06/17                                    //
//                Email: lobosoft@oi.com.br                          //
///////////////////////////////////////////////////////////////////////

#include <12F675.h>        // inclusão do pic em questão
#OCS 4 MHz                 // oscilador 4.000.000 herts
#use fast_io(A)            // O método rápido de fazer E/S

//Configura os fusiveis
#fuses NOWDT
#fuses PUT
#fuses NOBROWNOUT
#fuses NOMCLR
#fuses INTRC_IO
#fuses PROTECT
//=======================================================================
//Definições de variaveis globais
//=======================================================================

#bit pulso = 0x05.2        //define pino A2 para pulso do motor
#bit dir   = 0x05.3        //define pino A3 para direção de rotação


#bit A     = 0x05.0        // define pino A0 para motor terminal A
#bit B     = 0x05.1        // define pino A1 para motor terminal B
#bit C     = 0x05.4        // define pino A2 para motor terminal C
#bit D     = 0x05.5        // define pino A3 para motor terminal D

#byte tris_portA = 0x85    // direção dos pinos do portA

int8 i = 0;              // variável i(indice) do tipo inteiro 8 bits 

//=======================================================================

void motor()               //função para girar o motor de passo Bipolar
{
   if (i<1) i=4;           //se i é menor que 1 então i = 4
   if (i>4) i=1;           //se i é maior que 4 então 1 = 1
   switch(i)               
   {
      case 1:A=1;B=0;C=0;D=1; break;    //1001
      case 2:A=0;B=1;C=0;D=1; break;    //0101
      case 3:A=0;B=1;C=1;D=0; break;    //0110
      case 4:A=1;B=0;C=1;D=0; break;    //1010
   }
}

void main()//Rotina principal do programa
{
   tris_portA = 0b00001100; //pinos A2 e A3 como entrada e o restante como saida
   While(true)              //loop infinito
   {
      if(!pulso)                 //se pulso é verdadeiro
      {
         if(dir) i++; else i--;  //igual a um: roda num sentido senão no outro sentido
         motor();                //vai para função motor()
         delay_us(800);          //800 microsegundos / simulação: 80 milesegundos
      }
   }
}//Fim de programa

A simulação:

Vídeo com o protótipo funcionando: