Sei sulla pagina 1di 26

Search Programmazione WxWidgets CodeBlocks Android Elettronica Arduino 1-Wire

AA

nov

26
2012

RS232 con bus 1wire: dalla teoria alla pratica


1-Wire, CodeBlocks, Elettronica, Programmazione, w xWidgets Add comments

69.164.218.62 Utente non autenticato Registrati Collegati

Una lunga

Italiano English

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

introduzione
Dopo aver visto qui come funziona il bus 1wire e la teoria su come utilizzare la porta seriale, ora vediamo limplementazione pratica. Coerentemente al resto del blog ho utilizzato CodeBlocks con le wxwidgets ma in questo caso ci serve unulteriore aggiunta, infatti le wxwidgets non hanno il supporto nativo per linterfaccia RS232. Per aggiungere questa funzionalit nel mio progetto avevo inizialmente usato le librerie ctb che danno appunto il supporto seriale alle per Linux che per Windows (non per Mac). Nel mio progetto avevo usato la versione 0.13 ora non pi disponibile in quanto attualmente distribuita la versione 0.16. Avevo perci deciso di aggiornare il mio progetto per permettere a chiunque di scaricarsi lultima versione disponibile e procedere con questo progetto. Avevo gi scritto una buona parte dellarticolo ma non sapevo che avrei avuto unamara sorpresa. Con la nuova versione il progetto non funziona! Ho perso decine di ore a scrivere codice, testare, riprovare, analizzare i dati seriali e quantaltro, ma a parit di codice non otteniamo lo stesso
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

RSS McMajan Libreria Ss_TFT Arduino, rel e infrarossi. IteadStudio 2.8 TFT Display shield: Una nuova libreria Arduino e RS485: piccoli approfondimenti Arduino cos? (per principianti e anche meno)

Categorie Elettronica (36) 1-Wire (8) Arduino (30) Programmazione (26) Android (7) CodeBlocks (9) wxWidgets (11) Senza categoria (1) WEB (1)

pdfcrowd.com

comportamento sulla porta seriale. Non ho scovato dove si annida il vero problema, ma come se il nuovo software perdesse alcuni dati nella lettura dalla porta il che impedisce il corretto funzionamento di tutto il software. Ho perci cercato unalternativa e mi sono imbattuto nell famose librerie boost. Dopo un paio di giorni di prove ho deciso di scartale. A parte i numerosi passaggi da fare per integrarle in CodeBlock, ho avuto comunque notevoli problemi con errori di compilazione, files non trovati e quantaltro, senza contare che le trovo particolarmente complesse e pesanti visto che dopo la luuuunga compilazione occupano la bellezza di 2.5GB. Mi sono imbattuto poi in queste librerie che sono molto leggere e supportano sia Linux che Windows. Il rovescio della medaglia che sono scritte in C e non in C++, inoltre mancano di un comando per variare il baud-rate di una porta gi aperta, funzione che fondamentale per il nostro progetto. A questo punto dovevo scegliere se utilizzare queste ultime librerie modificandole, o tornare indietro ed utilizzare le ctb versione 0.13. Per fortuna avevo una copia di backup dei files originali per cui li ho resi disponibili per il download qui: Librerie ctb 0.13 (5).
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

WEB (1) Wordpress (1)

Elettronica Sito ufficiale Arduino

Programmazione HomePage Code::Blocks HomePage wxWidgets

Blog QR Code

pdfcrowd.com

Preparare la libreria ctb


Dopo aver scaricato le librerie decomprimete larchivio dove preferite. Aprite un prompt dei comandi e puntate alla sottocartella build con un CD, nel mio caso sar CD C:\STX\TECNIX\PROGRAMMAZIONE\Librerie\libwxctb0.13\build. Per compilare le librerie usiamo, come di consueto, il comando mingw32-make usando lopzione -f per specidifcare il file makefile.gcc. Lanciamo perci il comando:

mingw32-make -f makefile.gcc DEBUG=0 che crea la


open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

versione release, e poi mingw32-make -f makefile.gcc DEBUG=1 per la versione di debug In meno di un minuto la compilazione sar terminata e dobbiamo andare ad integrare le librerie con le wxwidgets, che nel mio esempio sono le 2.9.1. Prima di tutto copiamoci gli header, in particolare in wxWidgets2.9.1\include\wx copiamo la directory ctb-0.13 che troviamo in include \libwxctb-0.13\include\wx. A questo punto potremmo decidere di spostare le librerie, ossia la directory lib, ma ci non indispensabile in quanto possiamo specificare il percorso nellinterfaccia di CodeBlocks. Baster andare su Project->Buld Options e sia nelle sezioni Debug e Release, nel linker setting, aggiunguamo il percorso alla libreria come potete vedere nella porzione di screenshot qui vicino. Fate attenzione al nome della libreria, quella con la d aggiuntiva la versione di debug, laltra la versione release (vedi immagine a lato).

Descrizione del progetto


open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

Per questo articolo ho preparato una classe che raggruppa tutte le funzioni per linterfacciamento con il bus 1wire: 01 class OWR 02 { 03 public: 04 wxSerialPort * SerialDevice; 05 wxString DeviceName; 06 char RS232_1W_Buff[50]; // buffer in ingresso della seriale 07 unsigned short RS232_1W_Len; 08 int Send2Serial(char*ccm,int len,int sleeptime=0); 09 int Send2Serial(char car,int sleeptime=0); 10 unsigned char Raw_RS232_Read(char * buff,int maxlen=50); 11 unsigned char OWReset(); 12 void OWWriteBit(unsigned char bit_value); 13 char OWReadBit(); 14 void OWWriteByte(unsigned char byte_value); 15 unsigned char OWReadByte(); 16 void OWRomSelect(char * address); 17 void OWWriteMultiByte(char * buffer,unsigned char len); 18 unsigned char OWByteInvert(unsigned char val); 19 void OWReadTemp(); 20 unsigned char ROM[10][8]; // memoria per memorizzare 10 rom
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

21 22 23 24 25 26 27 28

memoria per memorizzare 10 rom float temp[10]; // memoria per 10 temperature: vedi prossimo articolo unsigned char DeviceCount; char RomSearch(); wxTextCtrl* Txt; char Calculate_crc(unsigned char*, int); OWR(); ~OWR(); };

Ora andremo a vedere le funzioni una per una, ma prima vi descivo rapidamente le variabili di questa classe. Allinizio abbiamo wxSerialPort * SerialDevice che un puntatore alla classe ctb che gestisce la porta seriale. Per comodit manteniamo il puntatore direttamente dentro la nostra classe OWR (OneWiRe). DeviceName tiene in memoria il nome della porta seriale da aprire, infatti in questa versione del progetto gestito solo il nome delle porte seriali Windows ma la classe gi predisposta per una piccola aggiunta per Linux. RS232_1W_Buff e RS232_1W_Len vengono utilizzate per gestire le letture dalla porta seriale. Per ultimo vi segnalo wxTextCtrl* Txt che permette di tenere in memoria un puntatore ad un wxTextCtrl per permettere alla nostra classa di stampare a monitor le informazioni che vogliamo fa apparire.
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

Funzioni generiche
int Send2Serial(char*ccm,int len,int sleeptime=0) e int Send2Serial(char car,int sleeptime=0)
Queste due funzioni permettono di inviare dati sulla porta seriale: la prima permette di specificare un buffer di caratteri e la lunghezza da inviare con un terzo parametro opzionale che permette di attendere quel numero di millisecondi dopo la scrittura sulla porta. La seconda funzione invia un singolo carattere sulla porta seriale e anchessa permette opzionalmente di stabilire un ritardo di un tot di millisecondi prima di uscire dalla funzione. 01 int OWR::Send2Serial(char*ccm,int len,int sleeptime) 02 { 03 int scritti=SerialDevice>Writev(ccm,len,1000); 04 if(sleeptime) wxMilliSleep(sleeptime); 05 return(scritti); 06 } 07 08 int OWR::Send2Serial(char car,int sleeptime)
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

09 10 11 12 13 14

sleeptime) { char *addcar=&car; int scritti=SerialDevice>Writev(addcar,1,1000); if(sleeptime) wxMilliSleep(sleeptime); return(scritti); }

Come vedete entrambe le funzioni al loro interno sfruttano la funzione Writev delle librerie ctb per inviare i caratteri alla porta seriale. Unaltra funzione generica la :

Raw_RS232_Read(char * buff,int maxlen)


1 unsigned char OWR::Raw_RS232_Read(char * buff,int maxlen) 2 { 3 unsigned short dwBytesRead = 0; 4 dwBytesRead = SerialDevice>Read(buff,maxlen-1); 5 return(dwBytesRead); 6 } Questa funzione sfrutta la funzione Read della classe ctb, copia i bytes letti nel buffer specificato e ritorna il numero di bytes letti. Si faccia attenzione che se il buffer contiene gi
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

dei dati, questi vengono sovrascritti e non accodati.

Funzioni 1-Wire
Ora vediamo le funzioni specificatamente scritte per il bus 1-wire. Questa parte in definitiva la parte pi importante di questo articolo e del precedente in quanto il risultato di tutto quel che abbiamo discusso in queste lunghe pagine.

OWReset()
Vi ricordate il reset del bus 1-Wire? Questa funzione f esattamente quanto abbiamo spiegato nel primo articolo: Prima viene settata una velocit di 9600 baud, poi viene inviato 0xF0 e si attende la risposta da parte dei dispositivi, dopodich la velocit reimpostata a 115200 baud per le operazioni successive. Vi faccio notare che nellattesa della risposta ho inserito un breve ciclo di lettura / attesa in quanto saltuariamente mi capitava di non ricevere la risposta nei tempi dovuti e cos facendo migliorata laffidabilit del software. 1 unsigned char OWR::OWReset() 2 { 3 RS232_1W_Len=0;
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

3 4 5 6 7 8

RS232_1W_Len=0; SerialDevice>SetBaudRate((wxBaud)9600); Send2Serial(0xF0,1); // reset for(int i=0;iSetBaudRate((wxBaud)115200); return((unsigned char)RS232_1W_Buff); }

La restituzione del primo carattere letto in risposta non necessario, lho utilizzato unicamente per motivi di debug. Ora vediamo le funzioni per leggere e scrivere i singoli bit che sono:

char OWReadBit() e void OWRWriteBit(unsigned char bit_value)


Anche in questo caso non facciamo che applicare quanto visto nel precedente articolo per cui nella scrittura del bit inviamo 0xFF per i bit 1 e 000 per i bit 0. Per quanto riguarda la lettura, ricordiamo che 0xFF corrisponde al bit 1 mentre valori diversi corrispondono a bit 0. 01 void OWR::OWWriteBit(unsigned char bit_value) 02 { 03 Send2Serial((bit_value ? 0xFF : 0x00),0);
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

04 05 06 07 08 09 10 11 12 13 14

0x00),0); wxMilliSleep(1); RS232_1W_Len=Raw_RS232_Read(RS232_1W_Buff); } //-----------------------------------------------------------------------char OWR::OWReadBit() { Send2Serial(0xFF); // invio comando lettura wxMilliSleep(2); RS232_1W_Len=Raw_RS232_Read(RS232_1W_Buff); // comando lettura return(RS232_1W_Buff[0] &0x01); }

Per leggere interi bytes non facciamo altro che ripetere 8 volte la funzione OWReadBit. A dirla tutta non abbiamo mai visto quando utilizzare questa funzione, infatti ci utile quando dobbiamo andare a leggere aree di memoria contenute nei sensori, cosa che ad esempio nei DS18B20 ci serve per leggere il valore di temperaura, e non solo.

unsigned char OWReadByte()


1 unsigned char OWR::OWReadByte() 2 { 3 unsigned char byte=0; 4 for(int i=0;i<8;i++) if(OWReadBit()) byte=byte+(1<<i);
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

if(OWReadBit()) byte=byte+(1<<i); 5 return(byte); 6 } Adesso vediamo una funzione che non opera direttamente sul BUS ma che serve a calcolare il CRC per verificare leventualit di alcuni errori di trasmissione. Ho avuto non poche difficolt a comprendere fino in fondo come viene calcolato questo valore, volevo infatti scrivere la mia routine ma alla fine ho deciso di prenderne una gi pronta. Anche in questo caso ho avuto numerosi problemi in quanto diverse funzioni mi davano risultati altrettanto diversi. Lunica che ho trovato funzionare quella che vi propongo qui sotto. Io mi sono limitato a fare un copia e incolla con piccole modifiche al codice che trovate qua. Non mi dilungher ulteriormente in quanto servirebbe un intero articolo per largomento, lunica cosa che vorrei sottolineare che il polinomio genreatore corretto per il bus 1wire 019. 01 char OWR::Calculate_crc(unsigned char * data_in, int number_of_bytes_to_read) 02 { 03 //#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

04 05 06 07 08 09 10 11 12 13

X^8+X^5+X^4+X^0 uint8_t uint16_t uint8_t uint8_t uint8_t crc; loop_count; bit_counter; data; feedback_bit;

crc = 0x00; // init

for (loop_count = 0; loop_count != number_of_bytes_to_read; loop_count++) 14 { 15 data = data_in[loop_count]; 16 17 bit_counter = 8; 18 do { 19 feedback_bit = (crc ^ data) & 0x01; 20 if ( feedback_bit == 0x01 ) crc = crc ^ 0x19; //CRC8POLY; 21 crc = (crc >> 1) & 0x7F; 22 if ( feedback_bit == 0x01 ) crc = crc | 0x80; 23 24 data = data >> 1; 25 bit_counter--; 26 } while (bit_counter > 0); 27 } 28 29 return crc;
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

29 30 }

return crc;

Ora la funzione pi importante del progetto, quella sche scansiona il bus 1wire alla ricerca dei dispositivi

char RomSearch()
Questa funzione descritta nella guida ufficiale, nel commento che trovate in fondo a questa pagina. Il codice perci non lho scritto io ma mi sono limitato ad adattarlo per utilizzare le funzioni che vi ho descritto sopra, per prevenire alcuni errori originariamente non previsti, verificare il CRC di ogni indirizzo, scrivere a monitor alcune informazioni e memorizzare gli indirizzi ROM nella struttura OWR da noi scritta: attenzione che la memoria impostata per 10 dispositivi e non stato inserito un controllo per verificare il superamento di queso limite. 01 char OWR::RomSearch() 02 { 03 int cnt; 04 char errorcounter=0; 05 cnt = 0; 06 07 08 unsigned char L_dwBytesRead; 09
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

char mybits[65]; char address[8]; int path,next,pos; // decision markers int count; // bit count int bit,chk; partenza: char crc=0; // bit values path=0; // initial path to follow DeviceCount=0; do { // each ROM search pass L_dwBytesRead=OWReset(); //initialize the bus with a reset pulse if(L_dwBytesRead==0) { Txt->AppendText("RomSearch ritorna -1 per errore reset\n"); return(-1); } OWWriteByte(0xF0); // Comando ricerca dispositivi next=0;
Are you a developer? Try out the HTML to PDF API

open in browser PRO version

pdfcrowd.com

30 31 32 33 34 35

36 37 38 39 40 41 42 43 44 45 46

next=0; // next path to follow pos=1; // path bit pointer count=0; // count the bits do { // each bit of the ROM value bit=OWReadBit();//OWB>OWReadBit(); //read two bits, 'bit' and 'chk', from the 1-wire bus chk=OWReadBit();//OWB>OWReadBit(); if(!bit && !chk) { // collision, both are zero if(pos&path) bit=1; // if we've been here before else next=(path&(pos1))|pos; // else, new branch for next pos<<=1; } OWWriteBit(bit);//(write 'bit' to the 1-wire bus)

mybits[count]=bit; SetBitN((unsigned char *)address,count,bit); 47 count++; 48 }


open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

} while(count<64); crc=Calculate_crc((unsigned char*)&address[0],7); if(crc!=address[7]) // c' un errore del CRC per cui la letura non stata corretta { Txt->AppendText("CRC error\n"); Txt->AppendText("-> "+Str2AnsiHex((char*)&address[0],8)+ errorcounter++; if(errorcounter==3) break; // dopo 5 errori molto probabilmente hai un problema sulla linea seriale goto partenza; } for(int i=0;i<8;i++) ROM[DeviceCount][i]=address[7i];//baddress[i]=address[7-i]; errorcounter=0; Txt->AppendText("-> "+Str2AnsiHex((char*)&ROM[DeviceCount][0],8)+ path=next; DeviceCount++; // non controlla il superamento dei limiti di memoria!!!! }while(path);

66 67 68 }

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

Di fatto abbiamo ormai completato il progetto. Dobbiamo solamente scrivere una funzione che apre la porta seriale ed effettua la scansione del bus. Nello specifico ho creato usato la pressione di un pulsante per lanciare lapplicazione: dapprima il software chiede il numero della porta seriale, avvia la scansione ed utilizza un TextCtrl per scrivere i numeri delle ROM ed eventualmente gli errori occorsi. La funzione credo sia autoesplicativa, lunica cosa che potrebbe confondere come viene calcolato il nome del device seriale da aprire (wxT(\\\\.\\com)+dialog>GetValue()), questa forma, poco usuale, permette di aprire porte seriali che vadano oltre la 9 (dal 10 in su). Ecco a voi la funzione: 01 void wxOneWireDialog::OnButton1Click(wxCommandEvent& event) 02 { 03 OWbus = new OWR; 04 05 if(!OWbus) return; 06 07 OWbus->Txt=TextCtrl1; 08 wxString comport; 09 TextCtrl1->AppendText("Start\n"); 10 wxTextEntryDialog* dialog = new
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

10

wxTextEntryDialog* dialog = new wxTextEntryDialog(this,wxT("Please insert serial port connection number"),wxT("Please inser the value....")); 11 if ( dialog->ShowModal() != wxID_OK ) return; 12 OWbus>DeviceName=wxT("\\\\.\\com")+dialog>GetValue(); 13 dialog->Destroy(); 14 15 OWbus->SerialDevice = new wxSerialPort; 16 if(!OWbus->SerialDevice) return; 17 18 if(OWbus->SerialDevice>Open(OWbus->DeviceName.mb_str()) < 0) TextCtrl1>AppendText("Attenzione porta seriale NON aperta\n"); 19 else TextCtrl1->AppendText("Ok porta seriale aperta.\n"); 20 OWbus->SerialDevice>SetBaudRate((wxBaud)9600); 21 TextCtrl1->AppendText("Comincio ricerca dispositivi 1Wire\n"); 22 23 int result=OWbus->RomSearch(); 24 25 if(result==-1) TextCtrl1>AppendText("Dispositivi 1Wire non rilevati\n"); 26 else
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

26 27 28

else { TextCtrl1>AppendText("\nScansione terminata..\n"); 29 for(int i=0;iDeviceCount;i++) TextCtrl1->AppendText("Rilevato 0x"+Str2AnsiHex((char*)&OWbus>ROM[i][0],8)+"\n"); 30 } 31 32 } Ed ecco, nellimmagine qui a lato, il risultato finale. Faccio notare anche la presenza del pulsante temp per la lettura

della temperatura dei sensori ds18B20, ma questa parte la affrontiamo nel prossimo articolo visto che anche questa volta ci siamo dilungati abbondantemente. Infatti nel prossimo articolo vediamo come leggere la temperatura dai sensori DS18B20, com strutturata la loro memoria e
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

come possiamo sfruttare il lavoro fatto sinora per interfacciarci a quesi sensori tramite porta seriale. Spero che abbiate apprezzato questi articoli anche perch non esiste nulal di cos approfondito, in particolare in lingua italiana. Prima di lasciarvi volevo solamente fare una nota sulla funzione Str2AnsiHex che non trovate in quanto descritto prima perch un funzione di una mia libreria e che utilizzo per la stampa in esadecimale:

wxString Str2AnsiHex(char * cm,unsigned short len,bool removespace) { wxString AS=_(""); for (unsigned short a=0;a<len;a++) { AS=AS+(Char2AnsiHex(cm[a])); if(!removespace) AS=AS+wxT(" "); } return(AS); }
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

Spero che i listati appaiano correttamente visto che postare codic c sul web sempre un incubo. Be Sociable, Share!

Tw eet

Like

Share

Articoli correlati: 1. RS232 con bus 1Wire: leggere la temperatura dai sensori ds18b20 2. RS232: interagire con il bus 1wire
open in browser PRO version
Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

3. 1wire microlan introduzione e convertitore seriale 4. Arduino e sensore 1wire DS18B20 5. Arduino, 1wire DS18B20 e datalogger su internet Articoli correlati elaborati dal plugin Yet Another Related Posts.

Stefano

Stefano Smania, medico radiologo Programma in C dalla fine degli anni 80. Ha conoscenze discrete di C++, php, javascript, html, sql. Possiede approfondite conoscienze sullo standard DICOM. Bazzica con l'elettronica e unisce le diverse passioni in un progetto di domotica. Ha realizzato da solo un piano della propria casa, dal rivestimento termico, ai muri interni, l'impianto elettrico e domotico, idraulico, riscaldamento a pavimento, infissi e quant'altro vi venga in mente. Gli piace cucinare ma ha poco tempo per applicarvisi. Scrive questi articoli nella speranza che servano a qualcuno
Posted by Stefano at 00:31 Tagged w ith: 1w ire, dallas, maxim, microlan, ricerca rom, rs232, seriale, uart

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com

One Response to RS232 con bus 1wire: dalla teoria alla pratica

1.

RS232 con bus 1Wire: leggere la temperatura dai sensori ds18b20 | McMajan says:
%e %B %Y at %H:%M [...] primo che descrive nel dettaglio i timing del bus 1wire e la correlazione con lRS232 ed il secondo in cui spiegato il codice C per comunicare con il bus 1Wire. Non mi ripeter [...]

Leave a Reply
You must be logged in to post a comment.

RS232: interagire con il bus 1wire

RS232 con bus 1Wire: leggere la temperatura dai sensori ds18b20

2011 McMajan

Suffusion theme by Sayontan Sinha


Are you a developer? Try out the HTML to PDF API

open in browser PRO version

pdfcrowd.com

open in browser PRO version

Are you a developer? Try out the HTML to PDF API

pdfcrowd.com