Source file: /~heha/ewa/Kram/Solarpaneel.zip/C-Programm/ser0.c

/*
Projekt: Photovoltaik-Präsentation "solar" mit MSP430
Detail: Zweit-Anzeige des Displays und der Tableaus via HyperTerminal
061106	erstellt
*/
#include "solar.h"
#include <mspgcc/ringbuffer.h>
#include <string.h>	// memchr
#include <sys/unistd.h>	// _reset_vector__

/* Hardware-Anschluss:
 P3.4 = TxD0 Sendedaten
 P3.5 = RxD0 Empfangsdaten
(P3.6 = TxD1)
(P3.7 = RxD1)
 */

#define BAUDRATE0 38400	// Baudrate in Schritt/s
	//061108: 115200 zu schnell für fehlerfreien Empfang
	//Es liegt NICHT am zu kleinen Teiler (=69, e<0,6%) bzw. Notwendigkeit
	//der Verwendung von U0MCTL, dem Modulationsregister
#define TXBUFSIZE 82	// Sendepuffergröße in Bytes (=Zeichen)
#define RXBUFSIZE 10	// Empfangspuffergröße in Bytes (=Zeichen)
#define XONXOFF		// Benutze XON/XOFF-Flusskontrolle

#ifdef XONXOFF
# define XON  0x11	// ^Q
# define XOFF 0x13	// ^S
# define HIWATERMARK 8	// XOFF senden wenn Empfangspuffer mehr als 8 Zeichen hat
# define LOWATERMARK 2	// XON senden wenn -"- weniger als 2 Zeichen hat
static char TxUrgent;	// zum Senden von XON/XOFF am Sendepuffer vorbei
BYTE Ser0Flags;	// u.a. zur Abschaltung von XON/XOFF während XYZMODEM
#endif

RINGBUFFER_NEW(TxRing,TXBUFSIZE);	// Sendepuffer
RINGBUFFER_NEW(RxRing,RXBUFSIZE);	// Empfangspuffer

/************************************************************************
 * Serielle Schnittstelle 0 mit Baudrate-8-n-1 initialisieren
 ************************************************************************/
void Ser0Init(void){
 P3SEL|=0x30;	//High-Nibble von Port3 sind serielle Schnittstellen
 P3DIR|=0x10;	//TxD ist Ausgang
#ifdef XONXOFF
 Ser0Flags=0xFF;	// alle Flags EIN
	// das nächste getchar() sendet ein XON, um eine möglicherweise
	// per XOFF festgefressene Schnittstelle (auf PC-Seite) loszueisen.
	// In der Senderichtung wird die Flusskontrolle ausschließlich mit
	// dem Interruptfreigabe-Bit realisiert.
#endif
#define UBR0 ((CPUCLK+(BAUDRATE0)/2)/(BAUDRATE0))
 U0CTL  = CHAR|SWRST;		//8 Datenbit(4), Reset(0)
 U0TCTL = 0x20;			//Taktquelle=SMCLK (8MHz) (5:4)
 U0BR0  = (BYTE)UBR0;
 U0BR1  = (BYTE)(UBR0>>8);
 U0MCTL = 0;			//Keine Modulation
 ME1   |= UTXE0|URXE0;		//Tx(7),Rx(6) aktivieren
#undef UBR0
 ringbuffer_clear(&TxRing);
 ringbuffer_clear(&RxRing);
 U0CTL &=~SWRST;		// kein Reset(0)
 IE1   |= UTXIE0|URXIE0;	// Interrupts(7)(6) aktivieren
#ifdef XONXOFF
 TransmitCommChar(XON);		// Gegenseite darf Daten liefern
 Ser0Flags&=~fXoffSent;
#endif
}

static void SendCharacterFromBuffer(void) {
#ifdef XONXOFF
 if (TxUrgent) {
  TXBUF0=TxUrgent;
  TxUrgent=0;
  return;
 }
#endif
 {
  int ch=ringbuffer_get(&TxRing);
  if (ch!=-1) TXBUF0=(char)ch;
 }
}

interrupt(USART0TX_VECTOR) Usart0_TxEmpty(void) {
// Nächstes Byte aus Sende-Ringpuffer nachschieben
 SendCharacterFromBuffer();
}

#ifdef XONXOFF
void TransmitCommChar(char c) {
 TxUrgent=c;
 if (U0TCTL&TXEPT) SendCharacterFromBuffer();
}
#endif

interrupt(USART0RX_VECTOR) Usart0_RxFilled(void) {
// Nächstes Byte in Empfangs-Ringpuffer schreiben
#ifdef XONXOFF
 int fill;
 int ch=U0RXBUF;	// mspgcc stellt sich mit "char" nicht allzu clever an
// Zeichen auf Flusskontrollzeichen prüfen und diese sofort behandeln
 if (Ser0Flags&fOutX) switch (ch) {
  case XOFF: {
   IE1&=~UTXIE0;	// Interrupts aus: Datenausstoß einstellen
  }return; 	// (außer XON/XOFF für die Flusskontrolle in Gegenrichtung)
  
  case XON: {
   IE1|= UTXIE0;	// Interrupts ein
   if (U0TCTL&TXEPT) SendCharacterFromBuffer();	// Datenausstoß starten
  }return;
  
  case 0x12: _reset_vector__();
	// hier bei ^R zum Low-Level-Reset springen... - geht nicht!!!
 }
// Zeichen in Empfangspuffer schreiben, Zeichen geht verloren wenn Puffer voll
 fill=ringbuffer_put(&RxRing,ch);
// Bei Hochwasserstand Gegenseite per XOFF anweisen, den Datenausstoß
// einzustellen. Der "unsigned"-Typecast deckt den Fall "-1" ab.
// Weil i.d.R. mehrere XOFF gesendet werden (Latenz), sollte die Gegenseite
// nicht die XOFFs akkumulieren (das ist der Normalfall)
 if (Ser0Flags&fInX && (unsigned)fill>HIWATERMARK) {
  TransmitCommChar(XOFF);
  Ser0Flags|=fXoffSent;
 }
#else
// Zeichen in Empfangspuffer schreiben, Zeichen geht verloren wenn Puffer voll
 ringbuffer_put(&RxRing,U0RXBUF);
#endif
}

static const unsigned char ansi2oem[0x80]={
0x9E,0x9F,0xA9,0xB0,0xB1,0xB2,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,
0xBE,0xBF,0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,
0xFF,0xAD,0x9B,0x9C,0xE8,0x9D,0xB3,0xEB,0xCE,0xCF,0xA6,0xAE,0xAA,0xD0,0xD1,0xD2,
0xF8,0xF1,0xFD,0xD3,0xD4,0xE6,0xD5,0xFA,0xD6,0xD7,0xA7,0xAF,0xAC,0xAB,0xD8,0xA8,
0xD9,0xDA,0xDB,0xDC,0x8E,0x8F,0x92,0x80,0xDD,0x90,0xDE,0xDF,0xE0,0xE2,0xE3,0xE4,
0xE5,0xA5,0xE7,0xE9,0xEA,0xEC,0x99,0xED,0xEE,0xEF,0xF0,0xF2,0x9A,0xF3,0xF4,0xE1,
0x85,0xA0,0x83,0xF5,0x84,0x86,0x91,0x87,0x8A,0x82,0x88,0x89,0x8D,0xA1,0x8C,0x8B,
0xF7,0xA4,0x95,0xA2,0x93,0xF9,0x94,0xF6,0xFB,0x97,0xA3,0x96,0x81,0xFC,0xFE,0x98};


int getchar(void) {
 int ch;
#ifdef XONXOFF
// Der Gegenseite XON melden, wenn Empfangspuffer Niedrigwasserstand erreicht
// Es wird nur ein XON gesendet, was zur Blockade führt, falls dieses Zeichen
// nicht den Weg zur Gegenseite findet...
 if (!(~Ser0Flags&(fInX|fXoffSent)) && ringbuffer_len(&RxRing)<=LOWATERMARK) {
  TransmitCommChar(XON);
  Ser0Flags&=~fXoffSent;
 }
#endif
// Zeichen aus Empfangspuffer liefern, blockieren wenn dieser leer ist
 while ((ch=ringbuffer_get(&RxRing))==-1) Idle();
 if (Ser0Flags&fInConv && (signed char)ch<0) {
  char*p=memchr(ansi2oem,ch,sizeof(ansi2oem));	// Suchen (Umlaute von Tastatur)
  if (p) ch=*p;
 }
 return ch;
}

int putchar(int c) {
 c&=0xFF;
 if (c==0x0A && Ser0Flags&fCRLF) putchar(0x0D);
 if (Ser0Flags&fOutConv && (signed char)c<0) {
  c=ansi2oem[c&0x7F];
 }
// Solange blockieren bis Zeichen in Puffer passt
 while (ringbuffer_put(&TxRing,c)==-1) Idle();
// ISR aufwecken, falls sie nur schläft
 if (U0TCTL&TXEPT && IE1&UTXIE0) SendCharacterFromBuffer();
 return 0;
}

extern bool kbhit(void) {
 return ringbuffer_len(&RxRing);
}
Detected encoding: UTF-80