Program the control the fischertechnik robo interface or intelligent interface via tcp socket or via a java gui.
Diff: rs485.c
- Revision:
- 0:7f26f0680202
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rs485.c Fri Dec 31 14:01:14 2010 +0000 @@ -0,0 +1,160 @@ +//#define DEBUG //switches PB2 in interrupts and timeouts +#if 0 //for reference only +#define ALLOW_NESTING + +#include "data.h" +#include "rs485.h" + + +#define BAUD 921600 +#define DIRPORT PORTD +#define DIRBIT PD4 +#define DIRDIR DDRD +#define TRANSMIT asm("sbi %0, %1"::"I" (_SFR_IO_ADDR(DIRPORT)),"I" (DIRBIT)); +#define RECEIVE asm("cbi %0, %1"::"I" (_SFR_IO_ADDR(DIRPORT)),"I" (DIRBIT)); + + +uint8_t /*wpos = 0,*/ rpos = 0; +volatile uint8_t rs485_timeout = 0; +volatile uint8_t rs485_delay = 0; +static char* wposp = (char*)&msg.hdr.snd; +static char state = 0; + +void init_rs485() +{ +/*Set baud rate */ +//Enable receiver and transmitter (also interrupts) +// UCSR0B = _BV(RXEN0) | _BV(TXEN0) | _BV(RXCIE0) /*| _BV(UDRIE0)*/; +/* Set frame format: 8data, 1stop bit */ +// UCSR0C = (3<<UCSZ00); +//set tranceiver +// RECEIVE; +// DIRDIR |= _BV(DIRBIT); //set enable as output +} + +void enable_rx_rs485() +{ + UCSR0B |= _BV(RXEN0) | _BV(RXCIE0); //enable uart rx + RECEIVE; +} + +void send_rs485() +{ rpos = 0; +//set RS485 tranceiver in send mode + TRANSMIT; +//disable rx interrupt + UCSR0B &= ~(_BV(RXCIE0) | _BV(RXEN0)); +//enable tx interrupt, will immediately generate int + UCSR0B |= _BV(UDRIE0); +//kick off transmission +// UDR0 = ((char*)&msg)[rpos++];//not necessary, will start by itself + rs485_timeout = sizeof(msg)/8; //just a precaution, transmit should not timeout, timeout is approx. 110% of expected time +} + +ISR(USART_RX_vect) +{ + SETPIN12; +#ifdef ALLOW_NESTING + MASK_TIMER_INT(); + MASK_EXTENSION_INT(); + MASK_DISTANCE_INT(); + MASK_IR_INT(); + //MASK_EEPROM_INT(); + sei(); +#endif + register char *wp asm("r30") = wposp; + register char data asm("r1"); + do + { data = UDR0; + rs485_timeout = 2;//set a timeout of 100-200us equiv. to 10-20 bytes + switch (state) + { case 0: //idle + if (data == 0x02) + state = 1; + else if (data == 0xA0)//this is really a hack, it avoids timeouts in case of a bad start + state = 5; + break; + case 1: //stx + if (data == 0x55) + state = 2; + else + state = 0; + break; + case 2://length H, high byte comes first + msg.hdr.bytesL = data; + state = 3; + break; + case 3://length L, low byte + msg.hdr.bytesH = data; + if (msg.hdr.bytes > sizeof(msg)-7) + state = 0; //message structure cannot accomodate message this size + else + state = 4; + break; + case 4://store + *wp++ = data; + if (wp >= ((char*)&msg.hdr.snd + sizeof(trailer)) + msg.hdr.bytes + && wp <= (char*)&msg + sizeof(message) + 1 + ) + { //message complete + wp = (char*)&msg.hdr.snd; + rs485_timeout = 0; + //tx_message = find_ad(msg.hdr.rec) > 0; + tx_message = msg.hdr.rec - 3; + if (tx_message >= 0) + { UCSR0B &= ~(_BV(RXCIE0) | _BV(RXEN0)); //disable rec to avoid corruption by new messages + } + state = 0; + } + break; + case 5://wrong start + if (data == 0x15)//after a wrong start A0 i.o. 02, the 55 gets read as 15 + { msg.hdr.bytesL = 0; + state = 3; + } + else + state = 0; + default: + break; + } + } while (UCSR0A & _BV(RXC0)); //see if another char is available, now it is fast enough so this is normally not the case + wposp = wp; +#ifdef ALLOW_NESTING + cli(); + UNMASK_TIMER_INT(); + UNMASK_EXTENSION_INT(); + UNMASK_DISTANCE_INT(); + UNMASK_IR_INT(); + //UNMASK_EEPROM_INT(); +#endif + CLRPIN12; +} + + +ISR(USART_UDRE_vect) +{ SETPIN12; + if (rpos > BYTES()+7) + { //last byte was sent + RECEIVE; + UCSR0B &= ~_BV(UDRIE0); //disable tx int + UCSR0B |= _BV(RXCIE0) | _BV(RXEN0); //re-enable rx int + rs485_timeout = 0; + } + else//send 1 byte too many in order to detect that the etx char was sent + UDR0 = ((char*)&msg)[rpos++]; + CLRPIN12; +} + +void timeout_rs485() +{ SETPIN12; + //reset receiver + wposp = (char*)&msg.hdr.snd; + state = 0; + //reset transmitter + rpos = 0; + RECEIVE; + UCSR0B &= ~_BV(UDRIE0); //disable tx int + UCSR0B |= _BV(RXCIE0) | _BV(RXEN0); //re-enable rx int + CLRPIN12; +} +#endif