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;
}
}
}
}
