lude <SPI.h>#include <Ethernet.h>//PINOS UTILIZADOS (SAIDA)int saidaLuz = 13; //PINO DAS LUZESint saidaTv = 5; //PINO DA TB//PINOS UTILIZADOS (VOLTA)int botaoLuz = 32;//ESTADO DO APARELHOS ( PINOS )boolean estadoLuz = false;boolean estadoTV = false;// MAC E IP DO ARDUINObyte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02};IPAddress ip(192, 168, 1, 3);//INICIA O SERVER NA PORTA 80EthernetServer server(80);void setup() { //PINOS DE SAIDA pinMode(saidaLuz,OUTPUT); pinMode(saidaTv,OUTPUT); //PINOS DE ENTRADA pinMode(botaoLuz,INPUT); //AGUARDA CONEXAO SERIAL Serial.begin(9600); while (!Serial) {;} //INICIA O SERVIDOR; Ethernet.begin(mac,ip); server.begin(); Serial.print("server is at "); Serial.println(Ethernet.localIP());}void loop() {if(digitalRead(botaoLuz) == HIGH || estadoLuz == true){ digitalWrite(saidaLuz,HIGH); estadoLuz = true; }else if(digitalRead(botaoLuz) == LOW || estadoLuz == false){ digitalWrite(saidaLuz,LOW); delay(1000); estadoLuz = false; }// listen for incoming clients EthernetClient client = server.available(); if (client) { // an http request ends with a blank line boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.println(c); // if you've gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == '\n' && currentLineIsBlank) { // send a standard http response header client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); // the connection will be closed after completion of the response client.println(); client.println("<!DOCTYPE HTML>"); client.println("<html>");client.println("<head>");client.println("<title>Automação Residencial</title>");client.println("<link rel=\"stylesheet\" href=\"botoes.css\" type=\"text/css\" />");client.println("<style>");client.println("@font-face { font-family: Century; src: url('GOTHIC.ttf');}");client.println("body{font-family: Century; background: rgb(51,51,51); padding:20px;}");client.println("*{ color:rgb(255,255,255);}");/*INICIO DA CONFIGURAÇÃO DOS RETANGULOS*/client.println(".tile img{ width:56px; margin:20px 22px 0 22px;}");client.println(".tileLargo img { margin:20px 77px 0 77px;}");client.println(".tile{ height:100px; width:100%; text-align:center; float:left; margin-top:5px;}");client.println(".amarelo{ background:#DAA520;}");client.println(".vermelho{ background:#CD0000;}");client.println(".azul{ background:#4682B4;}");client.println(".verde{background-color: #2E8B57;}");client.println(".selecionado{ background-color: #483D8B;}");/*FIM DA CONFIGURAÇÃO DOS RETANGULOS*//*INICIO DAS CONFIGURAÇÕES DOS COMODOS*/client.println(".comodos{ position:absolute; top:0; left:0; background:RGBA(0,0,0,0,1); width:100%; height:auto;}");client.println(".tabelas{ width:100%; text-align:center;}");client.println(".comodosOpen{ width:100%; height:30px; line-height:30px; text-align:center; background:RGBA(255,255,255,1); margin-top:5px; color:RGBA(0,0,0,1);}");/*FIM DACONFIGURAÇÃO DOS COMODOS*/client.println("</style>");client.println("<script language=\"javascript\" src=\"jquery.js\"></script>");client.println("<script language=\"javascript\">");client.println("$(document).ready(function(e) {");client.println("$(\"#sala\").hide();");client.println("$(\"#cozinha\").hide();");client.println("});");client.println("function mostraJanela(local){");client.println("$(\"#\"+local).show();");client.println("$(\"#\"+local+\" #close\").click(function(){");client.println("$(\"#\"+local).hide();");client.println("});");client.println("}");client.println("function fazFuncao(endereco){");client.println("window.location(endereco);");client.println("alert(endereco);");client.println("}");client.println("</script>");client.println("</head>");client.println("<body>");client.println("<h1 align=\"center\">Automação Residêncial</h1>");client.println("<a href=\"#\" onClick=\"mostraJanela('sala');\">");client.println("<div class=\"tile amarelo\">");client.println("<img src=\"imagens/sala.png\" alt=\"Sala\"/>");client.println("<span>Sala</span></div>");client.println("</a>");client.println("<a href=\"#\" onClick=\"mostraJanela('cozinha');\">");client.println("<div class=\"tile azul\">");client.println("<img src=\"imagens/imgCozinha.png\" alt=\"Cozinha\"/>");client.println("<span>Cozinha</span></div>");client.println("</a>");client.println("<a href=\"#\">");client.println("<div class=\"tile vermelho\">");client.println("<img src=\"imagens/quarto.png\" alt=\"Quarto\" />");client.println("<span>Quartos</span></div>");client.println("</a>");client.println("<a href=\"#\">");client.println("<div class=\"tile verde\">");client.println("<img src=\"imagens/piscina.png\" alt=\"Piscina\" />");client.println("<span>Piscina</span></div>");client.println("</a>");client.println("<a href=\"#\">");client.println("<div class=\"tile amarelo\">");client.println("<img src=\"imagens/churrasqueira.png\" alt=\"Churrasqueira\" />");client.println("<span>Churrasqueira</span></div>"); client.println("</div>");client.println("</a>");//INICIO DAS DIVS DO COMODO DA SALAclient.println("<div id=\"sala\" class=\"comodos\">");client.println("<a href=\"#\" id=\"close\">Fechar Janela</a>");//Luzes Salaclient.println("<div id=\"luzSala\" class=\"comodosOpen\">");client.println("Luzes da Sala:");client.println("<label class=\"switch switch-green\">");client.println("<input type=\"checkbox\" onchange=\"fazFuncao('http://192.168.0.1/luzes');\" class=\"switch-input\">");client.println("<span class=\"switch-label\" data-on=\"On\" data-off=\"Off\"></span>");client.println("<span class=\"switch-handle\"></span>");client.println("</label>");client.println("</div>");//Som da Salaclient.println("<div id=\"somSala\" class=\"comodosOpen\">");client.println("Som da Sala:");client.println("<label class=\"switch switch-green\">");client.println("<input type=\"checkbox\" onchange=\"fazFuncao('http://192.168.0.1/som');\" class=\"switch-input\">");client.println("<span class=\"switch-label\" data-on=\"On\" data-off=\"Off\"></span>");client.println("<span class=\"switch-handle\"></span>");client.println("</label>");client.println("</div>");//Tv da Salaclient.println("<div id=\"tvSala\" class=\"comodosOpen\">");client.println("Tv da Sala:");client.println("<label class=\"switch switch-green\">");client.println("<input type=\"checkbox\" onchange=\"fazFuncao('http://192.168.0.1/tv')\" class=\"switch-input\">");client.println("<span class=\"switch-label\" data-on=\"On\" data-off=\"Off\"></span>");client.println("<span class=\"switch-handle\"></span>");client.println("</label>");client.println("</div>");client.println("</div>");/*FIM DAS DIVS DOS COMODOS*/if(estadoLuz == true){client.println("<label class=\"switch switch-green\">");client.println("<input type=\"checkbox\" onchange=\"fazFuncao(\'http://192.168.1.3/apagarLuz\')\" class=\"switch-input\" checked=\"checked\">");client.println("<span class=\"switch-label\" data-on=\"On\" data-off=\"Off\"></span>");client.println("<span class=\"switch-handle\"></span>");client.println("</label>");}else{client.println("<label class=\"switch switch-green\">");client.println("<input type=\"checkbox\" onchange=\"fazFuncao(\'http://192.168.1.3/acenderLuz\')\" class=\"switch-input\">");client.println("<span class=\"switch-label\" data-on=\"On\" data-off=\"Off\"></span>");client.println("<span class=\"switch-handle\"></span>");client.println("</label>");}client.println("</body>");client.println("</html>"); break;} if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); }}…
eracional) considerado ultrapassado (e isso já a mais de 30 anos). Assim seu uso em um Projeto Acadêmico, pode acabar sendo visto por alguns Professores, como algo inadequado. Apesar da sua justificativa (que vc me disse pelo chat) ser compreensível, não deixe de levar em consideração aspectos práticos como a extensa disponibilidade de AOs muito mais adequados a Projetos e custos envolvidos. Alguns aspectos tecnológicos podem também ser fundamentais, como variação de parâmetros com a temperatura, etc.
2) no estágio do Pré-Amplificador, "C7" garante que níveis DC não sejam amplificados, e também facilita o acoplamento do sinal de entrada (até certo ponto!). Ele também garante o mínimo de efeito do Offset de Tensão do AO na saída deste estágio.
Mas provavelmente seria melhor eliminar o ajuste do Ganho substituindo "POT_U1" por um Resistor fixo, e diminuir o Ganho neste estágio, e caso o Ganho não seja o que vc deseja, compense em um segundo estágio (e não no estágio de saída!). Isto seria muito facilitado se vc usar um CI mais "moderno", preferencialmente um que tem 4 AOs.
E se vc mantiver o ajuste de offset através do trimpot de 10k, vc precisará curto-circuitar "C7" durante esse ajuste, do contrário o ajuste não será possível, já que "C7" suprime o nível DC na saída.
3) observe que "C7" não pode ser do tipo polarizado, pois a tensão DC sobre ele pode ser tanto positiva como negativa. Já existem fartamente disponíveis Capacitores Cerâmicos nesta faixa de "C7", notadamente com dielétrico X5R (que são excelentes, e eu já usei muito em projetos recentes). Há também X7R, mas costumam ser mais caros pois são em menor disponibilidade para Capacitâncias dessa faixa. Claro, neste caso, usar dois Eletrolíticos de Alumínio em série (e em "contra-polaridade"), também resolve a questão da polaridade (mas há ressalvas nas frequências de áudio mais altas, pois Eletrolíticos de Alumínio se comportam como indutores a partir de alguns kHz).
4) o valor de 1M para "POT_U2" está totalmente inadequado para a entrada do LM386. Ocorre que a Impedância de Entrada do LM386 é de 50k, e "POT_U2" teria que ter um valor pelo menos 10 vezes menor, ou seja: algo em torno de 5k, senão o ajuste será extremamente difícil e até sem sentido. Este valor de 5k, não compromete o consumo de energia, uma vez que neste ponto do circuito, tanto o sinal de áudio como qualquer remanescente DC, ainda tem amplitudes muito baixas (no caso do sinal de áudio, o valor RMS será baixíssimo neste ponto).
5) tente manter o Ganho do LM386, no menor valor possível, que neste caso seria 20. Estágios de Saída de Potência devem ser concebidos para ganhos baixos (em alguns casos até mesmo ganho igual a 1), pois isso minimiza o efeito de ruídos da fonte de alimentação. O ganho atual de 200 que vc está usando, provavelmente vai trazer algumas surpresas ruins.
6) sobre o consumo de energia, sempre é possível otimizar. Mas circuitos totalmente analógicos tem um limite para isto, e este limite não costuma ser muito baixo, principalmente em amplificadores de áudio. Então não espere grande resultado alimentando seu Sistema com Pilhas ou Baterias, mesmo que "modernas".
Se seu problema for com o 60Hz presente na Fonte de Alimentação (mesmo um 60Hz de 1mV que mal seria visto em um Osciloscópio, pode ser terrível em um Amplificador de áudio), uma outra solução pode ser usada. Vc pode filtrar de forma exclusiva, a alimentação do Pré-Amplificador. Como o estágio Pré consome pouca energia, esta filtragem é totalmente viável. Há diversas formas de fazer isso, mais uma das mais eficientes é através de um Filtro Passa-Baixas usando um "Gyrator" (veja um artigo na Revista Elektor-Brasil 6 de 1986). Eu já usei isto e recomendo.
Agora respondendo sua pergunta sobre a Impedância do Estágio de Entrada: nesta topologia que vc está usando com o AO, a Impedância de Entrada já é a máxima possível. Veja: não são os 2M Ohms que vc deixou descrito no circuito. É muito maior que isso (certamente mais de 1Giga Ohm). Essa é uma característica da configuração "não-inversora" que vc está usando com o AO (e claro que "Zin" depende da frequência, mas para a faixa de áudio, isto é negligenciável).
Mas pode ser que seja vantajoso ter uma impedância mais baixa, por exemplo na casa das dezenas ou centenas de kilo-Ohms. Vai depender de quem é a sua fonte de sinal. Caso sua fonte de sinal tenha uma impedância de saída relativamente baixa, então vc não precisa ter um estágio Pré com uma Impedância de Entrada extremamente alta. Considere isto, pois quanto mais alta a Impedância em um Circuito, mais susceptível a ruídos será este Circuito.
Espero ter ajudado.
abrçs,
Elcids…
Adicionado por Elcids Chagas ao 2:24 em 12 agosto 2021
eferência para seu Sistema atual e suas futuras implementações. E depois de publicado este, irei fazer uma pequena melhoria em termos de desempenho na precisão do processo de medir o Fluxo (ou a RPM de algo em um Sistema), e publicarei aqui também.
Não deixe de ler todo o texto, pois há considerações importantes nele.
Lembrando que este tópico é praticamente uma continuação de outro do J. Leonardo, onde publiquei uma implementação inicial, e que está neste link: "Medição Vazão 1"
Mas antes, comentando sobre as fotos do seu Sistema, ficou bem legal, e tem até uma personalização identificando o equipamento ("Hidrômetro Digital"). Vi também que o módulo Bluetooth HC-05 já está conectado no Sistema, e sobre isto, comento no final do post.
Como de costume, quando possível implemento também uma simulação, o que permite que aqueles que não tem o Hardware em mãos, possam testar, fazer experimentações, e aprender com isso.
Para a simulação, aproveitei o Sistema que eu já tinha publicado antes naquele seu outro tópico. Apenas tive que acrescentar no Hardware, a parte dos dois Botões de Controle e dos dois LEDs de sinalização de alertas. Também fiz um pequeno ajuste no circuito que "emula" o Sensor de Fluxo, a fim de que ele tivesse uma faixa de ajuste da "Vazão" mais de acordo com a faixa que vc está usando. O arquivo para simulação no Proteus está anexado no final do post.
Então começando pela simulação, o circuito pode ser visto na figura a seguir:
(clique na figura para "zoom")
Na figura a seguir, pode-se ver o resultado após quase 14 segundos de simulação (este tempo é "virtual").
(clique na figura para "zoom")
No Display LCD é exibida a informação conforme selecionada via Botões de controle "Up" e "Down", e no Terminal do Arduino são "printados" dados a cada segundo (ou seja, a cada vez que é obtida uma nova amostragem da Vazão).
Nota-se que além da Vazão "instantânea", também é "printado" no Terminal do Arduino, a Vazão Média (sobre a qual falo mais adiante), a qual vai aumentando até praticamente se igualar ao valor instantâneo (como esperado).
Mas após isso, eu aumentei em "TP10" (o Trimpot para ajuste do Fluxo), para que a Vazão ficasse acima do Limite (que é 1 L/minuto).
O tempo necessário para detectar a Vazão Limite é de 5 minutos conforme o J. Leonardo especificou, ou seja, a Vazão tem que ficar acima do Limite por 5 minutos para que seja emitido um alerta. Porém, apenas na simulação eu diminui este tempo para 1 minuto, para não ter que esperar muito para ver o resultado.
E este resultado pode ser visto na figura a seguir, que mostra ligado o LED vermelho "Alerta Vazão":
(clique na figura para "zoom")
Nota-se também que pelo tempo decorrido, que novamente o valor da Vazão Média praticamente já igualou a Vazão instantânea.
Agora falando sobre o código, cujo link para download está no final do post.
Um ponto importante a salientar, é que o Sistema calcula continuamente a Vazão Média, e usa esse valor como referência para determinar se a Vazão Limite (no caso, 1 L/minuto) foi excedida (claro, após se manter assim por tempo determinado). Isso é necessário porque a Vazão "instantânea" terá variações, o que poderá impedir o Sistema de detectar o limite e emitir um alerta. Exemplo: a Vazão Limite é de 2 L/minuto e a Vazão instantânea está em 2,1 L/min a algum tempo, mas cai por 3 segundos para 1,9 L/min, e em seguida volta a subir indo para 2,3 L/min. Neste caso, quando a Vazão caiu momentaneamente para 1,9 L/min, isto interromperia a contagem de tempo para emissão de um alerta, o que seria um problema caso essas quedas ficassem ocorrendo e impedindo o alerta de ser emitido. Usando a Vazão Média, diminui-se a possibilidade desse problema, uma vez que variações momentâneas na Vazão, terão efeito menor no valor da Vazão Média.
No código, você pode determinar quantas amostras irão compor a Vazão Média, conforme mostro mais adiante.
Além de usar a Vazão Média para o alerta, o código também tem uma tolerância para o valor da Vazão Limite, sendo esta tolerância sempre "para baixo" (já que não teria sentido ser também "para cima"). Exemplo: se a Vazão Limite é de 2 L/min, e a tolerância é definida para 10%, então o Sistema considera como valor limite efetivo, os 2 L/min menos 10% de 2 L/min. Ou seja, 2 - 0.1 x 2 = 1,8 L/minuto. A tolerância pode ser facilmente alterada no código (como mostro adiante), e caso não se deseje utilizá-la basta então especificar uma tolerância de 0%.
A verificação para alerta de Vazão Limite, é temporizada, ou seja, é feita em intervalos de tempo. No código, este intervalo de tempo está especificado em segundos (como mostro logo adiante). Como resultado, esta temporização também ajuda a minimizar alertas errôneos, uma vez que pequenas variações podem até ser ignoradas pelo Sistema. Exemplo: a Vazão Média está próxima ao limite mas abaixo dele, e fica acima desse limite por 5 segundos, voltando a ficar abaixo em seguida, e como isso ocorre entre dois intervalos de verificação, a variação acaba não sendo detectada (mas seria, se fosse efetiva e ficasse mais tempo acima do limite).
Outros detalhes de definições no código, são descritos a seguir na ordem que eles aparecem no próprio código. Lembrando que logo no início do código, estão definidos os parâmetros mais significativos e que são normalmente os mais alterados em implementações diversas. A quantidade de parâmetros é um pouco extensa, e além das definições de parâmetros constantes, há também algumas variáveis/flags importantes para o funcionamento do Sistema. No texto a seguir, descrevo os tais parâmetros mais significativos e aponto algumas funções mais relevantes para o Sistema.
A figura a seguir, mostra a definição dos fatores para cálculo da Vazão "instantânea" e da conta de água.
(clique na figura para "zoom")
O "fator_Vazão" permite o cálculo da Vazão "instantânea" em mili-Litros por segundo. Assim no código, para se obter a Vazão em Litros por minuto, basta multiplicar a Vazão instantânea por 60 (já que 60 segundos= 1 minuto) e dividir por 1000 (já que 1000 mili-Litros = 1 Litro).
Na figura a seguir, são mostrados os parâmetros usados para determinar se o Sistema deve emitir um alerta de Vazão acima de um limite definido. A figura é auto-explicativa, uma vez que os comentários no código descrevem cada parâmetro e explicam como são usados.
(clique na figura para "zoom")
O Sistema emite também um alerta quando o consumo total (o fluxo total acumulado), ultrapassa um limite estabelecido. A figura a seguir, mostra a definição deste limite, em metros cúbicos:
(clique na figura para "zoom")
Observar que como o fluxo é sempre cumulativo, não é necessário tratamento especial (como calcular um valor médio) para se detectar um limiar e consequentemente emitir um alerta.
Além de mensagem no Display LCD, dois LEDs são usados para sinalizar o alerta de Vazão Limite e alerta de fluxo total acumulado. A figura a seguir mostra as definições para uso destes LEDs no Sistema:
(clique na figura para "zoom")
Sinalizar através de LED é uma forma eficiente de emitir um alerta (alertas auditivos geralmente são mais eficientes, mas nem sempre são os mais adequados devido ao "barulho" resultante). Mas é preciso considerar a cor usada para o alerta visual, neste caso a cor da luz que os LEDs emitem. Eu projetei Equipamentos Eletro-Médicos por 25 anos, e conheço bem as normas relacionadas a alertas naqueles equipamentos (normas compulsórias neste caso), onde alertas visuais devem se restringir a cores como "amarelo", "laranja", "vermelho", e tons semelhantes. Ou seja, não tem sentido sinalizar um alerta com uma cor como "verde" ou "azul" (ou mesmo "branco"). Aqui neste tópico não estamos tratando de equipamentos médicos, mas observem que o bom senso do uso das cores também se aplica de forma muito natural para sinalizarmos alertas.
Para selecionar a informação exibida no Display, são usados dois Botões chamados de "Up" e "Down". Acredito que apenas um Botão seria suficiente para esta função, mas o J. Leonardo optou por dois. Mas além disso, um Botão a mais permite mais opções de uso, e isso certamente será necessário se as funcionalidades do código forem expandidas por quem assim desejar (é bem provável que um terceiro e um quarto Botão sejam bem vindos). Os dois Botões são definidos conforme mostra a figura a seguir:
(clique na figura para "zoom")
Como o Sistema é originalmente para o Arduino UNO (ou seja, com Processador "AVR"), o código automaticamente ligará o Resistor de Pullup interno no pino dos Botões, caso o Nível Lógico de acionamento (com nome "logica_Botao_ON" na figura anterior) seja "LOW", assim dispensando um Pullup externo. Lembrando que o Pullup interno do AVR tem um valor com alta-tolerância, podendo ir de 20 kΩ a 50 kΩ (depende da tensão de alimentação, sendo que tensões mais altas neste caso implicam em impedâncias mais baixas, pois são usados MOSFETs para "construir" os Resistores de pullup). Caso o código seja usado em Sistemas com outros Processadores que permitam também "Pulldown" (como ESP32, STM32, Arduino Due, etc), então pode-se usar a mesma técnica para ligar automaticamente ou o "Pullup" ou o "PullDown" (ou mesmo nenhum deles, caso se especifique que um Resistor externo esteja sendo usado).
Para eliminar o "bouncing" (ou trepidação mecânica) resultante do acionamento de um Botão, e assim impedir acionamentos errôneos consecutivos, o Sistema implementa um "tempo de debouncing". Assim quando um Botão é acionado, o Sistema ignora qualquer outro acionamento no mesmo botão, pelo "tempo de debouncing", e isso faz com que a trepidação mecânica não tenha efeito. Como existem Botões de todo tipo no mercado e com maior ou menor trepidação mecânica, é preciso definir qual o tempo de "debouncing" a ser utilizado no Sistema, e isto pode ser visto na figura a seguir:
(clique na figura para "zoom")
Por razões óbvias, este tempo está especificado em unidades de mili-segundos. O tempo de 100 [ms] definido na figura anterior, é geralmente mais que suficiente mesmo para os "piores" Botões, mas pode-se diminuir ou aumentar o mesmo caso seja desejado. Este tempo não tem efeito na detecção imediata do Botão, ou seja, quando um Botão é acionado ele será imediatamente detectado. Claro, se o tempo for especificado como "0" (zero), então o "tempo de debouncing" não terá efeito (ou seja, as trepidações mecânicas no acionamento provocarão diversos acionamentos).
Como já dito, o Sistema emite dois alertas: um de Vazão Limite e um alerta de Fluxo acumulado (um "alerta de consumo" total). Para ambos, há LEDs específicos para emissão de alerta visual. O alerta de Vazão Limite também é exibido periodicamente no Display (conforme descrito mais adiante). Caso seja desejado emitir outras formas de alerta, pode-se testar as Flags específicas para cada um dos dois alertas. Estas Flags são variáveis do tipo "bool" (ou "boolean"), e assumem o valor "true" ou o valor "false". Quando um alerta é emitido, a Flag respectiva vai ao valor "true". As variáveis correspondentes a estas Flags, são definidas conforme mostrado na figura a seguir:
(clique na figura para "zoom")
Logo, estas Flags podem ser testadas a qualquer momento e em qualquer ponto do código, para se saber se o alerta correspondente foi emitido. Lembrando que o consumo acumulado só aumenta, e portanto quando fica além do limite definido para alerta, este alerta passa a ser constante, ou seja, o LED de alerta fica permanentemente ligado e a Flag de alerta passa a ficar em "true" (e não volta mais para "false").
Também como dito antes, o Sistema calcula continuamente a Vazão Média em Litros por minuto, e para isso ele mantém um registro das últimas "N" amostras da Vazão instantânea. Esta quantidade "N" é definida conforme mostrado na figura a seguir:
(clique na figura para "zoom")
A Vazão Média será então o resultado do somatório das últimas "N" amostras, dividido pelo valor "N". No código este total de registros está definido como sendo 10 (dez), mas pode ser alterado conforme desejado (lembrando que quanto maior a quantidade de registros, mais memória RAM é usada para manter estes registros, e mais tempo o Sistema gasta para fazer os cálculos da Vazão Média).
Nota: a página do post não comporta o restante do texto, então estou continuando logo a seguir:
…
Adicionado por Elcids Chagas ao 1:09 em 20 novembro 2020
EFLOP - Arduino e Cia
#include <VirtualWire.h>
String mensagem;
void setup()
{
Serial.begin(9600);
//Define o pino 8 do Arduino como
//o pino de dados do transmissor
vw_set_tx_pin(8);
vw_setup(2000); // Bits per sec
Serial.println("Digite o texto e clique em ENVIAR...");
}
void loop()
{
char data[40];
int numero;
if (Serial.available() > 0)
{
numero = Serial.readBytesUntil (13,data,40);
data[numero] = 0;
Serial.print("Enviado : ");
Serial.print(data);
Serial.print(" - Caracteres : ");
Serial.println(strlen(data));
//Envia a mensagem para a rotina que
//transmite os dados via RF
send(data);
}
}
void send (char *message)
{
vw_send((uint8_t *)message, strlen(message));
vw_wait_tx(); // Aguarda o envio de dados
}
…
Adicionado por augusto ao 15:30 em 25 novembro 2017
IR, tem um LM35 para mostrar a temperatura no visor do celular e um dimmer para iluminação. No entanto, estou tendo problema com um ruido na serial que trava o funcionamento do programa. Este ruido só acontece se eu deixo todos os comandos que controlam o home theater ativos (linhas entre os comandos "M" e "X"). Se eu comentar as linhas de 2 comandos, quaisquer que sejam, o programa funciona perfeitamente. Exemplo: se eu colocar em comentário as linhas dos códigos "N" e "O" o programa funciona. Se eu "descomentar" as linhas "N" e "O" e comentar as linhas "X" e "Y", o programa também funciona. Se eu "descomentar" todas as linhas aparece um ruido na serial que trava a execução do programa. Estava usando o SoftwareSerial para comunicar com o bluetooth, mas o programa estava se perdendo quando plugava a placa na energia para a operação do dimmer. Descobri aqui no fórum que o SoftwareSerial utiliza interrupções que conflitam com a interrupção do dimmer para o zero-crossing. Por este motivo optei em utilizar os pinos RxTx do garagino. Também tentei colocar as variáveis como #define para verificar se o problema não era memória, mas também não funcionou. Os comandos entre "A" e "E", padrão NEC, não interferem no funcionamento, estando comentados ou não. Alguém saberia me explicar por que ao comentar algumas linhas do o programa funciona normalmente?
Grato.
#include <IRremote.h>
char caractere;
//definições dimmerint ZERO = 2; // pino de interrupçãoint AC_LOAD = 9; // Output para o Triacvolatile int dimming = 100; // Dimming level (0-128) 0 = ON, 128 = OFFString ValorDimmer;
//definições do Receptor IRIRsend irsend; //objeto para enviar IR const int led = 8; // pino do led de indicação de funcionamento const int ledIR = 3; //pino do emissor IR
// comando TV LG - padrão NECint freqNEC = 32;long int TvLiga = 0x2FD48B7; //Along int TvChL = 0x2FDF807; long int TvChH = 0x2FDD827;long int TvVolL = 0x2FD7887; //Blong int TvVolH = 0x2FD58A7; //Clong int TvTimer = 0x2FDA857; //Dlong int TvMute = 0x2FD08F7; //E
// Comandos Oi Tv - padrão RC6int freqRC6 = 32;long int CaboLiga = 0x8072260C; //Flong int CaboChL = 0x8072261F; //Glong int CaboChH = 0x8072261E; //Hlong int CaboVolL = 0x80722611; //I long int CaboVolH = 0x80722610; //J
long int CaboIdioma = 0x8072A6A1; //Klong int CaboLegenda = 0x8072264B; //L
// Comando HOME THEATER LG - RAWint compr = 67;int freq = 36;//Munsigned int LgHtLiga[] = {4600,4300,750,350,750,350,750,1450,750,1500,700,400,750,1500,700,400,700,400,700,400,700,400,700,1550,700,1500,700,400,650,1600,550,600,500,600,500,600,500,1700,550,1700,500,1700,500,1700,550,600,500,600,500,600,500,1700,550,550,550,600,500,600,500,600,500,1700,550,1700,500,1700,550};//Nunsigned int LgHtVolL[] = {4500,4450,500,600,500,600,550,1700,500,1700,500,600,550,1650,550,600,500,600,500,600,500,600,550,1650,550,1700,500,600,500,1700,550,550,550,600,500,600,500,1700,550,1650,550,600,500,1700,550,550,550,550,550,550,550,1700,500,600,550,550,550,1700,500,600,500,1700,550,1650,550,1700,500};//Ounsigned int LgHtVolH[] = {4450,4500,500,600,500,600,500,1700,550,1700,500,600,500,1700,550,550,550,550,550,600,500,600,500,1700,550,1700,500,600,500,1700,500,600,550,550,550,1700,500,1700,550,1650,550,600,500,1700,500,600,550,550,550,550,550,600,500,600,500,600,500,1700,550,550,550,1700,500,1700,550,1650,550};//Punsigned int LgHtInput[] = {4600,4350,600,500,600,550,550,1650,550,1650,550,600,500,1700,550,550,550,550,550,600,500,600,500,1700,550,1650,550,600,500,1700,500,600,550,550,550,600,500,1700,500,600,500,1700,550,600,500,600,500,600,500,1700,550,1700,500,600,500,1700,550,550,550,1700,500,1700,550,1650,550,600,500};//Qunsigned int LgHtOpen[] = {4450,4500,500,600,500,600,500,1700,550,1700,500,600,500,1700,550,550,550,550,550,600,500,600,500,1700,550,1700,500,600,500,1700,500,600,550,550,550,600,500,1700,500,600,500,1700,550,1700,500,600,500,600,550,1650,550,1700,500,600,500,1700,550,550,550,600,500,1700,500,1700,550,550,550};//Runsigned int LgHtChL[] = {4500,4450,500,600,550,550,550,1700,500,1700,550,550,550,1700,500,600,500,600,500,600,550,550,550,1700,500,1700,500,600,550,1650,550,600,500,600,500,600,500,600,550,550,550,1700,500,600,500,1700,550,550,550,1700,500,1700,550,1650,550,1700,500,600,500,1700,550,550,550,1700,500,600,500};//Sunsigned int LgHtChH[] = {4450,4500,500,600,500,600,500,1700,550,1700,500,600,500,1700,550,550,550,550,550,600,500,600,500,1700,550,1650,550,600,500,1700,500,600,550,550,550,1700,500,600,500,600,550,1650,550,550,550,1700,500,600,500,1700,550,600,500,1700,500,1700,550,550,550,1700,500,600,500,1700,550,550,550};//Tunsigned int LgHtEnter[] = {4450,4450,550,600,500,600,500,1700,550,1700,500,600,500,1700,550,550,550,550,550,600,500,600,500,1700,550,1650,550,600,500,1700,500,600,550,550,550,550,550,1700,500,600,550,1650,550,600,500,1700,500,600,500,1700,550,1700,500,600,500,1700,550,550,550,1700,500,600,500,1700,550,550,550};//Uunsigned int LgHtPlay[] = {4450,4450,550,600,500,600,500,1700,550,1650,550,600,500,1700,500,600,550,550,550,550,550,600,500,1700,500,1700,550,600,500,1700,500,600,500,600,550,550,550,600,500,1700,500,600,500,600,550,550,550,600,500,600,500,1700,550,1650,550,600,500,1700,500,1700,550,1700,500,1700,500,1700,550};//Vunsigned int LgHtPause[] = {4450,4500,500,600,500,600,500,1700,550,1700,500,600,500,1700,550,550,550,600,500,600,500,600,500,1700,550,1650,550,600,500,1700,550,550,550,550,550,1700,500,1700,550,1650,550,1700,500,600,500,600,550,1650,550,600,500,600,500,600,500,600,550,550,550,1700,500,1700,550,550,550,1700,500};//Xunsigned int LgHtSkpL[] = {4450,4500,500,600,500,600,550,1700,500,1700,500,600,550,1650,550,600,500,600,500,600,500,600,550,1700,500,1700,500,600,500,1700,550,550,550,600,500,600,500,1700,550,1700,500,600,500,600,500,600,500,600,550,550,550,1700,500,600,500,600,550,1650,550,1700,500,1700,550,1700,500,1700,500};//Zunsigned int LgHtSkpH[] = {4450,4500,500,600,500,600,500,1700,550,1700,500,600,500,1700,550,550,550,550,550,600,500,600,500,1700,550,1650,550,600,500,1700,550,550,550,550,550,1700,500,1700,550,1650,550,600,500,600,500,600,500,600,550,550,550,600,500,600,500,600,500,1700,550,1700,500,1700,500,1700,550,1650,550};
//variaveis do temporizadorint savedTime;int totalTime = 0;
//variaveis leitura serialString bufferSerial = "";int numero; //contador para alterar a potencia do dimmer
void setup(){ Serial.begin(9600); //ir pinMode(led, OUTPUT); // saida led pinMode(ledIR ,OUTPUT); // saída do infravermelho //dimmer pinMode(ZERO, INPUT); pinMode(AC_LOAD, OUTPUT);// Set AC Load pin as output attachInterrupt(0, zero_crosss_int, RISING); //zero-crossing - interrupção numero = dimming; //inicializa a leitura da serial com o mesmo valor do dimming //inicia temporizador que atualiza temperatura savedTime = millis();}
void loop(){
//atualiza temperatura no intervalo de "totaltime" int passedTime = millis() - savedTime; if (passedTime > totalTime) { //temperatura LM35 int sum=0; for (int i = 0; i < 50; i++) sum += analogRead(A5); int media = (sum * 0.48875855) / 50; Serial.print(media); savedTime = millis(); // Save the current time to restart the timer! totalTime = 5000; //Seta para 5seg }
bufferSerial = ""; while (Serial.available()>0) {char c = Serial.read(); // Lê byte do buffer serial; bufferSerial.concat(c); // Concatena valores delay(5);if (c == '@') break; // se leu o caracter @ sai do loop. Este caracter é enviado pelo comando do celular }
if (bufferSerial.length()>0 && bufferSerial.length()<2) { //verifica se informação que chegou esta entre 1 e 2 caracteres (para futuras implementações) digitalWrite(led, HIGH); //acende o led indicador de envio de IR / comando
if (bufferSerial == "A"){irsend.sendNEC(TvLiga, freqNEC);} // código que sera enviado a tv para ligar if (bufferSerial == "B"){irsend.sendNEC(TvVolL, freqNEC);} // código que sera enviado a tv para diminuir o volume if (bufferSerial == "C"){irsend.sendNEC(TvVolH, freqNEC);}// código que sera enviado a tv para aumentar o volume if (bufferSerial == "D"){irsend.sendNEC(TvTimer, freqNEC);}// código que sera enviado a tv para timer if (bufferSerial == "E"){irsend.sendNEC(TvMute, freqNEC);}// código que sera enviado a tv para mute // código que sera enviado a o HT para ligar/desligar if (bufferSerial == "M"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtLiga, compr, freq); delay(50);}} // código que sera enviado a o HT para baixar o volume if (bufferSerial == "N"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtVolL, compr, freq); delay(50);}} // código que sera enviado a o HT para aumentar o volume if (bufferSerial == "O"){ for (int i = 0; i < 3; i++) { irsend.sendRaw(LgHtVolH, compr, freq); delay(50);}} // código que sera enviado a o HT para selecionar o source if (bufferSerial == "P"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtInput, compr, freq); delay(50);}} // código que sera enviado a o HT para abrir o deck if (bufferSerial == "Q"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtOpen, compr, freq); delay(50);}} // código que sera enviado a o HT para mudar de estação / seleção - if (bufferSerial == "R"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtChL, compr, freq); delay(50);}} // código que sera enviado a o HT para mudar de estação / seleção + if (bufferSerial == "S"){ for (int i = 0; i < 3; i++) { irsend.sendRaw(LgHtChH, compr, freq); delay(50);}} // código que sera enviado a o HT como enter if (bufferSerial == "T"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtEnter, compr, freq); delay(50);}} // código que sera enviado a o HT como play if (bufferSerial == "U"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtPlay, compr, freq); delay(50);}} // código que sera enviado a o HT como pause if (bufferSerial == "V"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtPause, compr, freq); delay(50);}} // código que sera enviado a o HT como skip - if (bufferSerial == "X"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtSkpL, compr, freq); delay(50);}} // código que sera enviado a o HT como skip + if (bufferSerial == "Y"){ for (int i = 0; i < 3; i++){ irsend.sendRaw(LgHtSkpH, compr, freq); delay(50);}} }
//se o comando possui mais de 2 caracteres então é para o dimmer if (bufferSerial.length()>2){ bufferSerial.trim(); //elimina possiveis espaços if (bufferSerial.substring(0,2) == "#L") numero = numero+5; //incrementa contador do dimmer para diminuir potencia if (bufferSerial.substring(0,2) == "#H") numero = numero-5; //decrementa contador do dimmer para aumentar potencia if (numero >= 15 && numero <= 128) //se contador estiver abaixo ou acima dos limites do dimmer mantém a ultima leitura {dimming=numero;}else{dimming=dimming;} }
digitalWrite(led, LOW); //apaga o led indicador de envio de IR / comando }
// função disparada pelo zero-crossingvoid zero_crosss_int() { int dimtime = (65*dimming); // For 60Hz =>65 delayMicroseconds(dimtime); // Off cycle digitalWrite(AC_LOAD, HIGH); // triac firing delayMicroseconds(8.33); // triac On propogation delay 10ms for 60Hz use 8.33) digitalWrite(AC_LOAD, LOW); // triac Off}…
Adicionado por Fernando Souza ao 17:44 em 3 novembro 2014
Veja: no UNO...”
Veja bem, utilizo o esp32 em outra placa para simular um pwm através do 595. Diferente do código atual, não utilizo o “digitalWrite”, mas sim os registradores. Não possui nenhum delay, funciona perfeitamente. (ao menos na bancada, na placa ainda não testei).
2) Sobre o Feder, considerando apenas uma chave de on/off, isso seria tão errado assim?
É apenas a título de curiosidade, pois apenas o RC economiza espaço e componente.
3) Sobre AmpOp,
nunca usei/testei. É mais uma nova situação para ser estudada. Mas sinto que vou gastar longas e longas horas com este carinha aqui. Confere?
4) Sobre o hc594
Não localizei o componente no formato dip. No aliexpress, apenas SMD. Eu tenho uma certa resistência com smd, pois AINDA acho o formato muito pequeno para mim. Sei que SMD é o único caminho, a diferença no tamanho final da pcb é ENOOOOOORME. Num “remake” de um projeto que tenho, chegou a quase 1/4 ou 1/3 do tamanho total. Entretanto, isso implicaria em adquirir novos componentes, novas ferramentas, mais tempo para praticar, e nisso vai mais dinheiro junto.
O drama disso tudo, é que desde que comecei a estudar um pouco sobre eletrônica, existe um loop infinito de: “precisa de componente -> componente encontrado -> novo problema/recurso -> novo componente que faz tudo que o anterior só que mais rápido, melhor e consome menos energia -> repete o loop”
Cheguei num ponto que, incomodado com o loop, bati o pé no chão e disse: “Não vou comprar mais nada até concluir alguma coisa” e colocar pra funcionar. As placas que fiz, estão com este pensamento.
A chance de migrar pro smd futuramente é de 99,99%, mas só depois de concluir essa primeira etapa.
E essa decisão veio pois caiu a ficha que entrei no mesmo loop "da perfeição" de quando eu escrevia códigos para tentar criar jogos, mas nunca cheguei a terminar nenhum, pois não defini um final e ficava sempre polindo. Depois que caiu a ficha, produzi um outro bem simples para ajudar o pessoal que tinha dificuldade para digitar: https://digitarrapido.wordpress.com/
Atenção: Caso tenham curiosidade e resolvam baixar, mas durante a execução, ou instalação, ele alegar a existência de algum tipo de vírus, pode excluir sem medo. É um falso positivo que não interfere no funcionamento do jogo. Este ".exe" foi um arquivo criado em delphi para compactar um conjunto de blocos de notas com os resultados da partida e depois enviar para um e-mail específico. Despois eu atualizava manualmente os ranks. (foi uma péssima ideia, pois em pouco tempo o google identificou até chineses tentando entrar na minha conta. kkkk)
Star Citizen é um exemplo do loop da perfeição, mas diferente de mim, o pessoal já recebeu mais de 250 milhões de DOLARES em doação, para a conclusão do jogo, além de arrecadar quase 5 milhões por mês, ainda hoje. (E TA EM DESENVOLVIMENTO!). Nesse caso, contrata 1000 pessoas e coloca todo mundo para trabalhar.
obs- um outro bom CI seria o tpic6b595 (ou algum dos seus familiares).
5) “ sobre o layout.”
Eu dei muita risada ao ler “quase dá pra dizer que não há padrão no seu layout” kkkkk, e eu tinha me esforçado tanto para ficar bonitinho. Mas faz parte, é a primeira tentativa, tenho muito o que melhorar ainda.
Sobre as trilhas em si, poucas foram realmente feitas por mim. As que fiz são fáceis de serem identificadas, pois possuem uma curva bem bonitinha, sem ângulos. Dentre elas, as que ligam 3 terminais do 4051b a 3 pads no canto central esquerdo, e outra do 4051b que vai até R20.
Todas as demais foram feitas pelo roteamento automático do proteus. Devido a meu conhecimento, ainda, pequeno, este era o melhor recurso que eu tinha. Em todo caso, é muito bom saber sobre estas questões e saber que existem programas específicos para este fim (quando li seu comentário, comecei a achar que era tudo manual), pois, futuramente, a quantidade de imperfeições tenderá a ser um pouco menor.
6) “Veja no "Bottom" alguns pontos que salientei:”
Realmente, são curvas totalmente estranhas e sem sentido.
Sobre as áreas do gnd, eu tinha visto que era sempre bom ter grandes áreas com gnd na placa, pois isso evitava o ground loop e outros problemas. Por isso, defini a largura das trilhas e no final coloquei um “chapeado” de gnd em todas as áreas disponíveis da parte inferior.
7) Geralmente se usa "U" para essa referência.
Sim, vi em algumas placas que desmontei que isso era muito comum, imaginei que fosse um padrão, toda via também achei que seria mais fácil, para mim (tendo em vista que é a primeira experiência), na hora de soldar os componentes, se eles já tivessem alguma referência.
Eu cheguei a pensar em colocar os componentes assim: “R20 – 180k”, “U3 74hc595_A” mas esse acréscimo começou a deixar o visual muito poluído e bagunçado.
8) “c pode interromper a trilha que liga o "DOUT" do HC165 ao ESP, e interconectá-la conforme a figura a seguir:”
Fiquei surpreso com a simplicidade da solução e como eu não tinha pensado nisso antes.
Obs- Sou da bahia, aqui está chovendo muito. Boa humidade.
9) “ Se o "A" funcionou corretamente, e o "B" não, então é...”
Bem, lendo isso resolvi fazer o mesmo teste que fiz com o pino 14 e 9.
74hc595_A pino 14 ao 74hc595_B pino 9
595_A pino 11 ao 595_B pino 11
595_A pino 12 ao 595_B pino 12.
O ci esta no 595_C, os outros, obviamente, vazios.
Resultado: o 595C respondeu corretamente.
Em seguida removi o jumper entre os pinos 12, E continuo funcionando. Em seguida removi o jumper entre os pinos 11, e parou de funcionar.
O pino 11 é o pino de clock.
Depois disso, feliz em ter descoberto o problema, mas lembrando que já tive problema com os leds, resolvi voltar ao esquema só para tirar uma duvida, e ter certeza que não era o mesmo erro. Ao chegar lá, descubro que coloquei tags diferentes.
Aparentemente, os problemas estão descobertos. Amanhã (02 de setembro), irei ligar os terminais com um pedaço de fio, assim como os que estão conectados aos leds, então postarei os resultados.
10) Aproveitando que já chegamos até aqui... “E obrigatoriamente deve ser um Capacitor do tipo Cerâmico “
Pq obrigatoriamente o cerâmico? Existiria problema em adicionar um capacitor eletrolítico de valor maior? Exemplo: 100, 470 ou 1000uf? Apenas por curiosidade.…
Adicionado por tiago merces ao 21:02 em 1 setembro 2021
1) a sua forma de implementar a Máquina de Estados está correta. Mas ainda assim há alguns conceitos equivocados na sua implementação. Você precisa corrigir estes conceitos para que sua Máquina funcione conforme vc deseja e sem bugs.
Os dois elementos principais em uma Máquina de Estados, são o "Estado" em que a Máquina se encontra, e os "Eventos" que provocam as mudanças de estado. E dentro de um "Estado", vc pode fazer duas coisas: pode controlar Dispositivos do seu Sistema (Relés, LEDs, Displays, Motores, o que vc quiser), e pode obter informações (estado de chaves, sensores, etc) que possibilitem controlar os Dispositivos e possivelmente mudar de estado (ou seja, as informações obtidas podem gerar Eventos).
E claro, vc deve fazer o Diagrama de Estados da Máquina de Estados, que essencialmente é descrever como o seu Sistema irá funcionar, mostrando nele como a Máquina de Estados controlará seu "fluxo" de forma a fazer o trabalho que vc deseja. Se vc fez um Diagrama de Estados "correto", bastará implementar sua Máquina de Estados a partir desse Diagrama.
Para que vc se oriente melhor nisso, veja algumas implementações que fiz aqui no LDG, para resolver problemas típicos, que estão nestes links:
- Máquina de Estados JMelo: link
- Máquina de Estados Lucas Piedra: link
- Máquina de Estados Luiz Henrique: link
- Máquina de Estados Francikleber: link
- Máquina de Estados Oziel Marques: link
- Máquina DogFeed Marcela: link
Este último ("DogFeed"), é um ambiente com maior quantidade de dispositivos e temporizações mais complexas. Por isso aconselho vê-lo apenas depois de ver os demais, que são mais simples.
2) Como o Minerin ressaltou, há alguns controles principais que vc pode fazer no Timer1. E sim, de fato ele começa a funcionar quase de imediato após a inicialização do código-base do Arduino (o qual vc normalmente não acessa). Mas isso não deveria afetar o funcionamento do seu Sistema. Se vc implementar sua Máquina de Estados corretamente, nem precisará se preocupar se o Timer1 já estava ou não contando. Essencialmente, o resultado funcional da utilização do Timer1, será equivalente à função "millis" do Arduino (analise e chegará a essa conclusão).
Ah sim: se sua intenção era o intervalo de 0.01 segundo (como vc disse), então está passando o valor errado para a função "Timer1.initialize", que deveria ser 10000 (10 mil micro-segundos = 10 mili-segundos), e não 100000 (isto seria para 0.1 segundo).
3) seu conceito da função para "callback" parece confuso, o que é evidenciado quando vc diz "Esse Time++ eu acho que...". Ocorre que um "callback" é executado na taxa do evento que vc programou pra que ele executasse, e que neste caso seria a taxa do "overflow" do Timer1. Se vc programou para 0.01 segundo, essa taxa será o inverso disso, ou seja: 1/0.01 = 100. Logo, a função "callback" seria executada 100 vezes por segundo (taxa de 100Hz). E a cada execução, ela incrementa a variável "time" em uma unidade (devido ao "++"). Mas como no seu código vc estava programando a taxa do Timer1 para 0.1 segundo, então a taxa de execução do "callback" será = 1/0.1 = 10, ou seja, sua variável "time" será incrementada 10 vezes por segundo. Em outra palavras, a cada segundo que passa, a variável "time" é incrementada em 10.
Notas importantes: como o "callback" é chamado de dentro de uma "ISR" (Interrupt Service Routine), então vc deve obrigatoriamente declarar a variável "time" como sendo do tipo "volatile", para que seu código funcione corretamente. Mas você declarou apenas assim: "int time;" , e deveria ser assim: "volatile int time;". Se vc não souber o motivo de ter que ser assim, explico depois (mas não é nada complexo não). Também devido ao mesmo fato do "callbak" ser chamado de dentro de uma "ISR", não execute tarefas demoradas dentro dele. Mas neste caso não tem problema no seu código, pois a única coisa que está sendo feita no seu "callback" é o incremento da variável "time", então está tranquilo isto. Se vc precisar fazer tarefas mais pesadas e demoradas, proceda assim: sete uma flag dentro do "callback" e use a Máquina de Estados para detectar isso (seria exatamente um Evento) e fazer o trabalho pesado e demorado dentro da "temporização realística" do seu Sistema (claro, imediatamente depois que a tarefa pesada terminar, resete a flag indicadora do evento).
4) seu código está um tanto "bagunçado". Para fazer uma Máquina de Estados de forma confiável, vc tem que fazer um código "limpo" e organizado. Isto é absolutamente necessário. Veja os exemplos dos códigos dos links que passei em 1), e note como estão super-organizados. Vou citar como exemplo, uma confusão enorme no seu código: não fica claro o que são o "curto", "medio", e "longo". Há uma mistureba, onde hora vc os usa como variáveis, e hora vc usa para acesso a pinos de I/O do Arduino. Aparentemente existem entradas de Botões associados a estas 3 variáveis, mas sem uma evidência clara disso no código, além do que no "setup", vc programa os mesmos pinos com níveis lógicos "LOW", o que parece sem sentido. Eu assumi que há Botões conectados aos pinos "2", "3" e "4", e com isso organizei o código que vc postou aqui (aquele do Pastebin). O código organizado é esse: "duvida_TimerOne_01.ino" . Mas claro, eu posso estar enganado, se os Botões não existirem. Mesmo neste caso, vc ainda pode aproveitar o código que eu organizei, pois isso pode te ajudar bastante. Caso faça isso, não o faça apenas pra ganhar tempo, mas principalmente para ver como foi feito e aprender com a implementação.
5) por fim, para resetar a contagem "time" como aparentemente vc deseja, crie um Estado Inicial na Máquina de Estados, digamos o Estado "0", e dentro deste estado zere o valor do "time". Claro, esse estado executará apenas uma única vez no seu Sistema, e depois seguirá para o Estado "1" que vc já implementou. Ah, vc deve ter colocado o "volatile" na declaração da variável "time", como mostrei em 3).
Se possível, post aqui algum desenho que esclareça mais seu Sistema (circuito, diagrama, fotos, etc), pois ajudará bastante para que possamos auxiliá-lo aqui no LDG.
Abrçs
Elcids
…
Adicionado por Elcids Chagas ao 18:46 em 8 maio 2019
erto, entendo sua frustração, uma vez que usando um circuito discreto é perfeitamente possível sua implementação (mas claro que aí não terá a mesma flexibilidade e "sofisticação").
Então, partindo de que entendi corretamente, implementei seu Sistema no Arduino, e ele funcionou perfeitamente. Inclusive também fiz a simulação do mesmo, a qual também funcionou como esperado.
Para isto, implementei uma Máquina de Estados, que controla a geração dos pulsos, baseado no valor atual do "tempo de bico" (um nome um tanto esquisito, né?). E foram necessários apenas 2 estados para a implementação (um tanto surpreendente, pois diversas outras Máquinas que já implementei aqui no LDG tinham mais estados).
Claro, além da implementação da Máquina de Estados, tive que utilizar algumas técnicas "especiais", e sobre algumas dessas técnicas falarei mais à frente.
Mas antes Leonardo, gostaria de esclarecer um ponto: não era exatamente o "delay" o culpado pelos problemas que vc estava tendo. Eram vários culpados (e o "delay" era o menos culpado). Mas claro, em Sistemas de "tempo real", deve-se evitar o uso do "delay" a todo custo (no código que implementei não há nenhum), pois ele geralmente compromete as temporizações existentes no Sistema.
Outro detalhe: como vc não disse praticamente nada sobre o Hardware, testei com o Arduino UNO (e a simulação também fiz com o UNO).
Assim, a implementação de Hardware pode ser vista na figura a seguir, onde já mostro o resultado da simulação:
(clique na figura para "zoom")
Sobre esta implementação e resultado, farei algumas observações relevantes:
1) observe o sinal na cor amarela no Osciloscópio: são os pulsos do Sensor Hall. O código implementado, não depende da largura destes pulsos do Sensor, o que é ótimo. Mas como na simulação eu tinha que colocar uma largura para eles, coloquei em 500us. Se na prática for maior ou menor, não haverá problema, pois o código trata isso sempre de forma adequada.
2) o sinal na cor azul no Osciloscópio, são os pulsos de acionamento dos bicos injetores. A largura destes é determinada pelo valor lido do Potenciômetro, conforme vc disse que deveria ser. Sempre que o valor lido do Potenciômetro entra numa nova faixa, a largura dos pulsos muda de acordo com esta faixa. Os períodos dos pulsos que medi estavam bem precisos, e isto é devido a algumas das "técnicas especiais" que apliquei.
3) para a geração dos pulsos do Sensor Hall, na simulação foi utilizado um Gerador de Pulsos (na prática usei um Sensor Hall mesmo). Veja que na simulação, o valor da Frequência do Gerador, está em 80 Hz, ou seja, 80 pulsos por segundo. Isto corresponde a 4800 RPM, já que a rotação do motor em RPM = Frequência x 60 (ou seja, 80 x 60 = 4800 RPM), isso considerando que há apenas um único ímã acoplado ao eixo do Motor (se fossem dois, a frequência dobraria). Assim, para alterar a rotação na simulação, basta alterar o parâmetro "Frequência" do Gerador de Pulsos.
4) observe que há um Capacitor (o "C1") conectado entre o "A0" e o GND do circuito. Aconselho fortemente que vc o conecte. Na simulação não há ruídos, mas na prática os Sistemas em ambientes com Motores, costumam ter um bom nível de ruídos. E o capacitor é justamente para filtrar estes ruídos do sinal vindo do Potenciômetro (e também para minimizar a "injeção de carga" existente no circuito interno do Processador do Arduino). O valor pode estar entre 100kpF (que é o que eu coloquei na simulação), e 1uF. Use capacitor cerâmico, ou de tântalo (não use outros tipos!!!).
5) na simulação, conectei também um Voltímetro no pino "A0", de forma a poder conferir o valor indicado nele com o medido pelo Arduino (bateu sempre). Na prática, se vc for conectar algum voltímetro ou multímetro ali, apenas faça isso se tiver colocado o capacitor "C1".
6) o LED conectado na simulação (também conectei na prática), é quase um "enfeite". Mas é interessante, pois piscará na frequência dos pulsos gerados.
7) observe que no Terminal do Arduino (a Serial padrao), é possível ver os valores atuais da tensão medida no Potenciômetro, e "tempo de bico" correspondente. O sistema é otimizado, e apenas atualiza o Terminal, quando o "tempo de bico" muda. Isso é importante, pois a Serial consome alguma performance do Arduino, e então isso é minimizado com a técnica utilizada. Vc pode facilmente desligar essa exibição no Terminal, veja como: no código, há um #define com o nome "SYS_DEBUG_ON", que pode assumir "1" ou "0". Se colocar "1", você verá as informações no Terminal do Arduino. Se colocar "0", o sistema não exibirá no Terminal. Este #define do "SYS_DEBUG_ON" está no início do código, facilmente encontrado.
Agora falando sobre uma das técnicas utilizadas para garantir maior performance do Sistema, o que é muito importante, pois o Processador AVR8 do Arduino não é nenhum foguete. Você verá que no tratamento interno, a tensão medida é multiplicada por 1000 (mil, isso mesmo). Isso converte o valor "float" para um valor inteiro com até 4 dígitos. Este valor é então utilizado para determinar qual a faixa do "tempo de bico" correspondente. Mas por que? Ocorre que as rotinas de Ponto Flutuante do Arduino não são nada velozes, então no caso deste Sistema é melhor evitá-las sempre que possível. Claro, se em algum momento vc precisar do valor original em Volts, bastará dividir por 1000, mas evite fazer isso, e se fizer use uma temporização como a que utilizei em diversas partes do código.
O código está todo comentado e com observações importantes. Então está bem acessível de seguir e entender.
A Máquina de Estados implementada, é extremamente simples, já que tem apenas 2 estados. Se quiser aprender sobre como funciona, eu já postei aqui no LDG diversas outras Máquinas também simples, que irão ajudar nesse processo. Na figura a seguir, vc pode ver o Diagrama de Estados, a partir do qual implementei a Máquina de Estados deste Sistema:
(clique na figura para "zoom")
Segue o código, incluindo os arquivos de simulação no Proteus, e o Diagrama de Estados (formato Visio e PDF).
Código: Injecao_Bicos_02.zip
Caso tenha alguma dúvida ou comentário, não deixe de postar.
Espero ter ajudado.
Abrçs,
Elcids…
Adicionado por Elcids Chagas ao 9:57 em 17 julho 2019