The SeaTalk repeaters are used as backup displays, useful when the notebook and/or the outdoor monitor are not available for some reason. For example, in low battery situation when the more power hungry monitor has to be shut off. I first tried a custom 7-segment LED display for this function, but it proved unreadable in the sun. I then decided to go with Raymarine ST40 repeaters for their easy-to-read displays in all conditions.
I found all the information I needed on Thomas Knauf’s website (www.thomasknauf.de/seatalk.htm). The SeaTalk protocol is peculiar in that it requires 9-bit ‘bytes’ instead of the usual 8-bit, which is why it cannot be interfaced directly with a PC. The ATmega microprocessor has built-in support for 9-bit communication. The SeaTalk protocol requires that you set the 9th bit to 1 for the first byte of a command, and reset it to 0 for the remaining bytes of the same command.
I built the bidirectional interface described on Thomas Knauf’s website, even if I use it only one-way. For the transistors, I picked a 2N3904 (NPN) and a 2N3906 (PNP).
With this post, I begin to present some code examples for the Atmega128, using the WinAVR environment (http://winavr.sourceforge.net/). The following example shows how to send 5 SeaTalk commands that the repeaters can recognize, using interrupt-driven communication for efficiency. The SeaTalk bus is connected to the USART1 of the microprocessor. The commands are first built in a byte array before being sent to USART1, configured at 4800 baud per the SeaTalk protocol.
/* Some inialization */
volatile char stbuff[21];
volatile uint8_t stindex = 0;
uint16_t data;
/* enable serial port UART1 */
/* Set baud rate : 4800 @ 16 MHz */
UBRR1L = (unsigned char)(207);
/* Enable transmitter with 9 data bits */
UCSR1B = _BV(TXEN1) | _BV(UCSZ12);
double stw = 5.9; // speed through water (STW) in knots
double depth = 50.0; // depth in feet
double temp = 70.0; // temperature in degrees F
double awa = -32.0; // apparent wind angle (AWA) in degrees
double aws = 11.0; // apparent wind speed (AWS) in knots
// build the STW command
data = (uint16_t)(stw * 10.0 + 0.5);
stbuff[0] = 0x20;
stbuff[1] = 0x01;
stbuff[2] = data;
stbuff[3] = data >> 8;
// build the depth command
data = (uint16_t)(depth * 10.0 + 0.5);
stbuff[4] = 0x00;
stbuff[5] = 0x02;
stbuff[6] = 0x00;
stbuff[7] = data;
stbuff[8] = data >> 8;
// build the temperature command
data = (uint16_t)(temp * 10.0 + 0.5 + 100.0);
stbuff[9] = 0x27;
stbuff[10] = 0x01;
stbuff[11] = data;
stbuff[12] = data >> 8;
data = (uint16_t)(depth * 10.0 + 0.5);
stbuff[4] = 0x00;
stbuff[5] = 0x02;
stbuff[6] = 0x00;
stbuff[7] = data;
stbuff[8] = data >> 8;
// build the temperature command
data = (uint16_t)(temp * 10.0 + 0.5 + 100.0);
stbuff[9] = 0x27;
stbuff[10] = 0x01;
stbuff[11] = data;
stbuff[12] = data >> 8;
// build the AWS command
double dummy;
uint8_t data8_1 = (uint8_t)aws;
uint8_t data8_2 = (uint8_t)(modf(aws, &dummy) * 10.0 + 0.5);
if(data8_2 == 10)
{
data8_1 += 1;
data8_2 = 0;
}
stbuff[13] = 0x11;
stbuff[14] = 0x01;
stbuff[15] = data8_1;
stbuff[16] = data8_2;
// build the AWA command
if(awa < 0.0)
awa += 360.0;
data = ((uint16_t)(awa + 0.5)) * 2;
stbuff[17] = 0x10;
stbuff[18] = 0x01;
stbuff[19] = data >> 8;
stbuff[20] = data;
// enable the interrupt that fires when the USART1
// is ready to accept a new character to send
UCSR1B |= _BV(UDRIE1);
// This interrupt routine will be called 21 times then will disable itself.
// Once a value is written in the UDR1 register, the USART will take care of
// sending it on the bus and the processor will be free to do its own things
// until the USART reports (by firing a new interrupt) that it is ready to accept
// another byte.
ISR(USART1_UDRE_vect)
{
// 4-5-4-4-4 : 21 bytes 1000-10000-1000-1000-1000 0-4-9-13-17
switch(stindex)
{
case 0:
case 4:
case 9:
case 13:
case 17:
UCSR1B |= _BV(TXB81); // set 9th bit to 1
break;
default:
UCSR1B &= ~(_BV(TXB81)); // reset 9th bit to 0
}
if(stindex < 20)
UDR1 = stbuff[stindex++];
else
{
UDR1 = stbuff[20];
stindex = 0;
UCSR1B &= ~(_BV(UDRIE1)); // disable interrupt
}
}
double dummy;
uint8_t data8_1 = (uint8_t)aws;
uint8_t data8_2 = (uint8_t)(modf(aws, &dummy) * 10.0 + 0.5);
if(data8_2 == 10)
{
data8_1 += 1;
data8_2 = 0;
}
stbuff[13] = 0x11;
stbuff[14] = 0x01;
stbuff[15] = data8_1;
stbuff[16] = data8_2;
// build the AWA command
if(awa < 0.0)
awa += 360.0;
data = ((uint16_t)(awa + 0.5)) * 2;
stbuff[17] = 0x10;
stbuff[18] = 0x01;
stbuff[19] = data >> 8;
stbuff[20] = data;
// enable the interrupt that fires when the USART1
// is ready to accept a new character to send
UCSR1B |= _BV(UDRIE1);
// This interrupt routine will be called 21 times then will disable itself.
// Once a value is written in the UDR1 register, the USART will take care of
// sending it on the bus and the processor will be free to do its own things
// until the USART reports (by firing a new interrupt) that it is ready to accept
// another byte.
ISR(USART1_UDRE_vect)
{
// 4-5-4-4-4 : 21 bytes 1000-10000-1000-1000-1000 0-4-9-13-17
switch(stindex)
{
case 0:
case 4:
case 9:
case 13:
case 17:
UCSR1B |= _BV(TXB81); // set 9th bit to 1
break;
default:
UCSR1B &= ~(_BV(TXB81)); // reset 9th bit to 0
}
if(stindex < 20)
UDR1 = stbuff[stindex++];
else
{
UDR1 = stbuff[20];
stindex = 0;
UCSR1B &= ~(_BV(UDRIE1)); // disable interrupt
}
}
In the current installation, I use the ST40 Bidata repeater to show the boat speed through water (STW), but I cheat by sending the VMG value for depth, and the speed of the current for temperature. For the the ST40 wind repeater, I send the usual apparent wind angle, but I cheat again by sending the true wind speed value for AWS, as I like to see the AWA and TWS together on the same display.
The data sent to the repeaters are the running averages over the last 4 seconds, sent at the 10 Hz rate. However, the repeaters are internally refreshed only one time per second, and with a one second delay. The values newly displayed are thus the average of the first 4 seconds of the last period of 5 seconds (you have to read this twice).
If anyone is interested in hooking up a B&G system, I did some work decoding the fastnet bus:
ReplyDeletehttp://www.oppedijk.com/bandg/fastnet