Zeitsteuerung
Fork of timer0 by
rs_485.cpp
- Committer:
- rs27
- Date:
- 2016-02-05
- Revision:
- 1:8779e76fd4ea
File content as of revision 1:8779e76fd4ea:
//--------------------------------------------------------------------------- // Modul...: RS_485.CPP // Chip....: iox.mini // //--------------------------------------------------------------------------- // Author..: Reinhold Schäfer // Date....: 2016.01.23 // http....: //www.microsps.net //--------------------------------------------------------------------------- #include "mbed.h" #include "rs_485.h" #include "timer0.h" MODSERIAL RS485(RS485_TX2, RS485_RX2); // tx, rx DigitalOut RS485_DIR(RS485_DIR2,0); // RS485 Direction extern MODSERIAL pc; extern timer0 down_timer; // definiert in main //-------------------------------------------------------- // Interruptroutine wird nach 300µs aufgerufen, da das Senden von // einem Zeichen ca. 100µs Zeit beansprucht, kann die Umschaltung // auf Empfang erst verzögert erfolgen. void rs_485::isr_timeout(void) { RS485_DIR = 0; // auf Empfang umschalten send_end_flag = true; } /* // ----------------------------------------------------------------------- // This function is called when TX buffer goes empty // void rs_485::txEmpty(MODSERIAL_IRQ_INFO *q) { timeout.attach_us(this, &rs_485::isr_timeout, 300); // Zeit für das Umschalten } */ //-------------------------------------------------------- // Construktor initialisiert den Timer rs_485::rs_485() { RS485.baud(115200); //RS485.attach(this, &rs_485::txEmpty); timeout.stop(); timeout.reset(); msg_in.sm = 0; msg_out.sm = 0; rs_aktiv = 0; rs_aktiv_old = 0; } //------------------------------------------------------------- // Checksum ermitteln uint8_t rs_485::get_crc(uint8_t *pbuffer, uint8_t count) { uint8_t crc_value = 0; uint8_t temp; // CheckSum calculation for(int i=0; i <= count; i++) { temp = *pbuffer; // pc.printf("\n CRC #%02d %02x ^ %02x = ",i,crc_value,temp); crc_value ^= temp; // XOR from ID to Data pbuffer++; // pc.printf("%02x",crc_value); } return crc_value; } //------------------------------------------------------------- // zum Testen das Telegramm ausgeben // void rs_485::msg_print(Message msg) { uint8_t len; pc.printf(" %02d:%02d:%02d.%03d",msg.h,msg.m,msg.s,msg.ms); pc.printf(" %02x",msg.STX); pc.printf(" %02x",msg.source); pc.printf(" %02x",msg.dest); pc.printf(" %02x [",msg.len); len = msg.len; for (int i = 0; i < len; i++) { pc.printf(" %02x",msg.data[i]); } pc.printf(" ] %02x",msg.CRC); pc.printf(" %02x",msg.ETX); } // ----------------------------------------------------------------------- // eine Telegramm erzeugen // // die Zeichen STX, CRC und ETX werden automatisch erzeugt // das Telegramm hat folgenden Aufbau // STX ADR ZIEL Länge [daten] CRC ETX // Länge ist Anzahl der Zeichen im Datenfeld // void rs_485::write(uint8_t *data) { uint16_t millis; uint8_t len; msg_out.STX = 0x02; // STX msg_out.source = *data; // Start Adresse data++; msg_out.dest = *data; // Ziel Adresse data++; msg_out.len = *data; // Länge len = *data; data++; for (int i = 0; i < len; i++) { msg_out.data[i] = *data; // Datenbyte data++; } // pc.printf("\n write crc berechnen \n"); msg_out.CRC = get_crc(&msg_out.source,msg_out.len+3); // CRC Summe ermitteln msg_out.ETX = 0x03; // Telegramm Abschluss // Zeitstempel schreiben down_timer.get_time_stamp(t_array,&millis); msg_out.h = t_array[0]; msg_out.m = t_array[1]; msg_out.s = t_array[2]; msg_out.ms = millis; // Datenausgabe wird aktiviert, prüfen ob harte Umschaltung hier sinnvoll msg_out.sm = 0; rs_aktiv = 2; } //------------------------------------------------------------- // Die Telegramme steuern und überwachen // void rs_485::execute(void) { // auf timeout testen, falls ein fehler auftritt // wird das Telegramm über diese Stelle abgebrochen // int temp; temp = timeout.read_ms(); if (temp >= 10) { timeout.stop(); timeout.reset(); msg_in.sm = 0; msg_out.sm = 0; if (rs_aktiv == 1) { pc.printf("\nreceive timeout %02d ms",temp); pc.printf("\n sm: %02x",msg_in.sm); pc.printf("\n tel:"); msg_print(msg_out); } if (rs_aktiv == 2) { pc.printf("\nsende timeout %02d ms",temp); pc.printf("\n sm: %02x",msg_out.sm); pc.printf("\n tel:"); msg_print(msg_out); } rs_aktiv = 0; } // an dieser Stelle wird der Programmablauf gesteuert // 0 Bus inaktiv auf Empfang // 1 BUS aktiv auf Empfangsmode // 2 BUS aktiv im Sendemode switch (rs_aktiv) { case 0: if (rs_aktiv != rs_aktiv_old) { pc.printf("\n\nreceive"); timeout.stop(); // timer starten timeout.reset(); // timer auf 0 setzen rs_aktiv_old = rs_aktiv; } receive(); break; case 1: if (rs_aktiv != rs_aktiv_old) { pc.printf("\n\nreceive aktiv"); timeout.reset(); // timer auf 0 setzen timeout.start(); rs_aktiv_old = rs_aktiv; } receive(); break; case 2: if (rs_aktiv != rs_aktiv_old) { pc.printf("\n\nsende aktiv"); timeout.reset(); // timer auf 0 setzen timeout.start(); rs_aktiv_old = rs_aktiv; } send(); break; } // end switch } // ----------------------------------------------------------------------- // das Telegramm ausgeben // void rs_485::send(void) { switch(msg_out.sm) { case 0: // das Senden beginnt erst, wenn das eingehende Telegramm abgeschlossen ist msg_print(msg_out); pc.printf(" \n"); RS485_DIR = 1; // Bus belegen msg_out.sm = 1; break; case 1: // Startzeichen senden RS485.putc(msg_out.STX); msg_out.sm++; break; case 2: RS485.putc(msg_out.source); msg_out.sm++; break; case 3: RS485.putc(msg_out.dest); msg_out.sm++; break; case 4: RS485.putc(msg_out.len); msg_out.sm++; break; case 5: for(int i=0; i < msg_out.len; i++) { RS485.putc(msg_out.data[i]); } msg_out.sm++; break; case 6: RS485.putc(msg_out.CRC); msg_out.sm++; break; case 7: RS485.putc(msg_out.ETX); msg_out.sm++; break; case 8: // hier warten bis alle Zeichen ausgegeben int n = RS485.txBufferGetCount(); if (n == 0) msg_out.sm = 0; //tx_timeout1 = timeout.read_us(); break; case 9: // hier warten bis alle Zeichen ausgegeben //tx_timeout2 = timeout.read_us(); //if ((tx_timeout2 - tx_timeout1) >= 100) //{ msg_out.sm = 0; RS485_DIR = 0; // Bus frei geben rs_aktiv = 0; // Bus wieder auf Empfang //} break; default: // wird nie erreicht pc.printf(" error in sm send %d",msg_out.sm); break; // } // end switch } // ----------------------------------------------------------------------- // ein Telegramm lesen // void rs_485::receive(void) { uint8_t ch, pos; if (RS485.readable()) // prüfen ob Zeichen im buffer vorhanden { ch = RS485.getc(); pc.printf(" %02x",ch); if ((ch == 0x02) && (msg_in.sm == 0)) { // ein neues Telegramm startet // ? ein timemout einbauen msg_in.STX = ch; msg_in.sm = 1; } else { switch(msg_in.sm) { case 1: msg_in.source = ch; msg_in.sm++; break; case 2: msg_in.dest = ch; msg_in.sm++; break; case 3: msg_in.count = ch; msg_in.sm++; pos = 0; break; case 4: msg_in.data[pos] = ch; pos++; msg_in.count--; if (msg_in.count == 0) { msg_in.sm++; } break; case 5: msg_in.CRC = ch; msg_in.sm++; break; case 6: msg_in.ETX = ch; msg_in.sm = 0; // auf ein neues Telegramm warten rs_aktiv = 0; // CRC prüfen uint8_t crc = get_crc(&msg_in.source,msg_in.len+3); // CRC Summe ermitteln if (crc == msg_in.CRC) { msg_in.error = 0xFF; // Telegramm korrekt empfangen } else { msg_in.error |= 0x80; // CRC Fehler } // Telegramm ausgeben pc.printf("\n receive"); msg_print(msg_in); pc.printf(" stauts: %02x\n",msg_in.error); break; } } } }