Hope I’ve posted in the right place.
Last Monday somebody told me about the Arduino. By the w.end had a Relay shield driving motors in response to switches. Now I’m loosing what hair I have left.
Big project, build a modular control system for a 40’ sailing yacht (so that a high level quadriplegic can sail it).
Current step, replicate the PIC based system that controls her existing 20’ boat (hence switches and motors). Built by a guy in Canada some years ago, don’t have very much info.
Current problem, getting a Mega to talk to a Raymarine ST4000+ autopilot.
The ST4000+ talks to the world over SeaTalk (see Thomas Knauf SeaTalk Technical Reference). SeaTalk is a Raymarine proprietary bus.
11 bits are transmitted for each character:
1 Start bit (0V)
8 Data Bits
1 Command bit
1 Stop bit (+12V)
Where I am at the moment is reading SeaTalk on Serial 3 and then sending it to Serial Monitor over the USB. It looks like rubbish. What I want to know is how to set the serial port to 11 bits? Is there a command or procedure? How much control can be had over how the serial ports work?
In the Thomas Knauf article there code in C with the line:
Getting the SeaTalk working on this is a stepping stone to getting access to another set up (S1 tiller pilot, C80, ST60 instruments) on another boat. I want to be able to access the SeaTalk bus, read messages and send messages. I eventually want to be able to plug any manufacturers equipment into a boat control computer. Got to start somewhere.
So far what you have described is absolutely standard RS232 (async serial) communications with 9 data bits (you don't count the start and stop bit).
And from the Atmega spec on page 180 it says:
A serial frame is defined to be one character of data bits with synchronization bits (start and stop bits),
and optionally a parity bit for error checking.
The USART accepts all 30 combinations of the following as valid frame formats:
• 1 start bit
• 5, 6, 7, 8, or 9 data bits
• no, even or odd parity bit
• 1 or 2 stop bits
So, you want to configure it for 9 data bits, no parity, and 1 stop bit (and of course the right baud rate).
I don't have a SeaTalk to test it with, so how about showing your test code and we'll take it from there?
Data sheet I have (2549M-AVR-09/10), "8-Bit AVR Microcontroller with...." is talking about PWM on page 180, so I guess its not the one you are talking about. Page 215/216 looks like what your talking about but I don't have a clue how to write this into a sketch.
/*
HLOR / Toby May
Experimental stuff with Arduino Mega and home made hardware interface to SeaTalk.
Rx only.
I.Face is a pair of resistors as a voltage dropper.
Receives on serial port 3, sends to the main serial (Serial 0) and then to Monitor on a laptop.
This example for Arduino Mega
WORK IN PROGRESS - may not work!!!!!
*/
char not_receiver_buf,receiver_buf;
void setup() // initialise both serial ports
{
Serial.begin(9600);
Serial3.begin(4800);
}
void loop()
{ // Continuous data processing loop
if((Serial3.available()) > 0) // LSR New SeaTalk Data received ?
{
receiver_buf=Serial3.read(); // RBR Read SeaTalk Data Byte
not_receiver_buf=~receiver_buf; // Invert received character...
Serial.println(not_receiver_buf, HEX); // ...and prints it out.
}
}
By the way, this is doing it a different way. I am guessing he is using space parity, which means "the parity bit is always zero". There is also mark parity which is "the parity bit is always one". However browsing the Atmega documentation it doesn't seem to support mark and space parity (only odd, even and none).
If your device supports space and mark parity, then that is a way (perhaps a rather obscure one) of putting a 0 or 1 into the 9th bit.
I looked in the AVR 328 datasheet under the USART section. And indeed the hardware USART can be made to handle 9 data bit sending and receiving data transactions. This is not related to enabling the parity bit, as it appears if you want to utilize the 9 bit mode you can't also have parity enabled, one or the other or neither option are your choices. At least that's my read on the subject. It is however a little complex and requires extra steps to set up the 9th bit before sending the character out, or reading the 9th bit before reading the 8 bit character on received characters. This is certainly not something you can configure with the standard arduino serial commands. You would have to drop down to direct USART register controls and write your own serial library to accomplish 9 bit transactions. Like I said, a little complex and obscure but it is covered in the 328 datasheet in the USART section.
Yes indeed. Looking at the datasheet is always interesting. It is interesting that they allow for 9 bits OR parity. It's almost as if the 9th bit is "parity on the fly".
Anyway, this seemed to work for me, to change the 9th bit for every other byte:
void loop()
{
Serial.print ("a");
UCSR0B = 0b10011101; // turn 9th bit on
Serial.print ("a");
UCSR0B = 0b10011100; // turn 9th bit off
}
The low-order bit of the UCSRnC register (where n is the serial port) is the 9th bit. So by setting or clearing that before you send a byte, you control the contents of the 9th bit.
My solutions was to adapt the softserial library to get a 9th data bit. It was quite easy in the recv function. afther the loop, add an extra delay and receive the parity bit.
You have to juggle a bit with data types to get the 9th bit in the recv buffer. I cahnged the type from byte to int and shift the 9th bit completely to the left.
teeman,
could you share your softwareserial mod? I have Thomas Knauf's code for a pc, but bridging the gap in my understanding of how to mod the usart on the arduino uno is still beyond me.
Add me to the list of people interested in seeing your mods. I'm trying to talk to a raymarine display (no nmea) and it sounds like you have it figured out. Please share!
David,
Frank Wallenwein makes an excellent nmea-seatalk bridge. It is an ATMEGA32 small computer which accepts seatalk and nmea sentences and converts each type to the other and sends them out to their respective ports. I have one and it works brilliantly allowing me to show depth, windspeed and windangle on my notebook computer running PolarView (an inexpensive and excellent charting program which runs on Linux, MacOS, and Windows).
you get all of Frank's code on a cd when you buy the bridge (something about buying a bridge seems a bit off, but there it is). Code is C and wrritten for the Atmega32 .
my effort is to get part of it ported to arduino uno, although I think I'm going to get a mega2560 - won't have to cut so much. i wanted a repeater in my berth which shows heading, windspeed, wind-direction, depth, and distance and bearing to last time I pressed rest button - for drag detection.
I can do all this by feeding nmea-seatalk bridge data to arduino and input from arduino mounted tilt compensated compass, but I thought it would be better just to feed seatalk to arduino (wind and depth) and have one fewer devices running.
you may be able to get Frank's code if you ask him - don;t know, but i thought the Bridge was well worth the price.
Buying a seatalk<->nmea bridge was what I had hoped to avoid though thanks very much for the pointer to a low cost supplier as I may go that way if I have to. A Seatalk hack would be an awesome contribution to the sailing-arduino fan base! I understand that the signal would need to be turned into a 0-5 V TTl or rs232 or whatever and I can do that but modifying the softwareserial library to read the 9 bit seatalk protocall is currently beyond me. If someone were to make a library available, they would attain hero status amongst those of us on a budget and who are sailing older boats with 20 year old instruments!
I am building an arduino based autopilot for my boat and I was hoping to use (as additional input) wind direction (it's a sail boat) and boat speed (to try to make a surfing mode functionality and to adjust rudder response for one of the PID loops) from my existing ST50 instruments. I also have a spare raymarine ST50 display that I would like to use to display heading info from my fluxgate compass. The arduino works well for the compass NMEA and for controlling the linear actuator and with relatively little effort I have something that looks like it will drive the boat quite well (its too cold to test on the water now). Sailing to the wind and a sparkfun gyro are the next steps.
Thanks Nick, I did see what you wrote and I am intrigued. I will build the seatalk to rs232 level shifter hardware as soon as I get a moment and start playing around but... let me see if I have this right... On the UNO you would be talking about pins 1 and 2 labelled rx/tx which also serve as hardware serial ports. You describe how to turn on and off the ninth bite (where did those commands come from?) .... but how do (and here I fearlessly reveal my profound ignorance) the nine bits turn into an acsi character?
Cheers,
How do you turn 9 bits into ASCII? Well ASCII is normally 8 bits, so I suppose you mean "how do I get or send the 9th bit?".
The datasheet has examples (I've adapted them a bit):
Sending:
void USART_Transmit (unsigned int data)
{
/* Wait for empty transmit buffer */
while ( !(UCSR0A & _BV (UDRE0)))
{ }
UCSR0B &= ~_BV (TXB80); // clear 9th bit
if (data & 0x0100) // if 9th bit in "data" set, set 9th bit
UCSR0B |= _BV (TXB80);
UDR0 = data; // put remaining 8 bits in, and send it
}
Receiving:
unsigned int USART_Receive ()
{
byte status, resh, resl;
/* Wait for data to be received */
while ( !(UCSR0A & _BV (RXC0)) )
{ }
/* Get status and 9th bit, then data */
/* from buffer */
status = UCSR0A;
resh = UCSR0B;
resl = UDR0;
/* If error, return -1 */
if ( status & _BV(FE0) | _BV (DOR0) | _BV (UPE0) )
return -1;
/* Filter the 9th bit, then return */
resh = (resh >> 1) & 0x01;
return (resh << 8) | resl;
}
Now in both cases the 9th bit is in the 9th bit of the unsigned int that you are sending/receiving.
For the receiving part at least you might need to get into the HardwareSerial library to achieve this. But this is fairly simple.
David,
I 've ordered an arduino mega 2560 -- $38.50 +/- at Mouser. My plan is to migrate Wallenwein's code to it and work directly with the port. mega 2560 has more designated ports and I think I can do it without involving SoftwareSerial. I really don't know what I'm doing but i didn't the last time i got into something like this and eventually prevailed. When I get it running I'll try to back it down to an UNO. I don't know that it can't be done with an UNO, but the Mega seems to my ignorant view to be a closer sister to the atmega32.
idea of building an autopilot is a good one. I'm running our marine trader 36 sedan on a Cetrek with which I'm delighted, but it's an orphan and I need a back up plan.
A quick browse of HardwareSerial indicates you probably need to make a custom version for 9 bits. For one thing the internal buffer is only 8-bit characters so there is no room for the 9th bit in the incoming data stream.
So you probably need to increase the buffer to unsigned int (from unsigned char) and then build in the above code to get that 9th bit, if indeed 9 bits are being used.
11 bits are transmitted for each character:
1 Start bit (0V)
8 Data Bits (least significant bit transmitted first)
1 Command bit, set on the first character of each datagram. Reflected in the parity bit of most UARTs. Not compatible with NMEA0183 but well suited for the multiprocessor communications mode of 8051-family microcontrollers (bit SM2 in SCON set).
1 Stop bit (+12V)
Composition of Messages
Each datagram contains between 3 and 18 characters:
Type of command (the only byte with the command-bit set)
Attribute Character, specifying the total length of the datagram in the least significant nibble:
Most significant 4 bits: 0 or part of a data value
Least significant 4 bits: Number of additional data bytes = n =>
Total length of datagram = 3 + n characters
First, mandatory data byte