Resultados da busca - %E6%81%92%E8%BE%BE%E7%99%BB%E5%BD%95%E7%94%A8%E6%88%B7%E5%90%8D%E6%98%AF%E4%BB%80%E4%B9%88%E6%84%8F%E6%80%9D%E3%80%90%E2%94%83%E5%A5%BD%E8%AE%A1%E5%88%922%E2%92%8F7%E2%92%8F01705%7B%EF%BC%B1%E3%80%91%E3%80%91
recisão de "6" dígitos. Isto fica bem evidente nos expoentes 7, 8, e 9.
No entanto, o valor "impresso" para o expoente 6, foi de "999999", e embora isto também seja um resultado "errado", há algo a mais a considerar neste caso além da própria precisão de 6 dígitos.
Ocorre que para fazer o cálculo da "potência", a respectiva função "pow" da LIB Matemática do Arduino, usa algumas constantes "float" (estas constantes são relacionadas a logaritmos), e por serem "float", estas constantes também tem a precisão de 6 dígitos. Assim, no resultado do cálculo para por exemplo "10^6" o valor não será exatamente "1000000", e alguma coisa sobrará após a vírgula. No caso da implementação matemática para o AVR, os valores sempre resultam ser ligeiramente abaixo do valor exato, e por isso para o resultado "1000000", temos algo como "999999.xxx", onde "xxx" seriam casas decimais após a vírgula, porém sem precisão, uma vez que a precisão é de apenas 6 dígitos. Quando o valor "float" é então convertido para "unsigned long", a Linguagem C determina que esta conversão deve ser feita truncada, o que resulta em "999999".
Observe que o mesmo ocorre para o caso dos expoentes 2, 3, 4, e 5. Porém neste caso, os resultados tem menos de 6 dígitos, o que implica que não haveria perda de precisão. Porém, devido àquelas constantes "float" usadas "internamente" no cálculo na função "pow" da LIB Matemática do AVR, os valores também são aproximados, e resultam ligeiramente menor que os valores exatos. Por exemplo para o expoente "2", o resultado seria algo como "99.9999xxx", que ao ser convertido para "unsigned long" é truncado e resulta em apenas "99".
Conclusão: é preciso atentar que ao convertermos de "float" para um tipo "inteiro", se esperamos valores exatos, devemos arredondar os valores, e não esquecer que a precisão é de apenas 6 dígitos (mas sobre esta precisão, incide o problema de cálculos cumulativos, que falo a seguir).
Além disso, conforme vc vai fazendo cálculos cumulativos com "float", a cada novo cálculo os erros de precisão vão se acumulando, e conforme o cálculo avança, vc vai perdendo mais dígitos na precisão, o que pode fornecer um valor muito diferente do que se espera. Ou seja, resultados de "float", devem ser observados com muito cuidado em relação à precisão.
Mas e sobre os expoentes "0" e "1"? Porque com eles o valor foi exato? Estes são casos "especiais". Ocorre que a função "pow" testa se o expoente é um destes dois números (0 ou 1), e estes são os únicos dois casos em que o resultado é previsível: para o expoente "0" o resultado será sempre "1" (a exceção é o 0^0, onde eu acho que retorna um "nan"), e para o expoente "1" o resultado será sempre a própria "base" (o valor que está sendo elevado ao expoente). Então nestes dois casos, a função "pow" não "perde tempo" fazendo os cálculos, mas sim retorna os dois valores exatos como resultado (ou "1" ou a própria "base").
E em Sistemas onde a precisão é maior, como o caso do ESP32, também temos erros de precisão cumulativos, e nunca se deve descuidar de até onde eles podem chegar conforme vc avança nos cálculos. E para analisar isso, normalmente é preciso usar técnicas de Metodologia Científica. Este é o motivo pelo qual na computação ordinária do dia a dia (por exemplo quando se trabalha com "dim-dim" ou "mufufa"), se buscam implementações com uma enormidade de bits na execução de cálculos em Ponto-Flutuante. Justamente pra diminuir ou negligenciar erros "traiçoeiros" oriundos do Sistema Binário (e que poderiam causar problemas no "mundo dos humanos").
Outro detalhe, é que no ESP32, os resultados sempre resultam em ligeiramente acima do valor exato (em contraste com as rotinas matemáticas para o AVR, onde a precisão de 6 dígitos é muito menor), e quando ocorre o truncamento para um tipo inteiro, o resultado então coincide com o valor exato (exemplo: 100.000000005, é truncado em "100"). Então nos resultados com o ESP32 temos erros também, mas por estes erros serem muito menores, eles acabaram sendo "automaticamente" suprimidos.
Espero ter contribuído para elucidar estas "maluquices" que podem nos deixar também doidos.
Abrçs,
Elcids…
Adicionado por Elcids Chagas ao 14:43 em 4 outubro 2020
or de 1k que esta ligado ao GND, como se fosse um potenciômetro, e na junção entre LDR e resistor de 1k eu liguei na porta 2 do arduino. O meu problema é que eu não estou conseguindo fazer uma função que, para cada variação no LDR ela adicione no contador, que seria os display.
Qualquer sugestão esta valendo.
Segue o código que eu montei.
int a = 3, b = 4, c = 5, d = 6, e = 7, f = 8, g = 9; int num[10][7] = {
{a,b,c,d,e,f}, {b,c}, {a,b,e,d,g}, {a,b,c,d,g}, {b,c,f,g}, {a,c,d,g,f}, {a,c,d,e,f,g}, {a,b,c}, {a,b,c,d,e,f,g}, {a,b,c,f,g},};
void setup() { pinMode(3,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); pinMode(7,OUTPUT); pinMode(8,OUTPUT); pinMode(9,OUTPUT); pinMode(11,OUTPUT); pinMode(12,OUTPUT); }
void loop(){ for(int dig2=0; dig2<10; dig2++){ for(int dig1=0; dig1<10;dig1++){ for(int tempo=0; tempo<1000; tempo++){ digito1(dig1); delayMicroseconds (500); digito2(dig2); delayMicroseconds (500); } } } }
void digito1(int i){ digitalWrite(11,LOW); digitalWrite(12,HIGH); numero(i); apaga(1); }
void digito2(int j){ digitalWrite(11,HIGH); digitalWrite(12,LOW); numero(j); apaga(1); }
void PD(int m){ digitalWrite(10, HIGH); switch(m){ case 1: digitalWrite(11,LOW); digitalWrite(12,HIGH); break; case 2: digitalWrite(11,HIGH); digitalWrite(12,LOW); break; case 3: digitalWrite(11,HIGH); digitalWrite(12,HIGH); break; } }
void apaga(int AP) { switch(AP){ case 1: digitalWrite(a,LOW); digitalWrite(b,LOW); digitalWrite(c,LOW); digitalWrite(d,LOW); digitalWrite(e,LOW); digitalWrite(f,LOW); digitalWrite(g,LOW); break;
case 2: digitalWrite(10,LOW); break; } }
void numero(int n){ for(int i=0;i<7;i++) digitalWrite(num[n][i], HIGH); }…
Adicionado por Luis Medeiros ao 10:28 em 8 fevereiro 2013
lt;SPI.h>#include <SD.h>#include <Ethernet_v2.h>#include <SerialRelay.h>
//Define o Mac Address da placa de rede. Essa informação pode ser encontrada em uma etiqueta colada embaixo da mesma.byte mac[] = { 0x90, 0xA2, 0xDA, 0x10, 0xC6, 0x65 };//Define o IP da placa. Caso necessário altere o mesmo para se adequar a sua rede.IPAddress ip(192, 168, 0, 99);
EthernetServer server(8484);File webFile;
//na linha de baixo está sendo definido as portas em que o módulo relé serial está conectado.SerialRelay relays(8, 9, 10); // (pino de data, pino de clock, quantidade de módulos)
#define REQ_BUF_SZ 60char HTTP_req[REQ_BUF_SZ] = {0};char req_index = 0;
int estado_botao[41];
char * pch;
void setup(){ //ESTADO INICIAL DOS BOTOES 0 -> desligado, 1 -> ligado: estado_botao[1] = 0; estado_botao[2] = 0; estado_botao[3] = 0; estado_botao[4] = 0; estado_botao[5] = 0; estado_botao[6] = 0; estado_botao[7] = 0; estado_botao[8] = 0; estado_botao[9] = 0; estado_botao[10] = 0; estado_botao[11] = 0; estado_botao[12] = 0; estado_botao[13] = 0; estado_botao[14] = 0; estado_botao[15] = 0; estado_botao[16] = 0; estado_botao[17] = 0; estado_botao[18] = 0; estado_botao[19] = 0; estado_botao[20] = 0; estado_botao[21] = 0; estado_botao[22] = 0; estado_botao[23] = 0; estado_botao[24] = 0; estado_botao[25] = 0; estado_botao[26] = 0; estado_botao[27] = 0; estado_botao[28] = 0; estado_botao[29] = 0; estado_botao[30] = 0; estado_botao[31] = 0; estado_botao[32] = 0; estado_botao[33] = 0; estado_botao[34] = 0; estado_botao[35] = 0; estado_botao[36] = 0; estado_botao[37] = 0; estado_botao[38] = 0; estado_botao[39] = 0; estado_botao[40] = 0;
Serial.begin(9600);
Serial.println("Inicializando cartao microSD..."); if (!SD.begin(4)) { Serial.println("ERRO - inicializacao do cartao falhou!"); return; } Serial.println("SUCESSO - cartao microSD inicializado.");
if (!SD.exists("index.htm")) { Serial.println("ERRO - index.htm nao foi encontrado!"); return; } Serial.println("SUCESSO - Encontrado arquivo index.htm.");
Ethernet.begin(mac, ip); server.begin();}
void loop(){ EthernetClient client = server.available(); //verifica se existe alguém querendo se conectar
if (client) { // existe cliente? boolean currentLineIsBlank = true; while (client.connected()) { if (client.available()) { // Existe informacao vinda do cliente char c = client.read(); // Le cada byte enviado pelo cliente, ou seja, cada caracter. // Por padrao, o ultimo caracter enviado pelo cliente (nosso navegador) é em branco e termina com \n // Dessa forma conseguimos saber se o cliente acabou de enviar informacoes para o servidor (Arduino) if (req_index < (REQ_BUF_SZ - 1)) { HTTP_req[req_index] = c; // salva os caracteres das solicitacoes do browser req_index++; } if (c == '\n' && currentLineIsBlank) { // envia para o cliente o protocolo padrao de sucesso HTTP client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); client.println();
//caso a request seja pela ação de um botão: if (StrContains(HTTP_req, "ajax_botao")) { for (int i = 1 ; i <= 40 ; i++) { //Serial.println(HTTP_req); char botao[] = "botaoxx"; if (i < 10) { botao[5] = '0'; botao[6] = '0' + i; } else { botao[5] = '0' + (i / 10); botao[6] = '0' + (i % 10); }
//Serial.println(botao); if (StrContains(HTTP_req, botao)) { SetBotao(i, client); } } } else { // grava no arquivo webFile a página que temos no microSD webFile = SD.open("index.htm"); if (webFile) { while (webFile.available()) { client.write(webFile.read()); // envia para o cliente a página - nessa linha de fato o Arduino imprime no browser a página } webFile.close(); } } Serial.println(HTTP_req); //para debug, verifica no monitor serial a requisição req_index = 0; //reseta o index do buffer e a variável que armazena as requisições StrClear(HTTP_req, REQ_BUF_SZ); break; } // toda linha de texto recebida do cliente termina com \r\n if (c == '\n') { //verifica se acabou a linha, já que \n é o ultimo caracter currentLineIsBlank = true; } else if (c != '\r') { // o cliente ainda está enviando informações currentLineIsBlank = false; } } } delay(1); // dá um tempo para o browser receber os dados client.stop(); // fecha a conexão }}
void SetBotao(int botao, EthernetClient client) {
int modulo = (botao - 1) / 4 + 1; int rele = botao % 4; if (rele == 0) { rele = 4; }
Serial.print("modulo:"); Serial.print(modulo); Serial.print(" rele:"); Serial.print(rele); Serial.print(" - ");
if (estado_botao[botao] == 0) { relays.SetRelay(rele, SERIAL_RELAY_ON, modulo); delay(500); estado_botao[botao] = 1; //client.print("1"); Serial.println("1"); relays.SetRelay(rele, SERIAL_RELAY_OFF, modulo); delay(500); estado_botao[botao] = 0; //client.print("0"); Serial.println("0"); } else { } client.print("0|"); for (int i = 1 ; i <= 40 ; i++) { client.print(estado_botao[i]); client.print("|"); }
}
// funcao para limpar arrays (no nosso caso, as variaveis que armazenam requests)void StrClear(char *str, char length){ for (int i = 0; i < length; i++) { str[i] = 0; }}
// funcao que procura pela string SFIND em STR// retorna 1 se a string for encontrada// retorna 0 se a setring não for encontradachar StrContains(char *str, char* sfind){ char found = 0; char index = 0; char len;
len = strlen(str);
if (strlen(sfind) > len) { return 0; } while (index < len) { if (str[index] == sfind[found]) { found++; if (strlen(sfind) == found) { return 1; } } else { found = 0; } index++; } return 0;}…
muita coisa, levando em consideração que ele nem deveria existir.
Então comprei uma pasta térmica chamada "thermal grizzly kryonaut" (LINK AQUI) para substituir a do CPU e GPU. Esta pasta ficou muito popular por ser excelente para overclock (não é meu caso) e possui uma boa capacidade de transferência térmica (12.5 W/mk -- O que exatamente isso quer dizer? eu não sei. Mas o pessoal escolhe as pastas baseadas nessa referência). Além disso, limpei o heatpipes (escova e álcool isopropílico) e as saídas de ar, que estavam parcialmente obstruídas (usei uma agulha com linha, pois eu não tinha jato de ar). Ficou ótimo.
Após aplicação e limpeza, o CPU throttling permaneceu, mas caiu o pico para 33%. Ainda assim, é muito alto.
Comecei a me questionar se não era devido a idade do notebook (2014~2015) ou problema na construção do mesmo, tendo em vista que só possui 1 fan e 2 heatpipes (1 para cpu e 1 para gpu).
*EDITADO*
A placa mãe é uma Clevo W35xSS_370ss, equipada com um i7 4710mq e uma GTX860m. A foto a seguir não foi tirada do meu notebook, mas a construção é a mesma é muito similar. Pode considerar a ventoinha + heatpipes (a diferença é mínima, SE existir).
obs- Para quem tiver dúvidas, o "CPU throttling" é um recurso onde o processador controla sua temperatura através da redução da performance. Isso normalmente só ocorre quando o processador atinge a temperatura limite de segurança. No meu caso, 100ºc.
A título de curiosidade, este problema ocorre somente quando é exigido muita performance da maquina. Neste exato momento (12 abas do chrome, com youtube tocando musica, vários programas leves abertos e etc...) a situação está extremamente estável (ventoinha está até "parada", se colocar no máximo, a temperatura cai mais ainda).
(abaixo, computador "parado")
(Abaixo, Aida64, após 10minutos de Stress de CPU+GPU)
(Abaixo, HWmonitor, informando a temperatura Máxima durante o teste que fiz com o Aida64)
Obs- veja que neste teste, não foi registrado os 100ºc, mas teve queda com pico de 33%.
Então... limpeza feita, pasta trocada... e agora? O que fazer?
Ainda que eu não acredite que o problema seja na ventoinha, mas acabei comprando uma na china. Vai demorar um pouco para chegar, em breve posto a diferença.
As outras opções que tenho são:
a) Trocar conjunto de heatpipes.
- Pode ser uma boa alternativa. Estou considerando a possibilidade.
b) adicionar um exaustor externo.
- Pensei em adquirir um exaustor como a da foto a seguir. Fiz algumas pesquisas rápidas no youtube, mas o resultado foi "inconclusivo". Alguns defendem, outros condenam. Isso devido a própria potencia que a ventoinha nativa de alguns notebooks já possuem, fazendo com que o exaustor acelere (caso a ventoinha do notebook seja mais fraca) ou "trave" (caso seja mais forte) o fluxo de ar.
c) adicionar uma base refrigeradora (a queridinha popular).
- A ideia aqui, PARECE simples, mas honestamente eu não entendi direito como funciona.
(Exemplo de base para notebook)
Em todas as base de notebooks, teremos algumas características que são iguais:
- Todas tem de 1 á 6 ventoinhas
- 99% possuem um gradeado na superfície.
- Até onde EU SEI, todas usam USB do PC para alimentação.
Mas afinal, como é o funcionamento dessas bases? Qual a ideia? qual o princípio?
- A ideia seria deixar o gradeado "frio" para que o notebook puxasse "ar frio"? O que não faz muito sentido, pois o notebook vai esquentar o gradeado.
- Se a ideia for aumentar o fluxo de ar, qual a finalidade da grade? afinal, ela reduz o fluxo.
- Não seria melhor remover o gradeado e deixar a ventoinha batendo direto?
- A alimentação da USB é muito fraca!
Afinal, como ela realmente funciona? qual o ponto mais importante?
Atualmente tenho uma bem similar a essa, da clone (comprei na mesma época que o computador). Honestamente, nunca senti diferença alguma, mas sempre usei pois evitava que as entradas de ar ficassem tapadas em superfícies que não fossem linear ou lisas (cama, por exemplo).
Estou pensando em montar uma com PVC (isso mesmo.. pvc), e colocar 2 ventoinhas de 130CFM cada uma (12v e 1,5a total). Mas antes de iniciar a empreitada, gostaria de saber um pouco mais sobre o assunto.
Caso algum colega possa agregar algum conhecimento ao tópico, eu ficaria bastante contente.…
Adicionado por tiago merces ao 15:55 em 3 dezembro 2021
om 10 botoes, blz! fiz a montagem e envie o código que foi criado pelo dono do projeto ao Arduino e tudo funcionou perfeitamente, esta aplicação estou usando em minha casa para acionamento de cargas: lampadas tvs e ventiladores e etc... ate aqui tudo tranquilo, acesso pela internet via celular na rede interna e externa tudo perfeito. Agora vou falar o que preciso, eu não sei quase nada de programação da linguagem C++, criei um aplicativo no MIT Inventor 2 e gostaria de usar o meu próprio aplicativo, não sei como criar as regras nos código para enviar para ao arduino é nisso que gostaria da ajuda de meus caros amigos deste conceituado fórum, estou tentando ler algumas coisas sobre este assunto, mais ainda não cheguei a entender, por isso que venho aqui, tentar alguns esclarecimento se possível para acrescentar no desenvolvimento de meus conhecimentos para esta necessidade.
Segue abaixo aplicativo que criei para Android:
tem as duas imagens ON e OFF, pra quando eu clicar ela mudaria a imagem para ON e vise-verso
O aplicativo e o código a baixo é o que eu comprei na PlayStore e está funcionado perfeitamente, gostaria de poder trocar os nomes laterais aos botoes e personalizar de acordo com minhas necessidade. ex colocar o nome do primeiro botão ao invés de ser "A0 OUT 5V" para "GARAGEM" não sei se isto seria melhor, não sei onde estão estas informações no código. agradeço se me for esclarecido estas duvidas.
#include <SPI.h>
#include <String.h>
#include <Ethernet.h>
//-------------------------------------------------------------------
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };//MAC padrão;
IPAddress ip(192, 168, 1, 120);//Define o endereco IPv4(trocar final);
IPAddress gateway(192, 168, 1, 1); //Define o gateway
IPAddress subnet(255, 255, 255, 0); //Define a máscara de rede
EthernetServer server(8090); // Porta de serviço
//-------------------------------------------------------------------
int AA0 = A0;//Arduino analogica A0;
int AA1 = A1;//Arduino analogica A1;
int AA2 = A2;//Arduino analogica A2;
int AA3 = A3;//Arduino analogica A3;
int AA4 = A4;//Arduino analogica A4;
//-------------------------------------------------------------------
int D2 = 2;//Arduino digital D2; int D3 = 3;//Arduino digital D3; int D4 = 4;//Arduino digital D4; int D5 = 5;//Arduino digital D5; int D6 = 6;//Arduino digital D6; //------------------------------------------------------------------- String readString = String(30); // string para buscar dados de endereço boolean statusA0 = false; // Variável para o status do led boolean statusA1 = false; // Variável para o status do led boolean statusA2 = false; // Variável para o status do led boolean statusA3 = false; // Variável para o status do led boolean statusA4 = false; // Variável para o status do led boolean statusD2 = false; // Variável para o status do led boolean statusD3 = false; // Variável para o status do led boolean statusD4 = false; // Variável para o status do led boolean statusD5 = false; // Variável para o status do led boolean statusD6 = false; // Variável para o status do led //-------------------------------------------------------------------- void setup(){ // Inicia o Ethernet //Ethernet.begin(mac, ip); Ethernet.begin(mac, ip, gateway, subnet); server.begin(); //-----------------------Define pino como saída----------------------- pinMode(AA0, OUTPUT); pinMode(AA1, OUTPUT); pinMode(AA2, OUTPUT); pinMode(AA3, OUTPUT); pinMode(AA4, OUTPUT); pinMode(D2, OUTPUT); pinMode(D3, OUTPUT); pinMode(D4, OUTPUT); pinMode(D5, OUTPUT); pinMode(D6, OUTPUT); //--------------------------------------------------------------------- // Inicia a comunicação Serial Serial.begin(9600); }
void loop(){ // Criar uma conexão de cliente EthernetClient client = server.available(); if (client) { while (client.connected()) { if (client.available()) { char c = client.read(); // ler caractere por caractere vindo do HTTP if (readString.length() < 30) { // armazena os caracteres para string readString += (c); } //se o pedido HTTP terminou if (c == '\n') { //------------------------------------------------------------------ if(readString.indexOf("a0high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(AA0, HIGH);//Arduino porta digital D2=5V; statusA0 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("a0low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(AA0, LOW);//Arduino porta digital D2=0V; statusA0 = false; } //------------------------------------------------------------------ if(readString.indexOf("a1high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(AA1, HIGH);//Arduino porta digital D2=5V; statusA1 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("a1low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(AA1, LOW);//Arduino porta digital D2=0V; statusA1 = false; } //------------------------------------------------------------------ if(readString.indexOf("a2high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(AA2, HIGH);//Arduino porta digital D2=5V; statusA2 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("a2low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(AA2, LOW);//Arduino porta digital D2=0V; statusA2 = false; } //------------------------------------------------------------------ if(readString.indexOf("a3high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(AA3, HIGH);//Arduino porta digital D2=5V; statusA3 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("a3low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(AA3, LOW);//Arduino porta digital D2=0V; statusA3 = false; } //------------------------------------------------------------------ if(readString.indexOf("a4high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(AA4, HIGH);//Arduino porta digital D2=5V; statusA4 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("a4low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(AA4, LOW);//Arduino porta digital D2=0V; statusA4 = false; } //------------------------------------------------------------------ if(readString.indexOf("d2high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(D2, HIGH);//Arduino porta digital D2=5V; statusD2 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("d2low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(D2, LOW);//Arduino porta digital D2=0V; statusD2 = false; } //------------------------------------------------------------------ if(readString.indexOf("d3high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(D3, HIGH);//Arduino porta digital D2=5V; statusD3 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("d3low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(D3, LOW);//Arduino porta digital D2=0V; statusD3 = false; } //------------------------------------------------------------------ if(readString.indexOf("d4high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(D4, HIGH);//Arduino porta digital D2=5V; statusD4 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("d4low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(D4, LOW);//Arduino porta digital D2=0V; statusD4 = false; } //------------------------------------------------------------------ if(readString.indexOf("d5high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(D5, HIGH);//Arduino porta digital D2=5V; statusD5 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("d5low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(D5, LOW);//Arduino porta digital D2=0V; statusD5 = false; } //------------------------------------------------------------------ if(readString.indexOf("d6high")>=0)//Recebido do Android; { // O Led vai ser ligado digitalWrite(D6, HIGH);//Arduino porta digital D2=5V; statusD6 = true; } // Se a string possui o texto L=Desligar if(readString.indexOf("d6low")>=0)//Recebido do Android; { // O Led vai ser desligado digitalWrite(D6, LOW);//Arduino porta digital D2=0V; statusD6 = false; } //------------------------------------------------------------------ // dados HTML de saída começando com cabeçalho padrão client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(); client.print("<font size='20'>"); //------------------------------------------------------------------ if (statusA0) { client.print("azeroon");//Ethernet envia para Android; //String apenas letras; } else { client.print("azerooff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusA1) { client.print("aoneon");//Ethernet envia para Android; //String apenas letras; } else { client.print("aoneoff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusA2) { client.print("atwoon");//Ethernet envia para Android; //String apenas letras; } else { client.print("atwooff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusA3) { client.print("athreeon");//Ethernet envia para Android; //String apenas letras; } else { client.print("athreeoff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusA4) { client.print("afouron");//Ethernet envia para Android; //String apenas letras; } else { client.print("afouroff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusD2) { client.print("dtwoon");//Ethernet envia para Android; //String apenas letras; } else { client.print("dtwooff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusD3) { client.print("dthreeon");//Ethernet envia para Android; //String apenas letras; } else { client.print("dthreeoff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusD4) { client.print("dfouron");//Ethernet envia para Android; //String apenas letras; } else { client.print("dfouroff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusD5) { client.print("dfiveon");//Ethernet envia para Android; //String apenas letras; } else { client.print("dfiveoff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ if (statusD6) { client.print("dsixon");//Ethernet envia para Android; //String apenas letras; } else { client.print("dsixoff");//Ethernet envia string para Android; //String apenas letras; } //------------------------------------------------------------------ //limpa string para a próxima leitura readString=""; // parar cliente client.stop(); } } } } }…
rir o valor dos resistores, procurei a imagem no Google, e encontrei o site onde a mesma foi postado (infelizmente vc não disse onde). Lá havia uma lista de componentes, e o link para o datasheet (que anexei ao final do post). Os valores dos componentes listados no site, são razoáveis e corretos para esse sensor. Usa um capacitor eletrolítico de alumínio, mas isso não é problema, já que a frequência é a da rede elétrica (60Hz), o que garante que o eletrolítico de alumínio funcione corretamente. Mas vc pode melhorar isso, se colocar um capacitor cerâmico entre 100kpF e 1uF, ligado em paralelo com o eletrolítico.
Dito isto, há duas observações principais sobre seu circuito:
1) os dois resistores que vc desenhou, estão com o valor inadequado de 100 kohm. No site "original" são de 10 kohm. Estes dois resistores são usados para criar um "GND Virtual" de 2,5V, que funciona como um "bias" para a escala analógica do Conversor A/D do Arduino (na figura original está conectado à entrada analógica "A1"). Para isso, os dois resistores devem ter o mesmo valor. Logo mesmo com os 100 kohm que vc desenhou, acaba funcionando, mas não é a melhor solução em termos de estabilidade (pois a impedância equivalente é alta). Já com os resistores originais do site, 10 kohm, a estabilidade é 10 vezes maior, pois a impedância equivalente é 10 vezes mais baixa. Então aconselho usar 10 kohm.
2) a conexão ao "P2" segundo o datasheet do sensor, é mostrada na figura a seguir (retirei do datasheet e colori para ficar fácil referenciar):
Observe que a saída de sinal é entre a ponta do P2 que no seu desenho é o "Left", e o "terra" que no seu desenho tem três designações "Ground"/"SLEEVE"/"TERRA". Então segundo estas informações, a conexão que vc fez está correta.
Mas mais uma coisa importante: a saída de sinal resultante, tem um "spam" de cerca de 1V. Ou seja, para a variação total de 100A, a faixa de conversão do A/D do Arduino será de 1V. Não olhei o código do programa que vc deve ter obtido do site, mas certamento está fazendo a conversão correta do canal analógico. Como para o canal analógico o "zero" é o 2,5V, e como o "spam" é de cerca de 1V, a variação irá de 2V a 3V, para a faixa de 100A.
O "spam" calculei assim: no datasheet, o fundo de escala indicado na saída do sensor, é de 33mA, conforme a figura a seguir:
Logo, como o resistor de carga que está sendo usado é de 33 ohm, a variação de tensão (o "spam"), será: 33ohm x 33mA = 1,089 Volts. Ou seja, cerca de 1V.
Portanto, para dobrar a resolução (e portanto a "qualidade" da medição), vc pode mudar o resistor para 68 ohm, dobrando assim o spam para cerca de 2,2V. Claro que se fizer isso, deve reajustar os cálculos feitos no código do Arduino. Segundo o datasheet, há diodos de proteção dentro do sensor, e estes poderiam limitar o "spam", mas acredito que a tensão de condução destes diodos sejam bem mais acima desses 2,2V resultantes, e não ocorreria esta limitação.
Dica importante: leia com atenção a observação no final do datasheet sobre o uso do sensor, a qual mostro na figura a seguir, pois isso é importante para não "fritar" seu Arduino (pois nenhuma proteção mais rigorosa está sendo feita), e pra não ter risco de choques elétricos perigosos na saída do sensor (cuidado a ser tomado com qualquer sensor deste tipo).
Espero ter ajudado. Fique à vontade para quaisquer dúvidas que eu possa esclarecer.
Abrçs,
Elcids
datasheet do sensor: SCT-013-datasheet.pdf…
Adicionado por Elcids Chagas ao 18:41 em 31 janeiro 2019
o o primeiro o modo estaconário, o segundo o modo LDR, e o terceiro entra no modo RTC DS 1302.
A lógica é a seguinte: no modo LDR ele faz a varredura pela diferença entre os LDRs e faz o movimento dos motores de modo a posicionar o módulo em direção ao sol, (essa parte está ok). O modo RTC vai ter 12 posicoes pré determinadas, dependendo apenas da hora do dia (ESSA PARTE É O PROBLEMA), já o modo estacionário vai ficar parado em uma inclinação especifica(ESSA PARTE ESTÀ OK). A idéia por tras disso é a seguinte: a cada hora vou medir corrente e tensão no módulo, e quero comparar a eficiencia dos 3 modos distintos. Estou utilizando Arduino UNO, DVR 8825 controlador de motor de passo LDRs e DS 1302 RTC. O Código está assim por enquanto;
#include <AccelStepper.h>#include <ThreeWire.h>#include <RtcDS1302.h>
// Pinos dos sensores LDR
int ldrLeftTopPin = A2; // amaint ldrLeftBottomPin = A0; // verint ldrRightTopPin = A3; // larint ldrRightBottomPin = A1; // preint limiar = 20; // Valor para corrigir diferença entre os LDR'sint Vel = 500; // Velocidade do motor em passos por segudoint MaxSpeed = 1000; // Velocidade máxima que o motor pode atingirint Acelera = 500; // Aceleração dos motoresint modo = 0;// 0 = Estacionário, 1 = LDR, 2 = DS1302int BUTTON_PIN = 7; // Pino do botãoconst int NUM_MODOS = 3;
// Pinos dos motores de passo#define azimuthDirPin 2#define azimuthStepPin 3#define elevationDirPin 4#define elevationStepPin 5#define motorInterfaceType 1 //Motor com dois fios para cada bobina (2 bobinas)
// Pinos RTC#define DS1302_RST 8#define DS1302_DAT 9#define DS1302_CLK 10
// Instância da ligação e do RTCThreeWire ligacao(DS1302_DAT, DS1302_CLK, DS1302_RST);RtcDS1302<ThreeWire> rtc(ligacao);bool buttonWasPressed = false;bool buttonState = false;bool lastButtonState = false;unsigned long lastDebounceTime = 0;unsigned long debounceDelay = 50;
// Instância da classe AccelStepper para cada motorAccelStepper azimuthStepper(motorInterfaceType, azimuthStepPin, azimuthDirPin);AccelStepper elevationStepper(motorInterfaceType, elevationStepPin, elevationDirPin);
void setup() { // Inicia a comunicação serial Serial.begin(9600); // Velocidade máxima em passos por segundo para ambos os motores azimuthStepper.setMaxSpeed(MaxSpeed); azimuthStepper.setAcceleration(Acelera); elevationStepper.setMaxSpeed(MaxSpeed); elevationStepper.setAcceleration(Acelera); pinMode(BUTTON_PIN, INPUT_PULLUP); // Inicia a comunicação com o RTC rtc.Begin(); // Desabilita a proteção contra escrita para gravar a hora e data if (rtc.GetIsWriteProtected()) { rtc.SetIsWriteProtected(false); }
// Se não estava rodando, começa a funcionar if (!rtc.GetIsRunning()) { rtc.SetIsRunning(true); // Obtém o valor da hora quando o código foi compilado RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__); rtc.SetDateTime(compiled); // Para definir um formato personalizado, você pode fazer o seguinte: // O mês precisa ter 3 letras abreviando o nome do mês em inglês (no exemplo abaixo é fevereiro) //RtcDateTime teste = RtcDateTime("Feb 12 2022", "19:32:45"); //rtc.SetDateTime(teste); }}
void loop() { unsigned long currentMillis = millis(); buttonState = digitalRead(BUTTON_PIN);
if (buttonState != lastButtonState) { lastDebounceTime = currentMillis; }
if ((currentMillis - lastDebounceTime) > debounceDelay) { if (buttonState != buttonWasPressed) { buttonWasPressed = buttonState;
if (buttonWasPressed) { // Botão pressionado, alterna entre os modos modo = (modo + 1) % NUM_MODOS; } } }
lastButtonState = buttonState; switch (modo) { case 0: // Modo Estacionário // Coloque o código para o modo estacionário aqui Serial.print("MODO : " ); // Mostra o valor no monitor serial Serial.println(modo); break;
case 1: // Modo LDR Serial.print("MODO : " ); // Mostra o valor no monitor serial Serial.println(modo); // Leitura dos sensores LDR int ldrLeftTopValue = analogRead(ldrLeftTopPin); int ldrLeftBottomValue = analogRead(ldrLeftBottomPin); int ldrRightTopValue = analogRead(ldrRightTopPin); int ldrRightBottomValue = analogRead(ldrRightBottomPin);
// Calculando as diferenças para ambos os eixos int azimuthDifference = (ldrLeftTopValue - ldrRightTopValue) + (ldrLeftBottomValue - ldrRightBottomValue); int elevationDifference = (ldrLeftTopValue - ldrLeftBottomValue) + (ldrRightTopValue - ldrRightBottomValue); // Ajustando a posição dos motores de passo com base nas diferenças dos sensores if (abs(azimuthDifference) > limiar) { // Limiar de diferença para evitar pequenos movimentos if (azimuthDifference > 0) { // Mova o motor de passo de azimuth para a esquerda azimuthStepper.setSpeed(Vel); azimuthStepper.runSpeed(); // Move o motor } else { // Mova o motor de passo de azimuth para a direita azimuthStepper.setSpeed(-Vel); // (sentido inverso) azimuthStepper.runSpeed(); // Move o motor } }
if (abs(elevationDifference) > limiar) { // Limiar de diferença para evitar pequenos movimentos if (elevationDifference > 0) { // Mova o motor de passo de elevação para cima elevationStepper.setSpeed(Vel); // elevationStepper.runSpeed(); // Move o motor } else { // Mova o motor de passo de elevação para baixo elevationStepper.setSpeed(-Vel); // (sentido inverso) elevationStepper.runSpeed(); // Move o motor } } break; case 2: // Modo DS1302 Serial.print("MODO : " ); // Mostra o valor no monitor serial Serial.println(modo); // Obtem a data e hora e imprime os valores RtcDateTime now = rtc.GetDateTime();
Serial.print(now.Day()); Serial.print("/"); Serial.print(now.Month()); Serial.print("/"); Serial.println(now.Year());
Serial.print(now.Hour()); Serial.print(":"); Serial.print(now.Minute()); Serial.print(":"); Serial.println(now.Second());
// Dia da semana (1 a 7, sendo 1 = segunda e 7 = domingo) Serial.println(now.DayOfWeek()); delay(50); break; }}…
s o próprio EMI gerado pelo circuito, é mais de 90% provocado pelo overshoot (intensidade e frequência). E certamente esse EMI será um imenso problema em equipamentos comerciais (se for muito alto, nem será aprovado em ensaios de certificação).
Então agora podemos abrir o jogo um pouco mais, assim colaborando com outros que venham aqui no LDG procurando informação relacionada.
Vamos resumir as coisas assim:
1) o chaveamento da corrente em L2, gera impulsos de tensão que tendem a ser os impulsos unitários, porém estes são do mundo real (tem amplitude limitada e a largura do pulso não é zero). Estes impulsos nada mais são portanto, do que "pacotes" de energia que que são enfiados pela guela do capacitor na saída do seu Conversor DC/DC. Cada novo impulso acrescenta um novo pacote de carga "dQ" ao Capacitor de saída, o que por sua vez se traduz num delta de tensão. Sem uma carga resistiva na saída, com o passar do tempo, a tensão sobre esse Capacitor tenderá a alcançar praticamente quase o mesmo valor do impulso, e isto ocorre porque simplesmente estamos pegando um "pacote" de carga "dQ", e jogando em cima de um valor de capacitância de saída muito alto (no seu caso, C4 de 2000uF), e pela equação V = Q/C, pode-se calcular não somente o degrau de tensão dV, mas a própria tensão final sobre o Capacitor após cada novo impulso.
2) mas ao termos uma carga resistiva na saída, parte de cada "dQ" é também usado para alimentar esta carga resistiva, o que implica que esta carga resistiva atua justamente como o "outro lado do cabo de guerra", e assim "trabalha" no sentido de reduzir a tensão sobre o Capacitor de saída. Ao final das contas, espera-se que a taxa de impulsos por segundo, seja suficiente para equilibrar esse cabo de guerra, fazendo com que a tensão sobre o Capacitor se estabilize em torno de um valor médio (na realidade, ela acaba oscilando em torno do valor médio, e este é o ripple real na saída). A taxa de impulsos é a própria frequência de chaveamento, e ela acaba por bombear impulsos de "dQ" para o Capacitor de saída. Maior taxa (frequência), compensação mais rápida. Menor taxa, compensação mais lenta. Um algorítimo de controle de malha fechada, então nada mais faz do que ajustar essa taxa para que a saída tenha o comportamento de tensão esperado: quase constante para uma tensão DC, ou em "arco" crescente ou decrescente para uma saída senoidal. Claro que neste último caso, você poderá variar a própria tensão de entrada (como vc mencionou que já o fez), e assim terá também uma variável a mais na sua equação, que será a intensidade de cada pacote de energia "dQ", e assim tendo um maior controle sob o comportamento da tensão de saída.
3) o fato de ser Buck, Boost, é apenas o resultado da manipulação da intensidade e frequência dos pacotes "dQ", já que estes acrescentam energia ao Capacitor de saída, determinando a tensão sobre este capacitor, ou seja, simplesmente um resultado da conversão V = Q/C, considerando que parte da energia acumulada no Capacitor de saída está sendo drenada por uma carga resistiva (formando o "cabo de guerra" entre consumo e "bombeamento" de energia).
4) e o fato de ser saída positiva ou negativa, é apenas a configuração de como vc direciona os impulsos "dQ" para o Capacitor de saída, ou seja: determinado pela polaridade do Diodo na saída (no seu circuito, D2), que é o elemento chave nisto. Obviamente a polaridade do Capacitor deverá estar de acordo com a tensão resultante desse direcionamento.
5) as diversas configurações mostradas no "slyu036" da Texas, nada mais são do que uma exploração das possíveis variações do que foi descrito acima, inclusive recombinando os circuitos e aplicando o controle adequado ao chaveamento para se obter as características de conversão DC/DC desejadas.
6) uma pequena parte do "dQ" do impulso, acaba injetando energia em um "inesperado" Circuito Tanque LC, composto pelo próprio Indutor do chaveamento de corrente e pela capacitância parasítica existente ali, resultando na oscilação amortecida de alta frequência determinada por Freq = 1/(2*Pi*raiz(LC)). Observe que qualquer chaveamento da corrente do Indutor, irá provocar o impulso de tensão, devido ao Ldi/dt, e havendo alguma capacitância parasítica formando um Circuito Tanque LC, certamente existirá o overshoot senoidal amortecido, na frequencia natural do tanque LC.
7) sempre haverá dois overshoots, pois o indutor é chaveado duas vezes em cada ciclo do seu PWM. Em um dos edges do PWM, a capacitância parasítica do Diodo formará com o Indutor, o circuito tanque LC, resultando em um overshoot. No edge seguinte, será a capacitância parasítica entre Gate e Dreno do MOSFET que se juntará ao Indutor para formar o tanque LC, e um overshoot com outra frequencia e intensidade ocorrerá.
8) e finalmente: como capacitores também são elementos de acoplamento de tensão, uma capacitância parasítica entre dois pontos, acoplará o overshoot no outro nó correspondente ao outro lado desse capacitor. É por isso Dário, que no seu próprio sinal PWM também acaba aparecendo o overshoot (mesma frequência, mas com outra intensidade, que pode ser calculada por um divisor de tensão com impedâncias imaginárias).
Agora sobre o tratamento:
1) observe que estes circuitos procuram usar diodos do tipo "Schottky", pois estes além de serem rápidos tem uma menor "capacitância de barreira" que os diodos "PN" convencionais. Os "Schottky" também tem uma menor resistência de corpo (BULK), o que diminui as perdas por efeito Joule. Observe que nos APNs, vc sempre verá diodos "Schottky" sendo usados (naquela plaquinha da China, também).
2) observe qual a capacitância parasítica intrínseca entre Dreno e Gate do MOSFET, e claro ela deve ser a menor possível, e se deve tomar o cuidado para não acrescentar circuitos ali que causem aumento significativo dessa capacitância entre Dreno e Gate. Observe também que devido ao proprio liga/desliga do MOSFET, capacitâncias parasíticas entre Dreno e Source também podem injetar um "dQ" no Dreno, causando também um overshoot. Logo, a chave aqui, é escolher MOSFETs que tenham sido projetados para chaveamento em circuitos conversores DC/DC de alta frequência, pois certamente suas capacitâncias terão valores menores. Usar MOSFETs originalmente projetados apenas para um ON/OFF convencional, poderá ser um tiro no pé.
3) o Capacitor Eletrolítico de Alumínio de alto valor usado como parte essencial do conversor DC/DC, não irá amenizar o overshoot na saída, porque este tipo de Capacitor tem também uma alta indutância equivalente (ESI), e portanto não filtra a alta frequência do overshoot. Para esta tarefa, sempre se deve usar em paralelo com o Eletrolítico de Alumínio (no seu caso o "C4" de 2000uF), ou um Capacitor de Tântalo ou um de Cerâmico, os quais tem uma baixa indutância equivalente. Veja que nos datasheets desses conversores DC/DC integrados, sempre é especificado o acréscimo de um Capacitor de Tântalo ou do tipo Cerâmico, justamente pelo motivo delineado. Usar combinação de Tântalo e Cerâmico, também é uma ótima alternativa, principalmente em termos de custo e eficiência.
4) usar técnicas pontuais caso seja realmente necessário, como os "snubers" do artigo que vc citou (o do Marcin Walczak). Mas antes disso, deve-se obrigatoriamente aplicar as técnicas convencionais citadas acima (todas devem ser usadas, sem exceção). Caso o overshoot ainda resulte ser acima do mínimo aceitável para sua aplicação, então parte-se para aplicar técnicas pontuais e especializadas.
Fico por aqui, pois um pouco mais disso vai me dar overshoot.
Mas claro, se houver algo mais que eu possa ajudar e esteja ao meu alcance, vamos em frente.
Abrçs,
Elcids…
Adicionado por Elcids Chagas ao 5:46 em 14 março 2019