/*
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: ANSI (CP1252) | 4
|
|