Program the control the fischertechnik robo interface or intelligent interface via tcp socket or via a java gui.
rs485.c
- Committer:
- networker
- Date:
- 2010-12-31
- Revision:
- 0:7f26f0680202
File content as of revision 0:7f26f0680202:
//#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