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

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!