a perfeitamente possível (e bastante didático também), é bastante trabalhoso. Por este motivo, implementei um Sistema com Arduino para fazer a mesma coisa, mas de forma "automatizada", pois acredito que o ajudará muito caso esteja querendo aprender. Mas a descrição deste Sistema e sua implementação estão mais à frente (juntamente com a Simulação no Proteus).
Antes, vamos ver algumas características do TLC5628, que precisam ser entendidas pra que se possa programá-lo, seja de forma manual como no seu esquema, seja de forma automatizada.
Para isso, vejamos primeiro o Diagrama em Blocos Funcional do TLC5628, que mostro na figura a seguir, observando que marquei algumas regiões com cores:
(clique na figura para "zoom")
Vc pode identificar facilmente os DACs do TLC5628, que estão na metade à direita do centro da figura anterior. Na figura são mostrados apenas 4 DACs, mas de fato são 8, e são numerados de 0 a 7, ou seja: "DAC0", "DAC1", "DAC2",..., até o "DAC7". Cada DAC é de 8 bits, o que significa que tem um "range" de 256 níveis. Então o que queremos é setar a saída de um determinado DAC em um desses 256 níveis. Como fazer isso?
Para reduzir o número de sinais de controle para programar o TLC5628 e consequentemente seus 8 DACs, foi adotada uma Interface Serial muito simples, semelhante à famigerada SPI. Os dois sinais principais desta Interface são o "CLK" e o "DATA". Então para programar o TLC5628, vc deve especificar qual dos 8 DACs vc deseja setar, e também qual o valor deseja setar naquele DAC. Como a Interface é serial, vc deve enviar estas informações, bit a bit, através dos sinais "CLK" e "DATA". Isto é simples e pode ser visto na temporização mostrada na figura a seguir:
(clique na figura para "zoom")
Note que os bits "A2", "A1" e "A0" são enviados primeiro, nesta ordem. Eles especificam qual dos 8 DAC vc deseja programar. Esta seleção pode ser vista na tabela na figura a seguir:
(clique na figura para "zoom")
O bit "RNG", significa "Range", e determina se vc estará ou não "multiplicando" por 2 a faixa representada pela "Tensão de Referência" do DAC. Aqui estarei assumindo que RNG = 0, ou seja, a faixa do DAC será determinada pela tensão VREF sem multiplicar seu valor por 2. Sobre esta questão falarei novamente no final deste post.
Então parece que tudo que é preciso fazer é ir enviando os bits de seleção do DAC (área marcada em laranja na figura anterior), juntamente com os bits de valor para o DAC (bits "D7" a "D0" marcados na cor roxa na figura anterior). O envio de cada bit ocorre na transição de "HIGH" para "LOW" do sinal "CLK". Mas na realidade não é apenas isso que precisa ser feito. Vamos ver porquê. Olhe novamente a figura do Diagrama em Blocos do TLC5628. Veja a região marcada na cor amarela. Esta é Interface Serial, que vai recebendo os bits. Veja agora a região na cor verde. Estes são os "Registros de Pre-Setting" dos DACs (e portanto existem 8 Registros). Ocorre que antes de vc enviar um valor para o DAC, vc precisa primeiro enviar este valor para o "Registro de Pre-Setting" do mesmo. Somente depois disto, vc transfere o valor armazenado no "Registro de Pre-Setting" para o "Registro de Saída" do DAC. O motivo para isto, é permitir uma característica que pode ser muito desejada: atualizar todos os 8 DACs "simultaneamente". Como? Simples: primeiro vc transfere para cada "Registro de Pre-Setting" o valor do DAC (e vc pode fazer isso em qualquer ordem). Depois que vc transferiu os valores de cada DAC para todos os 8 "Registros de Pre-Setting", então através de um único "comando" vc transfere destes para os 8 "Registros de Saída" (os azuis), o que causa a atualização "simultânea" dos 8 DACs. Este "comando" final de transferência, é através do sinal "LDAC", conforme vc pode ver na figura da temporização onde o mesmo está marcado na cor azul. Sempre que vc acionar o "LDAC", todos os "Registros de Pre-Setting" serão transferidos ao mesmo tempo para os "Registros de Saída" dos DACs. Então aqueles "Registros de Pre-Setting" que vc não alterar, permanecerão com o valor que já estava neles, e quando o "LDAC" for acionado, as saídas daqueles DACs serão atualizadas com o mesmo valor. Portanto, se vc quer alterar apenas um DAC, basta alterar o "Registro de Pre-Setting" daquele DAC, e em seguida acionar o sinal "LDAC" para atualizar os DACs. Como se pode ver, é um mecanismo bastante versátil e completo.
Mas como se altera um "Registro de Pre-Setting"? Simples: através da Interface Serial, vc envia aqueles bits de seleção do DAC, além do próprio valor de 8 bits para o DAC. Isto selecionará apenas o "Registro de Pre-Setting" que vc especificou através dos bits de seleção (A2, A1, A0). Então logo em seguida vc aciona o sinal "LOAD", o que fará que os bits de valor (D7..D0) sejam transferidos para o "Registro de Pre-Setting" selecionado. Veja na figura da temporização, o acionamento do "LOAD" (marcado em verde) logo após o bit "D0" ser enviado.
Resumindo: a transferência é sempre feita em duas etapas. Primeiro se transfere o valor para o "Registro de Pre-Setting" através da Interface Serial e do acionamento do sinal "LOAD". Depois, acionando o sinal "LDAC", todos os "Registros de Pre-Setting" são transferidos simultaneamente para os "Registros de Saída" dos DACs. Observe que esta última transferência, não altera os valores nos "Registros de Pre-Setting", ou seja, eles ficam com os mesmos valores dos "Registros de Saída" (ou seja, o sinal "LDAC" faz com que os "Registros de Saída" sejam uma cópia dos "Registros de Pre-Setting").
Na figura a seguir, mostro o Sistema implementado com Arduino UNO para o controle do TLC5628:
(clique na figura para "zoom")
No final do post, há um link para o vídeo mostrando a simulação no Proteus.
Sobre a mensagem de "Atenção" na figura anterior, falarei mais no final do post.
Observe que os Resistores R1, R2, e R3, não são obrigatórios. Mas eles garantem que os sinais de controle do TLC5628 estejam em níveis lógicos inativos logo após o Sistema ser ligado, enquanto o Arduino ainda não configurou as saídas de controle.
Sobre o código de controle, irei falar sobre alguns aspectos e parâmetros. Os pinos usados para a Interface Serial com o TLC5628, podem ser facilmente alterados, pois são definidos conforme mostrado na figura a seguir:
(clique na figura para "zoom")
A Tensão de Referência para o TLC5628, é definida em Volts, conforme mostrado na figura a seguir:
(clique na figura para "zoom")
A função que faz o envio dos bits de controle através da Interface Serial, e que portanto altera apenas o "Registro de Pre-Setting" especificado, é mostrada na figura a seguir:
(clique na figura para "zoom")
Observe que marquei três áreas na figura anterior, com as cores laranja, roxo, e verde. Estas mesmas três cores estão marcadas na figura da temporização, o que facilita entender qual parte da função está executando a respectiva parte da temporização. Note que a cor azul na figura da temporização, não está marcada nesta função, pois esta marcação em azul é do acionamento do sinal "LDAC".
E o acionamento do "LDAC", é feito na função mostrada na figura a seguir:
(clique na figura para "zoom")
No código implementado, para alterar um DAC, vc envia um comando através do Terminal do Arduino, especificando qual é o DAC e qual valor em Volts vc deseja setar naquele DAC. Vejamos um exemplo de comando para setar o DAC3:
[DAC3=1.47]
Observe que o comando inicia com "[" e termina com "]". Assim, após enviar este comando, a Saída do DAC3 terá o valor de 1.47 Volts. Claro, existe um erro de resolução, que pode refletir na segunda casa após a vírgula, já que como VREF = 2.5V, a resolução será 2.5 / 256 = 0.0098 , ou seja, praticamente 10 mV.
No vídeo da Simulação no final do post, os comandos podem ser vistos sendo digitados no Terminal do Arduino, e as tensões sendo reproduzidas no TLC5628.
As funções de recepção dos comandos via Serial do Arduino, estão separadas e bem identificadas no código, para não confundir com as partes relacionadas ao TLC5628.
Mas a decodificação e execução dos comandos foi feita na função "loop" do Arduino, por motivos didáticos. Isto pode ser visto na figura a seguir:
(clique na figura para "zoom")
Veja que o código no "loop" é simples e organizado. E para ajudar no entendimento, marquei em amarelo a decodificação do comando para o "DAC0". E em azul, é "extraído" do comando, o valor da tensão a ser setada no "DAC0". Em verde está a parte que envia o valor para o "Registro de Pre-Setting" do DAC0. E finalmente em laranja, aquele valor é transferido para o "Registro de Saída" do DAC0, concluindo o processo e a execução do comando.
No loop, isto é repetido para os comandos dos outros 7 DACs.
Observe que como já dito, vc pode setar quantos "Registros de Pre-Setting" desejar, e depois então atualizar as saídas dos respectivos DACs todas de uma vez.
Sobre as notas de atenção mostradas no esquemático da Simulação, iniciando pela nota "2)". Ela está salientada no Datasheet do TLC5628, conforme pode ser visto na figura a seguir, onde marquei em amarelo:
(clique na figura para "zoom")
Assim, como VDD = 5V, o máximo valor permitido para VREF, será 5V - 1.5V, ou seja 3.5V. Isto é uma limitação dos circuitos internos do TLC5628. Inclusive, observe que se VREF = 3.5V, se vc setar o bit "RNG", o range de saída seria 7V, o que não é possível, já que a alimentação do TLC5628 é de 5V. E mesmo assim a tensão de saída não chegará a 5V, como pode ser visto na figura a seguir ("figura 9"):
(clique na figura para "zoom")
Ocorre que, conforme vc drena corrente na saída do DAC, isto deteriora a tensão presente naquela saída. Por este motivo deve-se ter na saída cargas de alta impedância, para minimizar o problema (ver na figura anterior a parte da "figura 10"). Esta questão piora quando a tensão na saída se aproxima de 5V, pois as saídas do TLC5628 não são do tipo "full rail-to-rail". E veja na figura que mostra o máximo valor de VREF, que por isso mesmo a impedância de carga na saída não deve ser menor que 10k (a figura anterior mostra como degrada a saída nesta faixa de impedância).
Assim, caso o fornecimento de corrente seja necessário, deve-se "bufferizar" a saída do DAC, e um exemplo disso é como mostrado na figura a seguir:
(clique na figura para "zoom")
E claro: o Buffer acrescentado na figura anterior, deve atender os "rails" que vc deseja reproduzir.
O código para o Arduino e arquivos de Simulação estão aqui: "Controle_TLC5628_01.zip"
O vídeo mostrando a Simulação pode ser visto/baixado aqui: "video Simulação"
Espero ter ajudado.
abrçs,
Elcids…
Adicionado por Elcids Chagas ao 12:22 em 25 agosto 2021
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
erá a água que sai da máquina de lavar ir para uma caixa a parte que denominei como caixa principal.
Caso tenham alguma dúvida pode me contatar..
Abraços
int CHG = 2; // Chave Geral
int BCXP = 3; // Chave bóia caixa principal
int BCXA = 4; // Chave bóia caixa acoplada
int VSFAR = 5; // Válvula solenóide fecha água da rua
int BOMBA = 6; // Bomba d'água
int LEDCXPO = 7; // Led caixa principal nível OK
int LEDCXPB = 8; // Led caixa principal nível Baixo
int LEDCXAO = 9; // Led caixa acoplada nível OK
int LEDCXAB = 10; // Led caixa acoplada nível Baixo
int leituraCHG; // Leitura Chave Geral
int leituraBCXP; // Leitura Chave bóia caixa principal
int leituraBCXA; // Leitura Chave bóia caixa acoplada
int leituraVSFAR; // Leitura Válvula solenóide fecha água da rua
int leituraBOMBA; // Leitura Bomba d'água
int leituraLEDCXPO; // Leitura Led caixa principal nível OK
int leituraLEDCXPB; // Leitura Led caixa principal nível Baixo
int leituraLEDCXAO; // Leitura Led caixa acoplada nível OK
int leituraLEDCXAB; // Leitura Led caixa acoplada nível Baixo
byte comando=0;//tipo de comando a ser utilizado
String modo= "Em condições de operação";
void setup()
{
Serial.begin(9600);
pinMode(CHG,INPUT);
pinMode(BCXP,INPUT);
pinMode(BCXA,INPUT);
pinMode(VSFAR,OUTPUT);
pinMode(BOMBA,OUTPUT);
pinMode(LEDCXPO,OUTPUT);
pinMode(LEDCXPB,OUTPUT);
pinMode(LEDCXAO,OUTPUT);
pinMode(LEDCXAB,OUTPUT);
}
void loop()
{
leituraCHG=digitalRead(CHG);
leituraBCXP=digitalRead(BCXP);
leituraBCXA=digitalRead(BCXA);
leituraVSFAR=digitalRead(VSFAR);
leituraBOMBA=digitalRead(BOMBA);
leituraLEDCXPO=digitalRead(LEDCXPO);
leituraLEDCXPB=digitalRead(LEDCXPB);
leituraLEDCXAO=digitalRead(LEDCXAO);
leituraLEDCXAB=digitalRead(LEDCXAB);
// INICIO DA LÓGICA DO COMANDO
if(leituraCHG==LOW)//Chave geral desligada
{comando=0;}
else//Chave geral ligada
{
if(leituraBCXP==LOW && leituraBCXA==LOW)// As chaves de bóia no nível baixo
{comando=1;}
else if (leituraBCXP==LOW && leituraBCXA==HIGH)// Caixa principal vazia e caixa acoplada cheia
{comando=2;}
else if (leituraBCXP==HIGH && leituraBCXA==LOW)// Caixa principal cheia e caixa acoplada vazia
{comando=3;}
else if (leituraBCXP==HIGH && leituraBCXA==HIGH)// As chave de bóia no nível alto
{comando=4;}
}
//TIPOS DE COMANDOS
switch(comando)
{
case 0:// Comando desligado
modo= "Chave Geral Desligada";
Serial.print(modo);
digitalWrite(VSFAR,LOW);
digitalWrite(BOMBA,LOW);
digitalWrite(LEDCXPO,LOW);
digitalWrite(LEDCXPB,LOW);
digitalWrite(LEDCXAO,LOW);
digitalWrite(LEDCXAB,HIGH);
delay(1000);
digitalWrite(LEDCXPB,HIGH);
digitalWrite(LEDCXAB,LOW);
delay(1000);
case 1:// As chaves de bóia no nível baixo
modo= "Enchimento pela água da rua";
Serial.print(modo);
digitalWrite(VSFAR,LOW);
digitalWrite(BOMBA,LOW);
digitalWrite(LEDCXPO,LOW);
digitalWrite(LEDCXPB,HIGH);
digitalWrite(LEDCXAO,LOW);
digitalWrite(LEDCXAB,HIGH);
break;
case 2:// Caixa principal vazia e caixa acoplada cheia
modo= "Sem água na caixa principal";
Serial.print(modo);
digitalWrite(VSFAR,LOW);
digitalWrite(BOMBA,LOW);
digitalWrite(LEDCXPO,LOW);
digitalWrite(LEDCXPB,HIGH);
digitalWrite(LEDCXAO,HIGH);
digitalWrite(LEDCXAB,LOW);
break;
case 3:// Caixa principal cheia e caixa acoplada vazia
modo= "Enchimento pela caixa da caixa principal";
Serial.print(modo);
digitalWrite(VSFAR,HIGH);
digitalWrite(BOMBA,HIGH);
digitalWrite(LEDCXPO,HIGH);
digitalWrite(LEDCXPB,LOW);
digitalWrite(LEDCXAO,LOW);
digitalWrite(LEDCXAB,HIGH);
break;
case 4:// As chave de bóia no nível alto
modo= "Caixas cheias";
Serial.print(modo);
digitalWrite(VSFAR,LOW);
digitalWrite(BOMBA,LOW);
digitalWrite(LEDCXPO,HIGH);
digitalWrite(LEDCXPB,LOW);
digitalWrite(LEDCXAO,HIGH);
digitalWrite(LEDCXAB,LOW);
break;
}
}
…
todo louco botoes param de funcionar etc. dessa maneira que esta o codigo agora tudo esta funcionando, mas o problema é que o tempo ficou fora de sincronia e os botoes só funcionam depois de segurar por uns 2 segundos e soltar, se so apertar e soltar nao funciona, alguem poderia me dar uma luz ai, Segue o Codigo
Obs: primeiro post, nao achei como coloca o Codigo em Code :(
//Programa: Arduino e DS18B20 controle de rele por temperatura e timer//Autor: Junior Oliveira
#include <LiquidCrystal.h>#include <OneWire.h>#include <DallasTemperature.h>
int posicao = 0;int temp_min = 24; // TEMPERATURA MINIMA PARA DESLIGARint temp_max = 28; // TEMPERATURA MAXIMA PARA LIGARint ahoras = 0; //VARIAVEL PARA MOSTRAR HORAS NO LCDint aminutos = 0; //VARIAVEL PARA MOSTRAR MINUTOS NO LCDint asegundos = 0; //VARIAVEL PARA MOSTRAR SEGUNDOS NO LCDint segundostotal = 0; //Tempo totalint msg = 0; //BARREIRA PARA MENSAGEM DE BEM VINDOint empieza = 1024; // VARIAVEL PARA BOTAO DE START FUNCIONARint varbuth = 0; //VARIAVEL PARA MUDAR VALOR DE HORASint varbutm = 0; //VARIAVEL PARA MUDAR VALOR DE MINUTOSint varbuts = 0; //VARIAVEL PARA MUDAR VALOR DE SEGUNDOS
// CONFIGURACOES DE PINOS PARA O CIRCUITO
int rele_timer = 13; // PINO DIGITAL PARA RELE TIMERint rele_temp = 12; // PINO DIGITAL RELE TEMPERATURAint start = A2; //PINO ANALOGICO PARA BOTAO DE STARTint buth = A0; //PINO ANALOGICO BOTAO HORASint butm = A1; //PINO ANALOGICO BOTAO MINUTOSint buts = A3; //PINO ANALOGICO BOTAO SEGUNDOS#define ONE_WIRE_BUS 10 // PINO DIGITAL SENSOR DE TEMPERATURA#define pino_aumenta 2 // BOTAO AUMENTA TEMPERATURA MAXIMA#define pino_diminui 3 // DIMINUI TEMPERATURA MAXIMA
OneWire oneWire(ONE_WIRE_BUS);DallasTemperature sensors(&oneWire);
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
int temperatura;int aumenta, diminui;
unsigned long previousMillis = 0;//Intervalo de medicao temperaturaconst long interval = 2000;
void setup(void){ lcd.begin(16, 2); Serial.begin(9600); pinMode(rele_temp, OUTPUT); pinMode(rele_timer, OUTPUT); pinMode(pino_aumenta, INPUT); pinMode(pino_diminui, INPUT); digitalWrite(rele_timer, HIGH); digitalWrite(rele_temp, LOW); msg = 0; //BARREIRA MENSAGEM BEM VINDO empieza = 1024; //BARREIRA START
varbuth = 1; //BARREIRA DE HORAS varbutm = 1; //BARREIRA DE MINUTOS varbuts = 1; //BARREIRA DE SEGUNDOS sensors.begin();}
void loop(void){ do { sensors.requestTemperatures(); // REQUISITA TEMPERATURA DOS SENSORES
varbuth = analogRead(buth); //LEITURA BOTAO HORAS varbutm = analogRead(butm); //LEITURA BOTAO MINUTOS varbuts = analogRead(buts); //LEITURA BOTAO SEGUNDOS
if (varbuth == 0) //SE PRESSIONAR O BOTAO AUMENTA UMA HORA { ahoras = ahoras + 1 ; delay(250); }
if (varbutm == 0) //SE PRESSIONAR O BOTAO AUMENTA UM MINUTO { aminutos = aminutos + 1; delay(250); }
if (varbuts == 0) //SE PRESSIONAR O BOTAO AUMENTA UM SEGUNDO { asegundos = asegundos + 1; delay(250); } lcd.setCursor(1, 1);
if (ahoras < 10) lcd.print("0"); // SE AS HORAS FOREM MENOR QUE "10" É COLOCADO UM "0" NA FRENTE lcd.print(ahoras); // SEM ESSE CODIGO SE MOSTARIA ASSIM: H:M:S (1:M:S) lcd.print(":");
if (aminutos < 10) lcd.print("0"); // SE OS MINUTOS FOREM MENOR QUE "10" É COLOCADO UM "0" NA FRENTE lcd.print(aminutos); // SEM ESSE CODIGO SE MOSTARIA ASSIM: H:M:S (H:1:S)
lcd.print(":"); if (asegundos < 10) lcd.print("0"); // SE OS SEGUNDOS FOREM MENOR QUE "10" É COLOCADO UM "0" NA FRENTE lcd.print(asegundos); // SEM ESSE CODIGO SE MOSTARIA ASSIM: H:M:S (H:M:1)
empieza = analogRead(start); //LEITURA DO BOTAO DE START
if (empieza == 0) //Si el boton de arranque, fue pulsado... { segundostotal = asegundos + (aminutos * 60) + (ahoras * 60 * 60); // CONVERTE TEMPO TOTAL EM SEGUNDOS } //botao aumenta temperatura aumenta = digitalRead(pino_aumenta); if (aumenta == 0) { temp_max++; } while (digitalRead(pino_aumenta) == 0) { delay(10); }
//botao diminui temperatura diminui = digitalRead(pino_diminui); if (diminui == 0) { temp_max--; } while (digitalRead(pino_diminui) == 0) { delay(10); } lcd.setCursor(0, 0); lcd.print(temperatura); lcd.setCursor(2, 0); lcd.print("C"); lcd.setCursor(4, 0); lcd.print("MIN"); lcd.setCursor(8, 0); lcd.print(temp_max); lcd.setCursor(10, 0); lcd.print("C"); if (temp_min >= temperatura){ digitalWrite(rele_temp, LOW);}else if (temp_max <= temperatura){ digitalWrite(rele_temp, HIGH);} unsigned long currentMillis = millis(); //Timer para ler o valor da temperatura if (currentMillis - previousMillis >= interval) { temperatura = sensors.getTempCByIndex(0); previousMillis = currentMillis; } } while (empieza != 0); // VOLTA AO MENU DE AJUSTE PARA APENAS APERTAR O BOTAO START while (segundostotal > 0) { sensors.requestTemperatures(); // REQUISITA TEMPERATURA DOS SENSORES delay (235); //DESCONTADO 1 SEGUNDO DO TIMER segundostotal--;
ahoras = ((segundostotal / 60) / 60); //CONVERTE OS SEGUNDOS TOTAIS EM HORAS aminutos = (segundostotal / 60) % 60; //CONVERTE OS SEGUNDOS TOTAIS EM MINUTOS asegundos = segundostotal % 60; //CONVERTE OS SEGUNDOS TOTAIS EM SEGUNDOS
lcd.setCursor(1, 1); if (ahoras < 10) lcd.print("0"); // SE AS HORAS FOREM MENOR QUE "10" É COLOCADO UM "0" NA FRENTE lcd.print(ahoras); // SEM ESSE CODIGO SE MOSTARIA ASSIM: H:M:S (1:M:S) lcd.print(":");
if (aminutos < 10) lcd.print("0"); // SE OS MINUTOS FOREM MENOR QUE "10" É COLOCADO UM "0" NA FRENTE lcd.print(aminutos); // SEM ESSE CODIGO SE MOSTARIA ASSIM: H:M:S (H:1:S)
lcd.print(":"); if (asegundos < 10) lcd.print("0"); // SE OS SEGUNDOS FOREM MENOR QUE "10" É COLOCADO UM "0" NA FRENTE lcd.print(asegundos); // SEM ESSE CODIGO SE MOSTARIA ASSIM: H:M:S (H:M:1)
if (segundostotal == 0) //FINALIZA O TEMPO DO TIMER { while (1) //FINALIZA O TEMPO E DESARMA O RELE { digitalWrite(rele_timer, LOW); delay(200); lcd.clear(); lcd.setCursor(1, 0); lcd.print("TEMPO ESGOTADO"); lcd.setCursor(5, 1); lcd.print("By: Jr"); } } //botao aumenta temperatura aumenta = digitalRead(pino_aumenta); if (aumenta == 0) { temp_max++; } while (digitalRead(pino_aumenta) == 0) { delay(10); }
//botao diminui temperatura diminui = digitalRead(pino_diminui); if (diminui == 0) { temp_max--; } while (digitalRead(pino_diminui) == 0) { delay(10); } lcd.setCursor(0, 0); lcd.print(temperatura); lcd.setCursor(2, 0); lcd.print("C"); lcd.setCursor(4, 0); lcd.print("MIN"); lcd.setCursor(8, 0); lcd.print(temp_max); lcd.setCursor(10, 0); lcd.print("C"); if (temp_min >= temperatura){ digitalWrite(rele_temp, LOW);}else if (temp_max <= temperatura){ digitalWrite(rele_temp, HIGH);} unsigned long currentMillis = millis(); //Timer para ler o valor da temperatura if (currentMillis - previousMillis >= interval) { temperatura = sensors.getTempCByIndex(0); previousMillis = currentMillis; } }}
…
utorials/serial-peripheral-interface-spi/all
* https://arduino.stackexchange.com/questions/16348/how-do-you-use-spi-on-an-arduino/16349
Explicando este experimento:
* Neste experimento são necessários 2 Arduinos, um para master e outro para slave.
* O Arduino master enviará automaticamente e seguidamente, a cada 5 segundos, duas sequências de caracteres...
* A primeira sequência de caracteres é composta de um caracter 'a' seguido dos números 10, 17, 33 e 42, da seguinte forma:
* 1. o slave recebe o primeiro byte do master, o caracter 'a' e espera pelo próximo byte do master. O caracter 'a' sinaliza para o slave adicionar 10 aos números que receber a seguir
* 2. o slave receber o segundo byte, o número 10, e então adiciona 10 ao número 10 recebido, resultando 20, e espera
* 3. o slave recebe o terceiro byte do master, o número 17, somando 10 a ele, e aproveita esta conexão para enviar, ao mesmo tempo (comunicação full duplex) em que recebe, o resultado da operação de adição anterior, o númro 20
* 4. o slave recebe o quarto byte do master, o número 33, somando 10 a ele, e aproveita esta conexão para enviar, ao mesmo tempo (comunicação full duplex) em que recebe, o resultado da operação de adição anterior, o número 27
* 5. o slave recebe o quinto byte do master, o número 42, somando 10 a ele, e aproveita esta conexão para enviar, ao mesmo tempo (comunicação full duplex) em que recebe, o resultado da operação de adição anterior, o número 43
* 6. o master não tem mais números a enviar para o slave mas o slave tem uma resposta a enviar para o master, o número 52, resultado da adição de 10 + 42
* 7. então o master, para não ficar sem esse resultado, envia um caracter qualquer para o slave e o slave aproveita esta conexão para enviar o número 52 para o master, finalizando a sequencia numérica enviada pelo master
* A segunda sequência de caracteres é composta de um caracter 's' seguido dos mesmos números 10, 17, 33 e 42, porém o 's' sinaliza para o slave agora fazer a subtração de 10 nestes números na mesma sequencia anterior
Pinagem entre os dois Arduinos Uno:
* Master <==> Slave
* D10 (SS) D10 (SS)
* D11 (MOSI) D11 (MOSI)
* D12 (MISO) D12 (MISO)
* D13 (SCK) D13 (SCK)
* 5V Vin
* GND GND
Código (sketch) para o Arduino master:
* Neste sketch (master) usaremos a biblioteca <SPI.h>
-------------------------------------------------------------------------------------------------------------------------------------------------
#include <SPI.h>
SPISettings settings(4000000, MSBFIRST, SPI_MODE0); // define velocidade desta conexão SPI em
// 4MHz (16MHz do Uno / 4 = 4MHz, default)
void setup(){ Serial.begin (9600); Serial.println();
digitalWrite(SS, HIGH); // desabilitar comunicação com o slave. Garantir que o pino SS do
// master não inicie habilitando a comunicação com o slave (SS em
//estado ALTO = desconectado) SPI.begin();}
byte charInOut(const byte charOut){ // rotina para transferir 1 byte do master para o slave byte charIn = SPI.transfer(charOut); // transfer 1 byte para o slave e, ao mesmo tempo, recebe 1
// byte do slave armazenando-o em 'a' delayMicroseconds(20); // pausa por 0,000.02 segundos ou 20 microsegundos return charIn;}
void loop(){ byte a, b, c, d; digitalWrite(SS, LOW); // habilitar comunicação SPI com o slave SPI.beginTransaction(settings); // inicializar a conexão SPI usando o SPIsettings definido charInOut('a'); // enviar o caracter 'a' para o slave. Neste sketch o caracter 'a'
// sinaliza para o slave fazer uma operação de adição charInOut(10); // enviar o número 10 para o slave e, ao mesmo tempo, não
// receber o que quer que seja do slave a = charInOut(17); // enviar o número 17 para o slave e, ao mesmo tempo, receber
// o dado enviado do slave armazenando-o na variável "a" b = charInOut(33); // enviar o número 33 para o slave e, ao mesmo tempo, receber
// o dado enviado do slave armazenando-o na variável "b" c = charInOut(42); // enviar o número 42 para o slave e, ao mesmo tempo, receber
// o dado enviado do slave armazenando-o na variável "c" d = charInOut(0); // enviar o número 0 (ou qualquer outro caracter) para o slave e,
// ao mesmo tempo, receber o dado enviado do slave
// armazenando-o na variável "d". Esta operação só existe para
// receber dado do slave SPI.endTransaction(); // finalizar a conexão SPI digitalWrite(SS, HIGH); // desabilitar comunicação SPI com slave
Serial.print("O números são 10, 17, 33 e 42. Adicionando 10: "); Serial.print(a, DEC); Serial.print(", "); Serial.print(b, DEC); Serial.print(", "); Serial.print(c, DEC); Serial.print(", "); Serial.print(d, DEC);
digitalWrite(SS, LOW); // habilitar comunicação SPI com o slave SPI.beginTransaction(settings); // inicializar a conexão SPI usando o SPIsettings definido charInOut('s'); // enviar o caracter 's' para o slave. Neste sketch o caracter 's'
// sinaliza para o slave fazer uma operação de subtração charInOut(10); // enviar o número 10 para o slave e, ao mesmo tempo, não
// receber o que quer que seja do slave a = charInOut(17); // enviar o número 17 para o slave e, ao mesmo tempo, receber o
// dado enviado do slave armazenando-o na variável "a" b = charInOut(33); // enviar o número 33 para o slave e, ao mesmo tempo, receber o
// dado enviado do slave armazenando-o na variável "b" c = charInOut(42); // enviar o número 42 para o slave e, ao mesmo tempo, receber o
// dado enviado do slave armazenando-o na variável "c" d = charInOut(0); // enviar o número 0 (ou qualquer outro caracter) para o slave e,
// ao mesmo tempo, receber o dado enviado do slave
// armazenando-o na variável "d". Esta operação só existe para
// receber dado do slave SPI.endTransaction(); // finalizar a conexão SPI digitalWrite(SS, HIGH); // desabilitar comunicação SPI com slave
Serial.print(". Subtraindo 10: "); Serial.print(a, DEC); Serial.print(", "); Serial.print(b, DEC); Serial.print(", "); Serial.print(c, DEC); Serial.print(", "); Serial.println(d, DEC);
Serial.println(); delay (5000); // esperar 5 segundos para fazer isso tudo novamente}
-------------------------------------------------------------------------------------------------------------------------------------------------
Código (sketch) para o Arduino slave:
* Neste sketch não usaremos a biblioteca <SPI.h> mas trabalharemos diretamente com os registradores SPI
-------------------------------------------------------------------------------------------------------------------------------------------------
volatile byte command = 'x'; // Para ter certeza que dados de variáveis globais sejam
// passados entre as ISRs e o programa principal, use definir
// a variável como "volatile"
void setup(){ pinMode(MISO, OUTPUT); // pino MISO deste slave é definido como de output
SPCR |= _BV(SPE); // Habilitar a comunicação SPI neste slave atribuindo 1 ao bit
// SPE do registrador SPCR do SPI do Arduino, ou seja,
// habilitar SPI neste slave SPCR |= _BV(SPIE); // Habilitar a interrupção SPI atribuindo 1 ao bit SPIE do
// registrador SPCR do SPI do Arduino }
ISR(SPI_STC_vect){ // Interrupt Service Routine (ISR), SPI_STC_vect, esta
// interrupção será executada enquanto estiver recebendo
// dados do master, ou seja, a interrupt do pino SS em estado
// BAIXO byte c = SPDR; // lê o registrador "de troca" SPDR que contém o dado (o byte)
// enviado pelo master, armazenado-o na variável 'c' switch (command){ case 'x': // se 'command' = 0, ou seja, se não tem uma ação de adição
// ou subtração command = c; // atribui à variável 'command' o caracter recebido na variável 'c' SPDR = 0; // escreve o número 0 no registrador SPDR, enviando-o ao
// master break; case 'a': // se 'command' = 'a' (de adição) SPDR = c + 10; // soma 10 ao número armazenado em 'c' escrevendo o
// resultado no registrador SPDR, enviando-o ao master break; case 's': // se 'command' = 's' (de subtração) SPDR = c - 10; // subtrai 10 ao número armazenado em 'c' escrevendo o
// resultado no registrador SPDR, enviando-o ao master break; } }
void loop(){ // permanecerá dentro do void loop() enquanto a interrupção
// ISR(SPI_STC_vect) estiver em estado ALTO, ou seja, com a
// SPI inativa if (digitalRead (SS) == HIGH) // se a interrupção estiver em estado ALTO, ou seja, se SPI
// inativa (não estiver recebendo dados do master) command = 'x'; }
-------------------------------------------------------------------------------------------------------------------------------------------------…
ar cancela deve parar o programa
Programa só inicia quando
pin11 der 1 pulso high durante 5 segundos
Quando iniciar programa pin10 em high
se o programa parar pin 10 em low
Se pin 3 ficar High a qualquer momento para o programa
Se pin1 ficar High a qualquer momento para o programa
Verifica se pin1 está em LOW
Low prossegue
High cancela ou ficar high a qualquer momento cancela
Verifica se pin2 está em LOW
Low prossegue
High cancela
tempo de 10s
repete
Verifica se pin1 está em LOW
Low prossegue
High cancela ou ficar high a qualquer momento cancela
Verifica se pin2 está em LOW
Low prossegue
High cancela
se prossegue aciona
pin5 em high
permanece 30s em high
pin6 em high
permanece 30s em high
desativa pin5 e pin6 para low
aguarda 3s
aciona pin7 para high
aciona pin8 para high
aguarda 3 s
aciona pin4 para high
aguarda 20 minutos
pin 4 para low
aguarda 3s
pin7 para low
pin8 para low
aguarda 1 s
aciona pin9 para High
pin 9 permanece em high até
pin1 ou pin 2 ficar em high
quando ficar em high pin1 e pin2
pin9 fica em low
…