inspirato da un progetto visto in rete che si propone di controllare un relè usb commerciale tramite un aga con firmware modificato sto provando a realizzare una cosa simile con Vodafone Station (OpenWRT) ed Arduino, ovviamente
Ho realizzato uno sketch che tramite terminale seriale (CuteCom) invia dei comandi per controllare 2 rele e leggere la temperatura dal classico Dallas DS18B20.
In pratica scrivo 'rele07=1' per accendere ed ovviamente 'rele07=0' per spengere se invece scrivo 'term', per adesso ho collegato un solo Dallas e non gestisco gli indirizzi, ottengo la temperatura.
Ho collegato Arduino alla VS, si crea il ttyACM0 ma se mando 'echo -e "rele08=1" >/dev/ttyACM0' (sul pin 8 ovviamente ho l'altro relè) non succede nulla, stesso dicasi da shell del PC, se però prima di dare l'echo do 'tail -f /dev/ttyACM0 &' e dopo rido il comando, le funzioni relè vanno finchè non killo la tail.
Ho provato a cercare su Google il perchè di questo, probabilmente la tail sincronizza la seriale, senza i comandi arrivano ad Arduino, i led lampeggiano, ma evidentemente la seriae non è impostata a 9600 8N1, come richiede il mio sketch, ma non ho trovato nulla.
Qualche idea ?
Ciao, Carlo.
Edit 08 Aprile 2013 23:20 - Riscritto completamente index.php adottando Ajax e spostando i comandi php per la seriale su file esterni.
Il progetto non è completamente funzionante, ma lo riporto nel caso servisse come spunto a qualcuno.
La parte relè funziona perfettamente e semplicemente modificando i limiti del ciclo for-next si possono aumentare i relè controllati, ovviamente adattando anche lo sketch.
ATTENZIONE - La parte temperatura non funziona, in realtà, il comando arriva ad Arduino, provato dal led collegato al pin 6, però per qualche motivo non viene letto dallo script php. Anche la parte che ritorna il valore e l'aggiorna nel <div> è da mettere a punto.
Purtroppo non sono l'unico ad avere problemi del genere con la seriale, come da bibliografia varia sul web.
I comandi sono 'rele0x=y' con x = 7 e 8 e y = 0 ed 1, c'è anche 'temp' che restituisce la temperatura dell'unico Dallas collegato.
I pin dei relè sono ovviamene 7 ed 8 mentre il Dallas è collegato al pin 3, i relè sono in logica negata.
Questo è lo sketch per Arduino:
Codice: Seleziona tutto
*---------------------------------*/
/* Controllo relè tramite seriale */
/*---------------------------------*/
/* Indirizzi Dallas:
Su RTC = 28ADAC4A0400007F
*/
#include <OneWire.h>
#include <DallasTemperature.h>
// Costanti
const int pinRele1 = 7;
const int pinRele2 = 8;
#define ONE_WIRE_BUS 3 // Pin Dallas DS18B20
// Variabili
String strIngresso = ""; // Contiene la stringa ricevuta
String strCmd = String(5);
String strTmp = "";
boolean strCompleta = false; // Stato stringa ricevuta
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
// Settaggi iniziali
void setup()
{
// Settaggio Pin Rele' in Output ed impostazione a riposo per i rele in logica negata
pinMode(pinRele1, OUTPUT);
pinMode(pinRele2, OUTPUT);
pinMode(6, OUTPUT);
digitalWrite(pinRele1, HIGH);
digitalWrite(pinRele2, HIGH);
// Impostazioni seriale
Serial.begin(9600);
sensors.begin();
delay(1000);
}
// Definizioni funzioni richiamate nel programma.
String estrCmd(String, int, int);
// int estrVal(String, int, int);
// Funzione Principale
void loop()
{
// Quando la stringa è completa la stampa ed inizia le operazioni:
if (strCompleta) {
// Elaborazione dei dati ricevuti dalla seriale
// Estrazione del comando (rele/temp)
strCmd = estrCmd(strIngresso, 0, 3);
// Scrittura pin digitali
if (strCmd == "rele") {
// Estrazione dei campi Valore e Piedino e conversione in itero
String strTmp = estrCmd(strIngresso, 4, 5);
int piedino = strTmp.toInt();
// Verifica che il pin del Rele sia nel range consentito
if (piedino >= 7 || piedino <= 8){
strTmp = estrCmd(strIngresso, 7, 7);
int valore = strTmp.toInt();
Serial.print(" Pin = ") ; Serial.print(piedino);
Serial.print(" valore = ") ; Serial.println(valore);
if (valore == 1){
digitalWrite(piedino, LOW);
}
if (valore == 0){
digitalWrite(piedino, HIGH);
}
}
}
// Lettura temperatura da dallas
if (strCmd == "temp") {
sensors.requestTemperatures();
float temperatura = sensors.getTempCByIndex(0);
//Serial.print(" Temperatura = ") ;
Serial.println(temperatura);
digitalWrite(6, HIGH);
delay(3000);
digitalWrite(6, LOW);
}
// Azzeramento variabili stringa ingresso:
// Serial.print(" !! strIngresso = ") ; Serial.println(strIngresso);
strIngresso = "";
strCmd = "";
strCompleta = false;
}
}
// Estrazione dati dalla stringa di input
String estrCmd(String stringa, int iniz, int fine)
{
String comando = "";
int k;
fine++;
for (k=iniz; k<fine; k++){
char thisChar = stringa[k];
comando.concat(thisChar);
}
return comando;
}
/*
SerialEvent occurs whenever a new data comes in the
hardware serial RX. This routine is run between each
time loop() runs, so using delay inside loop can delay
response. Multiple bytes of data may be available.
*/
void serialEvent() {
// Acquisizione di una carattere dalla seriale quando disponibile
while (Serial.available()) {
char carIngr = (char)Serial.read();
// Serial.print(" carIngr = ") ; Serial.println(carIngr) ;
// Accodamento del carattere nella stringa
strIngresso += carIngr;
// All'arrivo del carattere di fine linea commuto lo switch ( strCompleta )
if (carIngr == '\n') {
strCompleta = true;
}
}
}
E per finire ho creato la pagina iniziale /www/index.php
Codice: Seleziona tutto
<script>
//
var myRequest = null;
function CreateXmlHttpReq(handler) {
var xmlhttp = null;
try {
xmlhttp = new XMLHttpRequest();
} catch(e) {
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch(e) {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
}
xmlhttp.onreadystatechange = handler;
return xmlhttp;
}
function myHandler() {
if (myRequest.readyState == 4 && myRequest.status == 200) {
alert(myRequest.responseText); // Restituisce i dati da 'myRequest'
}
}
/* Funzione per leggere la temperatura ed aggiornare il <div> */
function leggeTemp(sensore) {
var r = Math.random();
myRequest = CreateXmlHttpReq(myHandler);
myRequest.open("GET","temp.php?sensore="+escape(sensore)+"&rand="+escape(r));
// alert("temp.php?sensore="+escape(sensore)+"&rand="+escape(r));
myRequest.send(null);
// Lettura dell'ID del div e relativo aggiornamento
var divTemp = document.getElementById("divTemp1");
// alert("divTemp = " +escape(divTemp));
divTemp.innerHTML = (myRequest.responseText);
}
/* Funzione per comandare i rele su seriale */
function rele(stato, pin) {
var r = Math.random();
myRequest = CreateXmlHttpReq(myHandler);
myRequest.open("GET","rele.php?pin="+escape(pin)+"&stato="+escape(stato)+"&rand="+escape(r));
// alert("rele.php?pin="+escape(pin)+"&stato="+escape(stato)+"&rand="+escape(r));
myRequest.send(null);
}
</script>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//IT"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Rele Arduino</title>
</head>
<body>
<TABLE BORDER="1" ALIGN=CENTER>
<TR><TD COLSPAN=4><H1>Rele Arduino</H1></TD></TR>
<?php
// Creazione Tabella Temperature
for ($temp = 1 ; $temp <= 1 ; $temp++)
{
echo "<TR><TD COLSPAN=1>Temperatura ".$temp; echo "</TD>\n";
echo "<TD ALIGN=CENTER><input type='button' value='O' onClick='leggeTemp(".$temp.")'/>";
echo "</TD>\n";
echo '<TD></script><div id="divTemp'.$temp.'">N/D</div>' ;echo "</TD>\n";
echo "</TD>\n";echo "</TR>";
}
// Creazione Tabella Comandi Rele
for ($rele = 7 ; $rele <= 8 ; $rele++)
{
echo "<TR><TD>Rele ".$rele; echo "</TD>\n";
echo "<TD ALIGN=CENTER><input type='button' value='On' onClick='rele(\"on\", ".$rele.")'/>";
echo "</TD>\n";
echo "<TD ALIGN=CENTER><input type='button' value='Off' onClick='rele(\"off\", ".$rele.")'/>";
echo "</TD>\n";echo "</TR>";
}
?>
</TABLE>
</body>
</html>
rele.php
Codice: Seleziona tutto
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
ini_set('display_startup_errors',1);
define("PORT","/dev/ttyUSB0");
require "php_serial.class.php";
$serial = new phpSerial;
$serial->deviceSet(PORT);
$serial->confBaudRate(9600);
$serial->confParity("none");
$serial->confCharacterLength(1);
$serial->confStopBits(1);
$serial->confFlowControl("none");
$serial->deviceOpen();
// sleep(1);
if (isset($_GET['stato'])) {
if ($_GET['pin'] > 9){
$rele="rele";
} else {
$rele="rele0";
}
if ($_GET['stato'] == "on") {
$serial->sendMessage($rele.$_GET['pin']."=1\n");
} else if ($_GET['stato'] == "off") {
$serial->sendMessage($rele.$_GET['pin']."=0\n");
}
}
$read = $serial->readPort();
echo $read;
$serial->deviceClose();
?>
Codice: Seleziona tutto
<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);
ini_set('display_startup_errors',1);
define("PORT","/dev/ttyUSB0");
require "php_serial.class.php";
$serial = new phpSerial;
$serial->deviceSet(PORT);
$serial->confBaudRate(9600);
$serial->confParity("none");
$serial->confCharacterLength(1);
$serial->confStopBits(1);
$serial->confFlowControl("none");
$serial->deviceOpen();
//sleep(1);
if (isset($_GET['sensore'])) {
echo "sensore=".$_GET['sensore'];
$serial->sendMessage("temp\n");
}
$read = $serial->readPort();
echo $read;
$serial->deviceClose();
?>
A questo punto avviare il server con il comando '# /etc/init.d/lighttpd start' e puntare il browser all'indirizzo del router ed alla porta scelta nel config di lighttpd.