This post will be of interest to programmers. I document how measured and calculated data are transferred from the microcontroller to the notebook, which is responsible to build the real-time displays.
In this Part 1, we look at the microprocessor side of the transfer.
For efficiency, all transferred data are in binary form, mostly in floating point format.
Within each cycle of 0.1 second (10 Hz), the microprocessor populates the ‘dump_info’ structure with measured and calculated values. At the end of the cycle, this data structure is copied to the ‘ubuff’ transmit buffer. The first 6 bytes of the transmit buffer, which contain the magic word ‘MERLIN’ , remain unchanged. This magic word will be used by the notebook to identify and confirm the beginning of a new data structure.
The transmit buffer is sent through USART0 of the microcontroller to the serial-to-USB converter, at a baud rate of 9600. This baud rate is the fastest that the notebook can handle at the other end among its other tasks. Higher baud rates could be handled by more powerful laptops, but the notebook has been chosen because of its longer battery life (around 9 hours). The transfer uses interrupt-based routines, because with poll-based strategy, it would not be possible to achieve the 10 Hz rate.
// Initialization
typedef union
{
unsigned char dump[76];
struct
{
double mwa; // measured apparent wind angle
double awa; // awa corrected for heel
double twa; // true wind angle
double aws; // apparent wind speed
double tws; // true wind speed
double wdir; // wind direction
double mbs1; // measured boat speed (starboard)
double mbs2; // measured boat speed (port)
double stw; // boat speed through water
double vmg; // velocity made good
double heading; // corrected heading
double heel; // heel angle
double leeway; // calculated leeway angle
double doc; // direction of current
double soc; // speed of current
double cog; // GPS course over ground
double sog; // GPS speed over ground
int long1; // GPS longitude (1st part)
int long2; // GPS longitude (2nd part)
int lat1; // GPS latitude (1st part)
int lat2; // GPS latitude (2nd part)
};
} dump_union; // double are 4 bytes, int are 2 bytes
dump_union dump_info;
static char ubuff[82];
int main(void)
{
/* USART0 : Set baud rate : 9600 @ 16MHz */
UBRR0L = (unsigned char)(103);
/* Enable transmitter */
UCSR0B =_BV(TXEN0);
// initialize the magic word
ubuff[0] = 'M';
ubuff[1] = 'E';
ubuff[2] = 'R';
ubuff[3] = 'L';
ubuff[4] = 'I';
ubuff[5] = 'N';
txindex = 0;
/* enable interrupts */
sei();
/* enable interrupts */
sei();
for(;;)
{
// begin a new cycle
// Measure and calculate new data,
// put results in dump_info structure
// ...
// dump_info.mwa = ...
// dump_info.awa = ...
// dump_info.twa = ...
// ...
// dump_info.long2 = ...
// dump_info.lat1 = ...
// dump_info.lat2 = ...
// Populate the transmit buffer,
// without changing the first 6 bytes
for(i = 6; i < 82; i++) // 76 + 6 = 82
ubuff[i] = dump_info.dump[i-6];
UCSR0B |= _BV(UDRIE0); // start transmitting
// Wait for timer signal to begin a new cycle
//...
}
}
// This interrupt routine will be called 82 times within
// the next 100 ms then will disable itself
ISR(USART0_UDRE_vect)
{
if(txindex < 81)
UDR0 = ubuff[txindex++];
else
{
UDR0 = ubuff[81];
txindex = 0;
UCSR0B &= ~(_BV(UDRIE0)); // stop transmitting
}
}
No comments:
Post a Comment