Notaus / RS_485-050216

Fork of timer0 by V09

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers rs_485.cpp Source File

rs_485.cpp

00001 //---------------------------------------------------------------------------
00002 // Modul...: RS_485.CPP    
00003 // Chip....: iox.mini
00004 // 
00005 //---------------------------------------------------------------------------
00006 // Author..: Reinhold Schäfer
00007 // Date....: 2016.01.23
00008 // http....: //www.microsps.net
00009 //---------------------------------------------------------------------------
00010 #include "mbed.h"
00011 #include "rs_485.h"
00012 #include "timer0.h"
00013 
00014 MODSERIAL RS485(RS485_TX2, RS485_RX2);  // tx, rx
00015 DigitalOut RS485_DIR(RS485_DIR2,0);     // RS485 Direction 
00016 
00017 extern MODSERIAL pc;
00018 extern timer0 down_timer;               // definiert in main
00019 
00020 //--------------------------------------------------------
00021 // Interruptroutine wird nach 300µs aufgerufen, da das Senden von
00022 // einem Zeichen ca. 100µs Zeit beansprucht, kann die Umschaltung
00023 // auf Empfang erst verzögert erfolgen.
00024 
00025 void rs_485::isr_timeout(void)
00026 {
00027   RS485_DIR = 0; // auf Empfang umschalten
00028   send_end_flag = true;  
00029 }
00030 
00031 /*
00032 // -----------------------------------------------------------------------
00033 // This function is called when TX buffer goes empty
00034 //
00035 void rs_485::txEmpty(MODSERIAL_IRQ_INFO *q) 
00036 {
00037     timeout.attach_us(this, &rs_485::isr_timeout, 300);    // Zeit für das Umschalten
00038 }
00039 */
00040 //--------------------------------------------------------
00041 // Construktor initialisiert den Timer
00042 rs_485::rs_485()
00043 {
00044     RS485.baud(115200);
00045     //RS485.attach(this, &rs_485::txEmpty);
00046     timeout.stop();
00047     timeout.reset();
00048     msg_in.sm = 0;
00049     msg_out.sm = 0;
00050     rs_aktiv = 0;
00051     rs_aktiv_old = 0;    
00052 }
00053 //-------------------------------------------------------------
00054 // Checksum ermitteln
00055 
00056 uint8_t rs_485::get_crc(uint8_t *pbuffer, uint8_t count)
00057 {
00058     uint8_t crc_value = 0;
00059     uint8_t temp;
00060     
00061     // CheckSum calculation
00062     for(int i=0; i <= count; i++)
00063     {
00064        temp = *pbuffer;
00065        // pc.printf("\n CRC #%02d  %02x ^ %02x = ",i,crc_value,temp);
00066        crc_value ^= temp;    // XOR from ID to Data
00067        pbuffer++;
00068        // pc.printf("%02x",crc_value);
00069     }
00070     return crc_value;
00071 } 
00072 
00073 //-------------------------------------------------------------
00074 // zum Testen das Telegramm ausgeben
00075 //
00076 void rs_485::msg_print(Message msg) 
00077 {
00078     uint8_t len;
00079     
00080     pc.printf(" %02d:%02d:%02d.%03d",msg.h,msg.m,msg.s,msg.ms);
00081  
00082     pc.printf(" %02x",msg.STX);
00083     pc.printf(" %02x",msg.source);
00084     pc.printf(" %02x",msg.dest);
00085     pc.printf(" %02x [",msg.len);
00086     
00087     len = msg.len;
00088     for (int i = 0; i < len; i++)
00089     {
00090       pc.printf(" %02x",msg.data[i]);   
00091     }
00092     pc.printf(" ] %02x",msg.CRC);
00093     pc.printf(" %02x",msg.ETX);
00094        
00095 }
00096 
00097 // -----------------------------------------------------------------------
00098 // eine Telegramm erzeugen
00099 //
00100 // die Zeichen STX, CRC und ETX werden automatisch erzeugt
00101 // das Telegramm hat folgenden Aufbau
00102 // STX ADR ZIEL Länge [daten] CRC ETX
00103 //   Länge ist Anzahl der Zeichen im Datenfeld
00104 //
00105 void rs_485::write(uint8_t *data)
00106 {  
00107    uint16_t millis;
00108    uint8_t len;
00109    
00110    msg_out.STX  = 0x02;      // STX
00111  
00112    msg_out.source = *data;   // Start Adresse
00113    data++; 
00114       
00115    msg_out.dest = *data;     // Ziel Adresse
00116    data++;
00117   
00118    msg_out.len = *data;      // Länge
00119    len = *data;
00120    data++;
00121            
00122    for (int i = 0; i < len; i++)
00123    {
00124         msg_out.data[i]  = *data; // Datenbyte
00125         data++;
00126    }
00127 
00128    // pc.printf("\n write crc berechnen \n");
00129    msg_out.CRC = get_crc(&msg_out.source,msg_out.len+3); // CRC Summe ermitteln
00130       
00131    msg_out.ETX      = 0x03;    // Telegramm Abschluss
00132    
00133    // Zeitstempel schreiben
00134    down_timer.get_time_stamp(t_array,&millis);
00135    msg_out.h = t_array[0];
00136    msg_out.m = t_array[1];
00137    msg_out.s = t_array[2];
00138    msg_out.ms = millis;
00139    
00140    // Datenausgabe wird aktiviert, prüfen ob harte Umschaltung hier sinnvoll 
00141    msg_out.sm = 0;
00142    rs_aktiv = 2; 
00143 }
00144     
00145 //-------------------------------------------------------------
00146 // Die Telegramme steuern und überwachen
00147 //
00148 void rs_485::execute(void)
00149 {
00150     // auf timeout testen, falls ein fehler auftritt
00151     // wird das Telegramm über diese Stelle abgebrochen
00152     // 
00153     
00154     int temp;
00155     
00156     temp = timeout.read_ms();
00157     if (temp >= 10)
00158     {
00159         timeout.stop();
00160         timeout.reset();
00161         msg_in.sm = 0;
00162         msg_out.sm = 0;
00163 
00164       
00165         if (rs_aktiv == 1) 
00166         {
00167             pc.printf("\nreceive timeout %02d ms",temp);
00168             pc.printf("\n sm: %02x",msg_in.sm);
00169             pc.printf("\n tel:");
00170             msg_print(msg_out);
00171         }
00172       
00173         if (rs_aktiv == 2) 
00174         {
00175             pc.printf("\nsende timeout %02d ms",temp);
00176             pc.printf("\n sm: %02x",msg_out.sm);
00177             pc.printf("\n tel:");
00178             msg_print(msg_out); 
00179         }
00180       
00181         rs_aktiv = 0; 
00182     }  
00183  
00184     // an dieser Stelle wird der Programmablauf gesteuert
00185     // 0 Bus inaktiv auf Empfang
00186     // 1 BUS aktiv auf Empfangsmode
00187     // 2 BUS aktiv im Sendemode 
00188     
00189     switch (rs_aktiv)
00190     {
00191       case 0:
00192       
00193         if (rs_aktiv != rs_aktiv_old)
00194         {
00195             pc.printf("\n\nreceive");  
00196             timeout.stop(); // timer starten
00197             timeout.reset(); // timer auf 0 setzen
00198             rs_aktiv_old = rs_aktiv;
00199         }
00200         receive();
00201         break;
00202 
00203       case 1:
00204         
00205         if (rs_aktiv != rs_aktiv_old)
00206         { 
00207             pc.printf("\n\nreceive aktiv");
00208             timeout.reset(); // timer auf 0 setzen
00209             timeout.start();
00210             rs_aktiv_old = rs_aktiv; 
00211         }    
00212         receive();
00213         break;
00214                 
00215       case 2:
00216       
00217         if (rs_aktiv != rs_aktiv_old)
00218         {
00219             pc.printf("\n\nsende aktiv");
00220             timeout.reset(); // timer auf 0 setzen
00221             timeout.start();
00222             rs_aktiv_old = rs_aktiv; 
00223         }
00224         send();
00225         break;      
00226     }  // end switch
00227         
00228 }
00229 
00230 // -----------------------------------------------------------------------
00231 // das Telegramm ausgeben
00232 //
00233 void rs_485::send(void)
00234 {
00235    
00236    switch(msg_out.sm)
00237    {
00238       case 0: 
00239         // das Senden beginnt erst, wenn das eingehende Telegramm abgeschlossen ist
00240 
00241         msg_print(msg_out);
00242         pc.printf(" \n");
00243         
00244         RS485_DIR = 1;              // Bus belegen   
00245         msg_out.sm = 1;
00246 
00247         break;
00248         
00249       case 1:                       // Startzeichen senden 
00250         RS485.putc(msg_out.STX);
00251         msg_out.sm++;
00252         break;
00253       
00254       case 2: 
00255         RS485.putc(msg_out.source);
00256         msg_out.sm++;
00257         break;
00258 
00259       case 3: 
00260         RS485.putc(msg_out.dest);
00261         msg_out.sm++;
00262         break;
00263         
00264       case 4: 
00265         RS485.putc(msg_out.len); 
00266         msg_out.sm++;
00267         break;
00268         
00269       case 5: 
00270         for(int i=0; i < msg_out.len; i++)
00271         {
00272             RS485.putc(msg_out.data[i]);          
00273         }
00274         msg_out.sm++;
00275         break;
00276         
00277       case 6: 
00278         RS485.putc(msg_out.CRC);
00279         msg_out.sm++;
00280         break;
00281          
00282       case 7: 
00283         RS485.putc(msg_out.ETX);
00284         msg_out.sm++;
00285         break;
00286         
00287       case 8: 
00288         // hier warten bis alle Zeichen ausgegeben
00289         int n = RS485.txBufferGetCount();
00290         if (n == 0) msg_out.sm = 0;
00291         //tx_timeout1 = timeout.read_us();
00292         break; 
00293 
00294       case 9: 
00295         // hier warten bis alle Zeichen ausgegeben
00296 
00297         //tx_timeout2 = timeout.read_us();
00298         //if ((tx_timeout2 - tx_timeout1) >= 100) 
00299         //{
00300             msg_out.sm = 0;
00301             RS485_DIR = 0;      // Bus frei geben
00302             rs_aktiv = 0;       // Bus wieder auf Empfang
00303         //} 
00304         break;
00305        
00306       default:  // wird nie erreicht
00307         pc.printf(" error in sm send %d",msg_out.sm);
00308         break;                                                             // 
00309     } // end switch                                
00310 }
00311 
00312 // -----------------------------------------------------------------------
00313 // ein Telegramm lesen
00314 //
00315 void rs_485::receive(void)
00316 {
00317     uint8_t ch, pos;
00318  
00319     if (RS485.readable())  // prüfen ob Zeichen im buffer vorhanden
00320     {
00321     ch = RS485.getc();
00322     pc.printf(" %02x",ch);
00323     if ((ch == 0x02) && (msg_in.sm == 0))
00324     { 
00325         // ein neues Telegramm startet
00326         // ? ein timemout einbauen
00327         msg_in.STX = ch;
00328         msg_in.sm = 1;
00329     }
00330     else
00331     {
00332        switch(msg_in.sm)
00333        {
00334           case 1:
00335             msg_in.source = ch;
00336             msg_in.sm++;
00337             break;
00338             
00339           case 2:
00340             msg_in.dest = ch;
00341             msg_in.sm++;
00342             break;
00343             
00344           case 3:
00345             msg_in.count = ch;
00346             msg_in.sm++;
00347             pos = 0;
00348             break;
00349             
00350           case 4:
00351             msg_in.data[pos] = ch;
00352             pos++;
00353             msg_in.count--;
00354             if (msg_in.count == 0)
00355             {
00356               msg_in.sm++;   
00357             }
00358             break;
00359              
00360            case 5:
00361             msg_in.CRC = ch;
00362             msg_in.sm++;
00363             break;
00364             
00365            case 6:
00366             msg_in.ETX = ch;
00367             msg_in.sm = 0;  // auf ein neues Telegramm warten 
00368             rs_aktiv = 0;
00369               
00370             // CRC prüfen
00371             uint8_t crc = get_crc(&msg_in.source,msg_in.len+3); // CRC Summe ermitteln
00372             if (crc == msg_in.CRC)
00373             {
00374                 msg_in.error = 0xFF; // Telegramm korrekt empfangen
00375             }
00376             else
00377             {
00378                 msg_in.error |= 0x80; // CRC Fehler
00379             }
00380             
00381             // Telegramm ausgeben
00382             pc.printf("\n receive");
00383             msg_print(msg_in);
00384             pc.printf(" stauts: %02x\n",msg_in.error);
00385             
00386             break;   
00387        }
00388        }
00389     }
00390 }    
00391 
00392 
00393 
00394