domingo, 8 de dezembro de 2019

Usando lcd no modo 4 bits, Wattímetro,voltímetro e amperímetro.


     Olá pessoal que acompanha o blog!
   Neste exemplo os conceitos abordados, no uso do compilador C18, serão o uso do conversor analógico digital e a implementação da comunicação em 4 bits utilizando LCD(funciona para 16X2 ou 4X20). A intenção é criar wattímetro que por consequência deve ler tensão e corrente, lembre-se que este circuito serve apenas para corrente continua. 

O código fonte :


/* 
 * File:   main_lcd.c
 * Author: aguivone
 * descrição: como usar display lcd no modo 4 bits no compilador C18
 * freq.de clock: 20MHZ
 * data:08/12/2019 
 */
#include <stdio.h>
#include <p18f4550.h>    
#include <string.h>
#include <delays.h>

//variaveis locais
unsigned char Buffer_lcd[16];
/////////////////////////////////////pinos do microcontrolador usado no lcd ///////////////////////////////////////////
//o pino r/w é conectado ao terra pois não é feita nenhuma leitura no display
//configuração:
//
// pino display  / pino da porta selecionada
//
// D4 = bit 0 da porta
// D5 = bit 1 da porta
// D6 = bit 2 da porta
// D7 = bit 3 da porta
//
// RS = bit 4 da porta
// EN = bit 5 da porta
//
//define qual porta vai usar neste caso port D
 #define BIT_0  PORTDbits.RD0
 #define BIT_1  PORTDbits.RD1
 #define BIT_2  PORTDbits.RD2
 #define BIT_3  PORTDbits.RD3

 #define RS     PORTDbits.RD4
 #define EN     PORTDbits.RD5
//////////////usado para escrever em cada bit da porta com o lcd.
union{
    unsigned char VALOR;
    struct{
        unsigned b0:1;
        unsigned b1:1; 
        unsigned b2:1;
        unsigned b3:1;
        unsigned b4:1;
        unsigned b5:1;
        unsigned b6:1;
        unsigned b7:1;
    };    
}LCD;
////prototipos de funções //////////////////////////////////////////////////////////////////
void Inic_Regs (void);
void _delay_us(int valor);
void _delay_ms(int valor);
unsigned char valor_bit(char cDa,char cBit);
void porta_lcd(unsigned char ucDado); 
void escreve_LCD(unsigned char ucDado,unsigned char ucVlr); 
void inicializa_LCD(void);
void impri_lcd(int iPos_inicial ,unsigned char ucLinha);
void impri_caracter_lcd(unsigned char ucCaracter,int iPos_inicial ,unsigned char ucLinha);
void Read_ADC (void);

////////função principal /////////////////////////////////////////////////////////////////////

void main() 
{
  Inic_Regs();
  inicializa_LCD();
  sprintf(Buffer_lcd,"Volts Corr. Pot.");
  impri_lcd(0,'1');
  sprintf(Buffer_lcd,"  0     0    0  ");
  impri_lcd(0,'2'); 
  while(1)
   { 
         Read_ADC();
         _delay_ms(300);//lê a cada 2s
   }//fim do laçõ while
 
  }//fim do laço main
/////////////inicializa as portas ////////////////////////////////////// 
void Inic_Regs(void)
{
    TRISA = 0x03;            //PORTA saida, exceto RA0(tensão) e RA1(corrente) será usado para entradas analogicas
    TRISB = 0x00;            //PORTB saida
    TRISC = 0x00;            //PORTC saida
    TRISD = 0x00;            //PORTD saida
    TRISE = 0x00;            //PORTE saida
    ADCON0 = 0X01;          //liga modulo analogico digital e configura entrada de sinal para o pino RA0(AN0)
    ADCON1=0b00001110;          // Vref- seta ao Vss e  Vref+ ao Vdd , somente Ra0 e Ra1 analogico
    //ADCON2 = 0b101101010;    // justificado a direita     // clk Fosc/32
       ADCON2=0b10101001;
    // tempo de aquisição 12TAD(assim funciona pra qualquer cristal, porem fica mais lento, se precisar deve ser ajustado)
    PORTA = 0x00;            //limpa PORTA
    PORTB = 0x00;            //limpa PORTB
    PORTC = 0x00;            //limpa PORTC
    PORTD = 0x00;            //limpa PORTD:
    PORTE = 0x00;            //limpa PORTE
//********************************************************************
}
//////////////funções de tempo /////////////////////////////////////////////////////////////// 
//===================================================================================
//Função:     _delay_us())
//Parâmetros: inteiro
//Retorno:   não tem retorno.
//Descrição: perde tempo em microsegundoas.
//===================================================================================
 void _delay_us(int valor)
 {
     while(valor>0)
     {
      Nop();Nop();Nop();Nop();Nop();//para 20MHZ -> 5 ciclos dão 1us//  para 8mhz -> 0,5 -> 2 ciclos
      valor--;
     }
 }
 //===================================================================================
//Função:     _delay_ms())
//Parâmetros: inteiro
//Retorno:   não tem retorno.
//Descrição: perde tempo em milisegundos.
//===================================================================================
 void _delay_ms(int valor)
 {
     while(valor>0)
     {
      Delay1KTCYx(5);//para 20MHZ -> 5000 ciclos dão 1ms -> [5]// 8mhz -> 2000 -> [2].
      valor--;
     }
 }

//===================================================================================
//Função:     _porta_lcd
//Parâmetros: char cDado
//Retorno:   não tem retorno.
//Descrição: envia um comando de configuração veja que os tempos devem ser maiores .
//===================================================================================
void porta_lcd(unsigned char ucDado)//byte a ser enviado
{
       LCD.VALOR = ucDado;
       //envia os bytes mais altos
       RS = 0; //habilita comandos
       BIT_0 = LCD.b4;
       BIT_1 = LCD.b5;
       BIT_2 = LCD.b6;
       BIT_3 = LCD.b7;
       EN = 1;
       _delay_ms(15);
       EN = 0;
       _delay_ms(15);
       //envia os bytes mais baixos
       BIT_0 = LCD.b0;
       BIT_1 = LCD.b1;
       BIT_2 = LCD.b2;
       BIT_3 = LCD.b3;
       EN = 1;
       _delay_ms(15);
       EN = 0;
       _delay_ms(15);
}
//===================================================================================
//Função:     _escreve_LCD
//Parâmetros: char cDado,
//            int iVlr
//Retorno:   não tem retorno.
//Descrição: escreve um caracter no display ou envia um comando.
//===================================================================================
void escreve_LCD(unsigned char ucDado,unsigned char ucVlr)//byte a ser enviado ,escreve caracter(0) ou comando(1)
{
    if(ucVlr == '0')
       {
         RS = 0; //habilita comandos
       }
       else
       {
        RS = 1; //habilita dados
       }
       LCD.VALOR = ucDado;
        _delay_us(5);//tempo para display atualizar
       //envia os bytes mais altos
       BIT_0 = LCD.b4;
       BIT_1 = LCD.b5;
       BIT_2 = LCD.b6;
       BIT_3 = LCD.b7;
       EN = 1;
       _delay_us(50);//tempo estabilizar o pino
       EN = 0;
       _delay_us(50);//tempo estabilizar o pino
       //envia os bytes mais baixos
       BIT_0 = LCD.b0;
       BIT_1 = LCD.b1;
       BIT_2 = LCD.b2;
       BIT_3 = LCD.b3;
       EN = 1;
       _delay_us(50);//tempo estabilizar o pino
       EN = 0;
       _delay_us(200);
}
//===================================================================================
//Função:     _inicializa_LCD
//Parâmetros: não tem
//Retorno:   não tem retorno.
//Descrição: faz a configuração inicial do display, verifique os datasheet dos fabricantes.
//===================================================================================
void inicializa_LCD(void)
{
       EN = 0;
       _delay_ms(15);//tempo para estabilizar a tensão e preparar o display
       porta_lcd(0X02);//cursor home - posiciona no inicio
       porta_lcd(0X28);//configura para usar modo 4bits,manda usar 2 linhas e matriza de caracter de 5X7.
       porta_lcd(0X01);//limpa display
       porta_lcd(0X06);//deslocamento do cursor para direita ,sem deslocamento de caracter automaticamente. 
       porta_lcd(0X0C);//liga display :0XC0 -> cursor desligado, 0X0F ->intermitente,0E -> fixo ,08 -> desligado.
       RS = 1; //habilita dados        

}
//===================================================================================
//Função:    _impri_caracter_lcd
//Parâmetros: char cCaracter, -> caracter a ser escrito
//            int iPos_inicial, indica em qual posição deve  colocar o caracter
//            int iLinha, indica qual o a linha do display vai usar
//Retorno:   não tem retorno.
//Descrição: usada para escrever um caracter em um display de lcd.
//===================================================================================
void impri_caracter_lcd(unsigned char ucCaracter,int iPos_inicial ,unsigned char ucLinha)
{
      switch(ucLinha)
           {
            case '1' :{escreve_LCD(0X80 + iPos_inicial,'0');}break;//linha1
            case '2' :{escreve_LCD(0XC0 + iPos_inicial,'0');}break;//linha2
            case '3' :{escreve_LCD(0X94 + iPos_inicial,'0');}break;//linha3
            case '4' :{escreve_LCD(0XD4 + iPos_inicial,'0');}//linha4
            }
       escreve_LCD(ucCaracter,'1');
}
 

//===================================================================================
//Função:    _impri_lcd
//Parâmetros: const char *ccFrase, mensagem que deve ser escrita usando "(aspas) para delimitar o tamanho
//            int iPos_inicial, indica em qual posição deve começar a colocar a mensagem
//            int iLinha, indica qual o a linha do display vai usar
//Retorno:   não tem retorno.
//Descrição: usada para escrever uma string(vetor de caracteres) em um display de lcd com parametro string.
//===================================================================================
//void impri_lcd(unsigned char frase[],int iPos_inicial ,unsigned char ucLinha)//  cuidado para não exceder a quantidade de caracter
void impri_lcd(int iPos_inicial ,unsigned char ucLinha)
{
      unsigned int indice=0;
      unsigned int tamanho = strlen(Buffer_lcd);
      switch(ucLinha)
           {
            case '1' :{escreve_LCD(0X80 + iPos_inicial,'0');}break;//linha1
            case '2' :{escreve_LCD(0XC0 + iPos_inicial,'0');}break;//linha2
            case '3' :{escreve_LCD(0X94 + iPos_inicial,'0');}break;//linha3
            case '4' :{escreve_LCD(0XD4 + iPos_inicial,'0');}//linha4
            }
      while(indice<tamanho)
       {
          if(Buffer_lcd[indice]!='\0')
          {           
            if((Buffer_lcd[indice]!='"') && (indice<21))//dados
                        {
                          escreve_LCD(Buffer_lcd[indice],'1');
                        }
          }
          else
          {
              indice = tamanho;//finaliza impressão
          }
       indice++;
       }
}

void Read_ADC (void)
{
       int lido_adc;
       float temp,tensao;
       unsigned int parte_inteira;                //declaração de variável local
       unsigned int parte_decimal;                //declaração de variável local
       //////////Lê tensão////////////////////
        ADCON0 = 0X05; 
        _delay_us(40);//espera tensão estabilizar
        ADCON0bits.GO = 1; //RA1
        while (ADCON0bits.DONE == 1); //espera finalizar leitura
       // lido_adc = ((((int)ADRESH <<8)|(ADRESL))&0x03FF); //Lê os valores em hexa
        lido_adc =  (((int)ADRESH)<<8)|(ADRESL);
        temp = (float)((lido_adc*5.0)/1023);       
    //*******************************************************************
        if(temp < 0)                    //valor é menor que 0?
        { temp = temp * (-1);        //inverte o sinal de float
        }
    //*******************************************************************
        parte_inteira = (int)temp;            //pega parte inteira do valor
        tensao =temp;
    //*******************************************************************
        parte_decimal =(unsigned int)((temp - parte_inteira) * 100);    //resgata parte fracionária do valor ,2 casa decimais
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(0,'2');
        
        //////////Lê corrente ////////////////////
       ADCON0 = 0X01; ///liga RA0        
        _delay_us(40);//espera tensão estabilizar
        ADCON0bits.GO = 1; //RA1
        while (ADCON0bits.DONE == 1); //espera finalizar leitura
       // lido_adc = ((((int)ADRESH <<8)|(ADRESL))&0x03FF); //Lê os valores em hexa
        lido_adc =  (((int)ADRESH)<<8)|(ADRESL);
        temp = (float)((lido_adc*5.0)/1023);       
    //*******************************************************************
        if(temp < 0)                    //valor é menor que 0?
        { temp = temp * (-1);        //inverte o sinal de float
        }
    //*******************************************************************
        parte_inteira = (int)temp;            //pega parte inteira do valor        
    //*******************************************************************
        parte_decimal =(unsigned int)((temp - parte_inteira) * 100);    //resgata parte fracionária do valor ,2 casa decimais
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(6,'2');
        temp = tensao*temp;
        parte_inteira = (int)temp;            //pega parte inteira do valor 
        parte_decimal =(unsigned int)((temp - parte_inteira) * 10);//somente uma casa decimal
        sprintf(Buffer_lcd,"%u.%u",parte_inteira,parte_decimal);        //converte valor em string e armazena no vetor buf    
        impri_lcd(12,'2');
}


A simulação do proteus:


     Muito obrigado,e até a próxima!

quinta-feira, 31 de janeiro de 2019

PWM de 20KHZ com o PIC 12F683 - Saída variável de 0 a 10V.


          Olá pessoal que acompanha o blog! depois de um bom tempo sem nenhum post, temos mais um projeto realizado por nosso colaborador Renato Lôbo, que nos traz um circuito que controla a saída por meio do uso da modulação PWM.
           O funcionamento se baseia na leitura da tensão que vem do potenciômetro(que neste caso varia de 0 a 5V) e então o microcontrolador irá gerar um sinal de pwm na frequência de 20Khz  e com largura de pulso proporcional a entrada(ou seja para  0 a 5V temos 0 a 10V) veja Figura 1, O filtro passa baixas  na saída(R3 e C2) faz com que o sinal de onda quadrada se aproxime do sinal analógico, dando uma "suavizada" no contorno do sinal  que tera um ganho de potencia por meio do transistor BC337.

Figura 1 - sinal gerado pelo microcontrolador.

 O código fonte.

Paste your////////////////////////////////////////////////////////////////////////////////
//              Projeto: PWM de 20Khz                                         //
//                 Nome: Renato Lôbo Rodrigues                                //
//                 Data: 27/01/19                                             //
//                Email: lobosoft@oi.com.br                                   //
////////////////////////////////////////////////////////////////////////////////
#include <12F683.h>
#use delay (clock = 8Mhz)
//Configure os fusíveis em acordo com o pic selecionado
#fuses NOWDT
#fuses PUT
#fuses NOBROWNOUT
#fuses NOMCLR
#fuses INTRC_IO
#fuses PROTECT

//Estes registros encontra-se nas funções especiais de cada modelo de pic.
#bit tris_bot1 = 0x85.0 //direção do pino A0
#bit bot1      = 0x05.0 //pino A0

#bit tris_bot2 = 0x85.1 //direção do pino A1
#bit bot2      = 0x05.1 //pino A1

#bit tris_pwm = 0x85.2 //direção do pino A2
#bit p_pwm    = 0x05.2 //pino A2

#bit tris_led = 0x85.5 //direção do pino A5
#bit led      = 0x05.5 //pino A5

#bit tris_adc = 0x85.4 //direção do pino A4
#bit adc      = 0x05.4 //pino A5

//Registro dos comparadores
#byte CMCON0            = 0x19          //Controle dos comparadores

//Registros do ADC
#byte ADCON0            = 0x1F          //Controle do ADC
#bit  ADCON0_GO_DONE    = ADCON0.1      //Status de conversão
#byte ANSEL             = 0x9F          //Selecioa os pinos Analógicos
#byte ADRESH            = 0x1E          //endereço do byte mais significativo
#byte ADRESL            = 0x9E          //endereço do byte menos significativo


//Registros de interrupção
#byte INTCON            = 0x0B          //Controle de interrupção
#bit  INTCON_GIE        = INTCON.7      //Registro geral
//#bit  INTCON_PEIE       = INTCON.6    //Interrupção de periferico

//Registros de PULL_UP
#byte OPTION_REG        = 0x81          //Registros de Opção 
#bit  OPT_REG_GPPU      = OPTION_REG.7  //habilitar ou desabilitar os Pull_up dos pinos 
#byte WPU               = 0x95          //Configurar os pinos que vão ser habilitados

//Registros do CCP1
#byte CCP1CON           = 0x15          //Registro do CCP1
//#bit  CCP1CON_DC1B1     = CCP1CON.5     //Bit 1 para byte menos significativo
//#bit  CCP1CON_DC1B0     = CCP1CON.4     //Bit 0 para byte menos significativo
#byte CCPR1L            = 0x13          //Byte mais significativo

//Registros do Timer2 para PWM
#byte T2CON             = 0x12          //Controle do timer 2
#byte PR2               = 0x92          //periodo do PWM


int16 pwm = 0;

//______________________________________________________________________________
//Rotina principal
void main()
{
   int1  st1         = false;    //status do botão
   int1  st2         = false;    //status do botão
   int   toc         = false;    //inicia regulando no potenciometro
   int16 valor_adc   = 0;        //inicia com zero 
   
   tris_bot1         = 1;        //pino A0 como entrada
   tris_bot2         = 1;        //pino A1 como entrada
   tris_adc          = 1;        //pino A4 entrada analogica
   tris_pwm          = 0;        //pino A2 do pwm como saída
   pwm               = 0;        //inicia o pwm com zero
   tris_led          = 0;        //pino A5 do led como saída
   led               = 0;        //led apagado
   
   OPT_REG_GPPU   = 0;  //zero = habilita os pull-up 
   WPU            = 3;  //00000011 liga pul-up dos pinos A0 e A1
                        //||||||||_Pino A0
                        //|||||||_Pino A1
                        //||||||_Pino A2
                        //|||||_Não usado, pino A3 não tem Pull_up interno
                        //||||_Pino A4 
                        //|||_Pino A5
                        //||_dois bit não usado

   CMCON0     = 7;      //000000111 Comparadores Desligados
                        //|||||||||_Tres bits "um" desliga todos os comparador
                        //||||||_Não usado para esse caso
   
   ADCON0     = 141;    //10001101 Controle do ADC
                        //||||||||_liga ou desliga o ADC
                        //|||||||_Status de conversão, zero terminou a conversão 
                        //||||||_Tres bits para determminar o canal usado 
                        //|||_Não implementado
                        //||_VDD
                        //|_Formatado a direita
                        
   ANSEL       = 88;    //10001000  frequência de atualização e pino A4 como ADC
                        //||||||||_Quatro bit seta o pinos analogicos
                        //||||_Tres bits seta a frequencia de conversão
                        //|_Não usado

   INTCON_GIE  = 1;     //Habilita Registro Geral
   
   CCP1CON     = 12;    //00001100 Habilita o modo PWM 
                        //||||||||_Quatro bits define o uso do PWM do CCP1
                        //||||_Dois bit do Duty
                        //||_Não usado
                        
   CCPR1L      = 0;     //Byte mais significativo
 
   T2CON       = 4;     //00000100
                        //||||||||_2 bit prescaler do time 2 = 1
                        //||||||_ bit liga o timer2
                        //|||||_Quatro bit do Postscaler = 1
                        //|_não usado
                        
   PR2         = 49;    //49 calculado para PWM com frequência de 20 Khz


   //Setando o Duty
   //CCPR1L = pwm>>2;   //DUTY(;
   //CCP1CON = (pwm <<4) | 12;

   while(true)     //laço infinito
   {
      ADCON0_GO_DONE = 1;
      while(ADCON0_GO_DONE)//Espera até terminar a conversão analogica para digital  
      valor_adc = ((int16)ADRESH<<8)|(ADRESL); //Formatado a direita
      
      if(!toc) pwm =  valor_adc/5.0895;   //1023/201

      CCPR1L = pwm>>2;                    //Duty
      //CCP1CON = (pwm<<4) | 12;      //dois bits do Duty    
      CCP1CON = (pwm<<4) | 12;
      
      if ( bot1)   st1=false;
      if (!bot1 && st1==false)
      {
           st1=true;
           led = 1 ; //Acende o led1
           if(pwm>=10) pwm=pwm-10;
           if(pwm<=10)pwm=0;
           CCPR1L = pwm>>2;               //Duty
           CCP1CON = (pwm <<4) | 12; //dois bits do Duty            
           toc = true;
           delay_ms(10);
           led = 0 ;
      }
      if ( bot2)   st2=false;
      if (!bot2 && st2==false)
      {
           st2=true;
           led = 1 ; //Acende o led1
           if(pwm<191) pwm=pwm+10;
           if(pwm>=191)pwm=201;
           CCPR1L = pwm>>2;               //Duty
           CCP1CON = (pwm<<4) | 12; //dois bits do Duty          
           delay_ms(10);
           led = 0 ;
      }
      if(!bot1 && !bot2) toc = false;
   }
} text here.

Esquemático do projeto:


PCB - do protótipo.
              O protótipo final ficou conforme a figura a seguir:


Obrigado e até a próxima!

quarta-feira, 7 de fevereiro de 2018

NODEMCU+MQTT+ANDROID = IOT (PARTE2)


        Olá, pessoal que acompanha o blog lhes trago uma versão melhorada do ultimo exemplo postado, para isto organizei os componentes na protoboard e coloquei um botão, e um sensor LM35 para medir temperatura.Veja abaixo como ficou o novo protótipo.
//colocar foto
         Apesar do LM35 funcionar 4 a 30V(segundo o datasheet) com 3,3V funcionou bem(pelo menos pra medir temperatura ambiente,assim não precisou de nenhum circuito externo além do sensor.
         Usei um botão do tipo NA de forma que a entrada selecionada ficasse o tempo todo em nível alto indo para nível baixo quando pressionado.
        Adicionei mais um led(led amarelo) para indicar que o programa está rodando.Note que é possível monitorar pela porta serial tudo que acontece(caso queira).

O Código fonte :
//Autor: Aguivone    -  microcontroladores-C
//Descricao: Placa para acionar 4 reles usado um servidor MQTT.
//Data: 18/01/18
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <ESP8266WiFi.h>
#include <PubSubClient.h> // essa lib deve ser adicionada em seu programa do arduino
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//variaveis usadas na inicialização da wifi
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const char* ssid = "nome da wifi"; //Aqui o nome da sua rede local wifi
const char* password =  "senha"; // Aqui a senha da sua rede local wifi
const char* mqttServer = "algumacoisa.cloudmqtt.com"; // Aqui o endereço do seu servidor fornecido pelo site 
const int mqttPort =16000; // Aqui mude para sua porta fornecida pelo site
const char* mqttUser = "xxxxxx"; //  Aqui o nome de usuario fornecido pelo site
const char* mqttPassword = "hfjuytsgeh"; //  Aqui sua senha fornecida pelo site
unsigned long  tempo_rot = 1000;// aprox 1s
unsigned int est_ant_bot = 0;//guarda estado do botão pra não enviar a todo momento uma nova informação
WiFiClient espClient;
PubSubClient client(espClient);
/*
Equivalencia das saidas Digitais entre nodeMCU e ESP8266 (na IDE do Arduino)
-------------------------------------------------
NodeMCU / ESP8266  |  NodeMCU / ESP8266  |
D0 = 16            |  D6 = 12            |
D1 = 5             |  D7 = 13            |
D2 = 4             |  D8 = 15            |
D3 = 0             |  D9 = 3             |
D4 = 2             |  D10 = 1            |
D5 = 14            |                     |
-------------------------------------------------
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Definindo o nome dos pinos
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const int  LED_STATUS = 12; // led de status 
const int TEMP_LM35 = A0; // porta analogica
//////////////configura os pinos dos reles/////////////////////////////
const int RELE1 = 0; 
const int RELE2 = 4;
const int LED1 = 5;
const int LED2 = 14;
const int BOT  = 13;//botão
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//variaveis globais
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mqtt_callback(char* topic, byte* dados_tcp, unsigned int length);///dados_tcp = payload


void setup() { 
  pinMode(RELE1, OUTPUT);
  pinMode(RELE2, OUTPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED_STATUS, OUTPUT);
  pinMode(BOT, INPUT);
  digitalWrite(RELE1,LOW);//desliga todos os reles
  digitalWrite(RELE2,LOW);
  digitalWrite(LED1,LOW);
  digitalWrite(LED2,LOW);
 
  Serial.begin(115200);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) 
  {    //inicialmente pisca o led da placa do nodemcu(é a mesma do ESP8266).
     delay(100);
    Serial.println("Conectando a WiFi..");
  }
  Serial.println("Conectado!"); 
  client.setServer(mqttServer, mqttPort);//configura servidor com as informações passadas
  client.setCallback(callback);
 
  while (!client.connected()) {
    Serial.println("Conectando ao servidor MQTT...");
    
    if (client.connect("Placa_leds", mqttUser, mqttPassword ))//colocar aqui o nome do dispositivo cliente("Placa_leds")
    {
 
      Serial.println("Conectado ao servidor MQTT!");  
      digitalWrite(LED_STATUS,HIGH); 
 
    } else {
 
      Serial.print("Falha ao conectar ");
      digitalWrite(LED_STATUS,LOW);
      Serial.print(client.state());
      delay(2000);
 
    }
  }
  
  client.publish("Status - placa_rele","Reiniciado!");
  client.publish("Placa_reles","Em funcionamento!");
  client.subscribe("RELE"); ///envia autorização para trabalhar com os topicos abaixo
  client.subscribe("LED"); 
  client.subscribe("TEMP"); 
  client.subscribe("BOT"); 
}
 //////////////////
void callback(char* topic, byte* dados_tcp, unsigned int length) 
{
   String msg ; // cria variavel que será responsavel pelo tratamento das informações
   for(int i = 0; i < length; i++) //converte array de bytes em string
    {  char c = (char)dados_tcp[i];
       msg += c;
    } 
   digitalWrite(LED_STATUS,LOW);
   delay(100);   
   digitalWrite(LED_STATUS,HIGH); //só pra indicar que houve recepção 
   Serial.print("\n\r topico:");//sempre será o escolhido no subscribe
   Serial.print(topic);   
   Serial.print("\n\r Pacote recebido:");
   Serial.print(msg);
   if (strcmp(topic, "RELE") == 0)//recebeu comando para trabalhar com o dispositivo relé
   {
    for (int i = 0; i < length; i++) // Varre o vetor(array) inteiro do pacote recebido 
        {         
          //toma ação dependendo da string recebida:      
      
          if (msg.equals("L1"))
          {
              digitalWrite(RELE1, HIGH);
              
          }
          if (msg.equals("D1"))
          {
              digitalWrite(RELE1, LOW);
            
          }
          if (msg.equals("L2"))
          {
              digitalWrite(RELE2, HIGH);
             
          }
          if (msg.equals("D2"))
          {
              digitalWrite(RELE2, LOW);
              
          }
        }
   }
   if (strcmp(topic, "LED") == 0)//recebeu comando para trabalhar com o dispositivo led
   {
       for (int i = 0; i < length; i++) // Varre o vetor(array) inteiro do pacote recebido 
        {         
          //toma ação dependendo da string recebida:      
      
          if (msg.equals("L1"))
          {
              digitalWrite(LED1, HIGH);
             
          }
          if (msg.equals("D1"))
          {
              digitalWrite(LED1, LOW);
              
          }
          if (msg.equals("L2"))
          {
              digitalWrite(LED2, HIGH);
             
          }
          if (msg.equals("D2"))
          {
              digitalWrite(LED2, LOW);
             
          }
        }
   }
 
}
 
void loop() {        
     client.loop();
     if(tempo_rot==500)
     {
      digitalWrite(LED_STATUS,LOW);
     }
     if(tempo_rot<1)
     {      
     tempo_rot = 1000;//reinicia contagem
     digitalWrite(LED_STATUS, HIGH);
     float Temperatura = analogRead(TEMP_LM35);    
     Temperatura = (Temperatura/1024.0) * 330;//converte para graus celsius
     Serial.print("\n\r temperatura :");     
     Serial.println(Temperatura);
     char data[6];
     char *valor = dtostrf(Temperatura,5,2,data);//float,tamanho da string,numero de casas decimais,variavel temporaria a ser usada
     client.publish("TEMP",valor);  
     if(digitalRead(BOT) == LOW)//botão pressionado?
        {
           if(est_ant_bot == 1)//botão não estava pressionado
           {
             client.publish("BOT","ON");
           }
          est_ant_bot = 0;
        }
        else
        {
          if(est_ant_bot == 0)//botão já estava pressionado
           {
             client.publish("BOT","OFF");
           }
          est_ant_bot = 1;
        }
     }
     delay(1);
     tempo_rot--;
     
}

          Quanto ao aplicativo do android esqueci de mencionar que é possível trocar os ícones ,então para este vídeo troquei eles e acrescentei mais um ícone para mostrar o status do botão.No vídeo e demonstrado o uso de um outro app do android(MQTTDASHBOAD) para plotar o gráfico da temperatura.Então vamos ao vídeo abaixo:

Vídeo de demonstração:




Até a próxima pessoal!

segunda-feira, 5 de fevereiro de 2018

NodeMcu + MQTT + ANDROID = IOT.

            Olá pessoal que acompanha o blog! nos últimos anos temos ouvido falar muito de "internet das coisas" (IOT = internet of things) , uma arquitetura pensada na interação entre dispositivos via internet e estes com o usuário. Este será o primeiro post sobre o assunto e vamos começar com algo simples, vamos colocar 2 leds para representar o acionamento de 2 lâmpadas , e mais 2 leds para representar o acionamento de 2 relés que podem estar ligados a qualquer carga.Isto será feito através de um servidor nas nuvens dedicado a IOT(geralmente chamado de "BROKER"),dentro do conceito do  BROKER existe 2 tipos de informação o publish e o subscribe  que se refere ao envio e o recebimento de dados respectivamente,veja a figura a seguir.
          Apesar do NodeMcu ser o dispositivo a ser acionado e portanto deveria apenas receber dados (subscribe) mas ele também informa quais os tópicos(tipo de dispositivo acionado) que será usado naquela conexão, alem de poder enviar status de controle, sendo por este motivo representado como uma comunicação de envio e recepção.O  protocolo usado para fazer tudo funcionar é chamado de MQTT(Message Queue Telemetry Transport) que será o responsavel por fazer as máquinas conversarem entre si M2M(Machine to Machine).
         Para fazer toda a "mágica" acontecer é preciso ter instalado o software do Arduino com as libs do ESP8266,Abra a janela de preferências na interface Arduino e digite no campo “Additional Board Manager URLs” o seguinte endereço:  http://arduino.esp8266.com/stable/package_esp8266com_index.json , depois é só instalar as bibliotecas indo na aba do gerenciador de placas do Arduino, para usar o MQTT será necessario adicionar a biblioteca "PubSubClient" que pode ser baixada(aqui) e colocada dentro da pasta "libraries" nos arquivos de instalação do Arduino, deve ficar em algo assim "C:\Arduino\arduino-1.8.5\Sketchbook\libraries\PubSubClient" eu preferi deixar a pasta do executável fora da pasta padrão do windows para não ter problemas de acesso a arquivos por parte do programa arduino. Estando com tudo corretamente preparado é só rodar o código fonte que estará anexado a este post.
        Para usar o servidor MQTT vc deve criar seu cadastro(existem vários destes procure o que achar melhor),no meu caso usei o "cloudMQTT", apenas uma obrsevação no video errei ao dizer que os servidores estavam localizados nos EUA, na verdade um fica lá(na Virginia) e o outro na Europa(Irlanda), no  vídeo de demostração vou dar mais detalhes das configurações dele.
       Para usar o Android ou qualquer outro Sistema operacional para Smartphone pode se usar uma solução pronta(existem diversas opções) para gerenciar seu dispositivo, eu usei o "MQTT Dash", no vídeo de demostração abaixo vou dar mais detalhes.
       Para melhor acompanhamento do que está acontecendo com o modulo tudo que é feito é também enviado via porta serial (emulada), ou seja através de um terminal serial RS232 podemos acompanhar todos os passos do circuito.Observe que no codigo o comando para ligar e desligar tanto os reles quanto as lâmpadas(led) é o mesmo, ou seja posso padronizar os mesmos comandos para dispositivos diversos não necessitando ter vários comandos(um pra cada dispositivo).
       O circuito elétrico  de testes da protoboard ficou assim:
        Mas você deve estar se perguntando por que usar um BROKER(servidor nas nuvens) se poderia usar uma simples pagina HTTP?A resposta é devido a 2 fatores, o primeiro é que usando um webservidor você pode acessar seu dispositivo de qualquer ponto do planeta sem a necessidade de fazer muitas configurações(caso contrario precisaria de liberar a porta de seu modem e usar um serviço de DDNS ou VPN).O segundo motivo é que usando um protocolo como o MQTT que foi pensado,preparado e padronizado para o uso de IOT a comunicação é muito mais rápido do que usar uma pagina HTTP.
O código fonte:

//Autor: Aguivone    -  microcontroladores-C
//Descricao: Placa para acionar 4 leds usado um servidor MQTT.
//Data: 18/01/18
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <ESP8266WiFi.h>
#include <PubSubClient.h> // essa lib deve ser adicionada em seu programa do arduino
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//variaveis usadas na inicialização da wifi
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const char* ssid = "nome da wifi"; //Aqui o nome da sua rede local wifi
const char* password =  "senha"; // Aqui a senha da sua rede local wifi
const char* mqttServer = "algumacoisa.cloudmqtt.com"; // Aqui o endereço do seu servidor fornecido pelo site 
const int mqttPort =16000; // Aqui mude para sua porta fornecida pelo site
const char* mqttUser = "xxxxxx"; //  Aqui o nome de usuario fornecido pelo site
const char* mqttPassword = "hfjuytsgeh"; //  Aqui sua senha fornecida pelo site

WiFiClient espClient;
PubSubClient client(espClient);
/*
Equivalencia das saidas Digitais entre nodeMCU e ESP8266 (na IDE do Arduino)
-------------------------------------------------
NodeMCU / ESP8266  |  NodeMCU / ESP8266  |
D0 = 16            |  D6 = 12            |
D1 = 5             |  D7 = 13            |
D2 = 4             |  D8 = 15            |
D3 = 0             |  D9 = 3             |
D4 = 2             |  D10 = 1            |
D5 = 14            |                     |
-------------------------------------------------
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Definindo o nome dos pinos
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const int  LED_STATUS = 2; // led de status(estou usando o led que já vem no modulo esp. 
const int  ANALOGICA = A0; // porta analogica
//////////////configura os pinos dos reles/////////////////////////////
const int RELE1 = 0; 
const int RELE2 = 4;
const int LED1 = 5;
const int LED2 = 14;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//variaveis globais
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void mqtt_callback(char* topic, byte* dados_tcp, unsigned int length);///dados_tcp = payload


void setup() { 
  pinMode(RELE1, OUTPUT);
  pinMode(RELE2, OUTPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  digitalWrite(RELE1,LOW);//desliga todos os reles
  digitalWrite(RELE2,LOW);
  digitalWrite(LED1,LOW);
  digitalWrite(LED2,LOW);
 
  Serial.begin(115200);
 
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) 
  {    //inicialmente pisca o led da placa do nodemcu(é a mesma do ESP8266).
     delay(100);
    Serial.println("Conectando a WiFi..");
  }
  Serial.println("Conectado!"); 
  client.setServer(mqttServer, mqttPort);//configura servidor com as informações passadas
  client.setCallback(callback);
 
  while (!client.connected()) {
    Serial.println("Conectando ao servidor MQTT...");
    
    if (client.connect("Placa_leds", mqttUser, mqttPassword ))//colocar aqui o nome do dispositivo cliente("Placa_leds")
    {
 
      Serial.println("Conectado ao servidor MQTT!");  
      digitalWrite(LED_STATUS,HIGH); 
 
    } else {
 
      Serial.print("Falha ao conectar ");
      digitalWrite(LED_STATUS,LOW);
      Serial.print(client.state());
      delay(2000);
 
    }
  }
  
  client.publish("Status - placa_rele","Reiniciado!");
  client.publish("Placa_reles","Em funcionamento!");
  client.subscribe("RELE"); ///envia autorização para trabalhar com os topicos led e relé
  client.subscribe("LED"); 
}
 //////////////////
void callback(char* topic, byte* dados_tcp, unsigned int length) 
{
   String msg ; // cria variavel que será responsavel pelo tratamento das informações
   for(int i = 0; i < length; i++) //converte array de bytes em string
    {  char c = (char)dados_tcp[i];
       msg += c;
    } 
   digitalWrite(LED_STATUS,LOW);
   delay(100);   
   digitalWrite(LED_STATUS,HIGH); //só pra indicar que houve recepção 
   Serial.print("\n\r topico:");//sempre será o escolhido no subscribe
   Serial.print(topic);   
   Serial.print("\n\r Pacote recebido:");
   Serial.print(msg);
   if (strcmp(topic, "RELE") == 0)//recebeu comando para trabalhar com o dispositivo relé
   {
    for (int i = 0; i < length; i++) // Varre o vetor(array) inteiro do pacote recebido 
        {         
          //toma ação dependendo da string recebida:      
      
          if (msg.equals("L1"))
          {
              digitalWrite(RELE1, HIGH);
             
          }
          if (msg.equals("D1"))
          {
              digitalWrite(RELE1, LOW);
             
          }
          if (msg.equals("L2"))
          {
              digitalWrite(RELE2, HIGH);
              
          }
          if (msg.equals("D2"))
          {
              digitalWrite(RELE2, LOW);
              
          }
        }
   }
   if (strcmp(topic, "LED") == 0)//recebeu comando para trabalhar com o dispositivo led
   {
       for (int i = 0; i < length; i++) // Varre o vetor(array) inteiro do pacote recebido 
        {         
          //toma ação dependendo da string recebida:      
      
          if (msg.equals("L1"))
          {
              digitalWrite(LED1, HIGH);
              
          }
          if (msg.equals("D1"))
          {
              digitalWrite(LED1, LOW);
             
          }
          if (msg.equals("L2"))
          {
              digitalWrite(LED2, HIGH);
              
          }
          if (msg.equals("D2"))
          {
              digitalWrite(LED2, LOW);
             
          }
        }
   }
 
}
 
void loop() {        
     client.loop();
}

Vídeo de demonstração e algumas explicações:




            Espero ter ajudado a quem está iniciando neste fantástico mundo da tecnologia da internet das coisas(IOT).espero postar outros exemplos de uso em breve.

terça-feira, 9 de janeiro de 2018

Implementando um temporizador WIFI, com o NodeMcu.

Olá, hoje resolvi demonstrar como gravar o NodeMcu pela interface do arduino, para isto criei um servidor web que mantém um um led aceso conforme um tempo configurado na pagina web que está rodando dentro do próprio modulo, veja que do mesmo modo que é gravado o modulo ESP8266 também é gravado o NodeMcu(o que muda é fisicamente,pois o NodeMcu já vem com todo o hardware necessário para seu funcionamento o que reduz custos e facilita a montagem, principalmente para leigos em eletrônica ),veja que o tempo não é muito preciso pois usa delay de rotinas.
       Este é só o começo da serie de projetos que virão a partir do NodeMcu, em breve postarei novos códigos com mais recursos,por hora fiquem com este exemplo.

O código fonte:

#include <dummy.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>//caso use o modo servidor
#include "FS.h"
WiFiServer server(80);//usa porta 80
const int  LED_STATUS = 2; // led de status(estou usando o led que já vem no modulo esp. 
const int  ANALOGICA = A0; // porta analogica

//////////////reles/////////////////////////////
const int RELE1 = 5; // neste exemplo vou usar apenas o rele 1
const int RELE2 = 4;
const int RELE3 = 10;
const int RELE4 = 15;

int tempo_pisca_led=500;
long liga_timer=0;
int tempo = 1;//padrão 1s

///////////////////////////////////////////////////////////////////
//////////configurações principais
///////////////////////////////////////////////////////////////////
void setup() 
{
  Serial.begin(115200);
  conf_pinos();  
  setupWiFi();
}
/////////////////////////////////////////////////////////////////////
///rotina prinicpal
/////////////////////////////////////////////////////////////////////
void loop() 
{
  rot_geral();
 // checa se tem algum dispositivo conectado!
  WiFiClient client = server.available();
  if (!client) 
  {return;}

  // Lê a primeir linha dos dados recebidos pelo pacote ethernet
  String req = client.readStringUntil('\r');
  client.flush(); //limpa buffer de recepção
  Serial.println("recebeu pag.");
  // prepara pagina ethenet
  String buf = "";//cria uma string para colocar a pagina web
  //vai adicionando linhas a string criada
  buf += "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\n";
  buf += "<h1> Servidor Web com ESP8266 </h1>";
  buf += "<h3> Temporizador - configure um tempo de 00 a 60 segundos.</h3>";
  buf += "<h3> coloque os numero no formato XX(por exemplo 1 = 01..</h3>";
  buf += "<h3><p>Iniciar: <a href=\"?b1_on\"><button>ON</button></a> <a href=\"?b1_off\"><button>OFF</button></a></p><br></h3>"; 
  buf += "<form><h3>Segundos: <input type=text name=\"tempo\"\"value=\"mm\"size=3 maxlength=2></h3>";  
  buf += "<h3><input type=\"submit\"  value=\"Configurar. \"></h3>"; 
  buf += "</form><marquee direction=\"right\"> Microcontroladores-c - Temporizador Web </marquee></html>\n";
  client.print(buf);//envia os dados pela wifi
  client.flush();  
  ///avalia o retorno da pagina HTTP
  if (req.indexOf("b1_on") != -1)
    {
      liga_timer=tempo*5;//pois como o pisca é mais rapido e leva 200 ms por incremento deve multiplicar por 5
      Serial.println("Acionou timer tempo:");
      Serial.print(liga_timer,DEC);
    }
  if (req.indexOf("b1_off") != -1)
    {
      liga_timer=0;
      digitalWrite(RELE1, LOW);
      Serial.println("rele desligado!");
    }  
  if(req.indexOf("tempo=") != -1)
  {
    int pos = req.lastIndexOf("tempo=");
    Serial.println("tempo");
    Serial.print('=');
    Serial.print(req[pos+6]);
    Serial.print(req[pos+7]);    
    if((char_to_int(req[pos+6]))*10 + char_to_int(req[pos+7])<61) 
    { tempo = (char_to_int(req[pos+6]))*10 + char_to_int(req[pos+7]) ; 
      Serial.println("foi gravado :");    
      Serial.print(tempo,DEC);
    } //se tempo menor que 60 atualiza valor   
  } 
  //cliente desconectado
  // a cada requisição a pagina é enviada e o cliente é desconectado
}   
 
unsigned int char_to_int(char val)
 {
    int valor =0;
    if((val>47)||(val<58))
    {
      valor = val-48;
    }    
    return(valor);
 }
 
void rot_geral()
{
      if(liga_timer>0)
      {          
          liga_timer--;
          if(liga_timer == 0)
          {
            // fim do tempo
            digitalWrite(RELE1, LOW);
            Serial.println("rele desligado!");
          }
          else
          {
            digitalWrite(RELE1, HIGH);// liga rele 
          }
          digitalWrite(LED_STATUS,HIGH);      
          delay(100);
          digitalWrite(LED_STATUS,LOW);
          delay(100);
      }
      else
      {
          digitalWrite(LED_STATUS,HIGH);      
          delay(tempo_pisca_led);
          digitalWrite(LED_STATUS,LOW);
          delay(tempo_pisca_led);
      }
     return;
}

 
  ////////////////////////////////////////////////////////////////////
//configura os pinos
////////////////////////////////////////////////////////////////////
void conf_pinos()
{  
  pinMode(9, INPUT);//sempre será entrada
  pinMode(LED_STATUS, OUTPUT);
  digitalWrite(LED_STATUS, LOW);
  pinMode(RELE1, OUTPUT);
  digitalWrite(RELE1, LOW);
  pinMode(RELE2, OUTPUT);
  digitalWrite(RELE2, LOW);
  pinMode(RELE3, OUTPUT);
  digitalWrite(RELE3, LOW);
  pinMode(RELE4, OUTPUT);
  digitalWrite(RELE4, LOW);
   return;
}

/////////////////////////////////////////////////////////////////////////
// Parâmetros da WiFi  //
////////////////////////////////////////////////////////////////////////
void setupWiFi()
{
    //////////////////////
    // definições da WiFi  //
    //////////////////////
  const char* WiFi_Senha = "123456789";//senha que você quer usar(deve ser em branco(aberta) ou maior que 8 caráteres,senão não funciona e não troca o nome da wifi)
  const char*  WiFi_Nome = "Microcontroladores-c";//nome que você quer dar a sua rede 
  IPAddress ip(192,168,50,4);//ok
  IPAddress gateway(192,168,50,1);//ok
  IPAddress subnet(255,255,255,0);//ok
  //////inicializa a wifi//////////////////////////////////////////////    
  uint8_t mac[WL_MAC_ADDR_LENGTH];
  WiFi.softAPmacAddress(mac);//mac qualquer pra testar
  WiFi.softAPConfig(ip, gateway, subnet);
  WiFi.softAP(WiFi_Nome, WiFi_Senha); 
 // WiFi.mode(WIFI_AP);//modo acess point(cliente)   
   WiFi.mode(WIFI_AP_STA);//modo acess point e servidor  
   WiFi.begin();  
   server.begin();   
}

A demonstração do código funcionando pode ser visto no vídeo abaixo :

Até a próxima!



segunda-feira, 25 de dezembro de 2017

Gravador de pic - monte você mesmo!

Olá, hoje será abordado um gravador de pic, que foi montado pelo colaborador Renato lobo e funcionou tranquilamente ele consiste de uma placa contendo um microcontrolador 18F2550,devido a sua simplicidade resolvi juntamente com o Renato postar este projeto. Os aquivos para gravação do microcontrolador e o projeto do Eagle estão disponíveis  AQUI.

Esquemático:


 As placas do protótipo montado:

Demonstração da tela do pc no momento da gravação de firmware:

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