Ahh so freqCount will work over on the side while the main loop runs?
Yes; counting happens without processor intervention.
The rpm pickup is a wire wrapped around the sparkplug lead, with some smoothing hardware, which then runs a transistor to send the signal back to the microcontroller. Though changing the transistor to a optocoupler might be a smart move. I had it working on the arduino using an interrupt, i put it on a car and the results matched the taco.
Sounds good to me -- although I haven't worked with combustion engines, and you might wish to keep the transistor to ensure it feeds enough current to the optocoupler infrared LED; typically something like 20mA.
I haven't started looking at the logging yet, I'm starting with the screen, then the sensors then finally the actual logging. I'm assuming I'd log to SD card on the teensy?
That is what I'd do. See the Datalogger example in Paul's
SD library.
To receive a message from the display, I'd use something like the following. This uses 261 bytes, but supports all possible responses. You can make the buffer smaller if you need to conserve memory; just make sure you never set
response_more larger than the buffer size.
The idea is that when header_have < 3, we add another header byte. When we read the third header byte, we initialize the response buffer. When we complete the response buffer, we call a function to handle the response, then reset header_have = response_more = response_left = 0 for the next response.
Code:
#define DISPLAY_SERIAL Serial1
#define DISPLAY_HEADER1 0xA5
#define DISPLAY_HEADER2 0x5A
static unsigned char header_have;
static unsigned char header[2];
static unsigned char response_more;
static unsigned char response_have;
static unsigned char response[255];
static unsigned char response_pending;
void setup(void)
{
header_have = 0;
response_have = 0;
response_pending = 0;
}
void received_display_registers(unsigned char first, unsigned char data[], unsigned char len)
{
/* Received 'len' bytes of register contents in 'data[0 .. len-1]',
with first register being 'first'. */
}
void received_display_value(unsigned short address, unsigned short value)
{
/* Received 'value' for address 'address'. */
}
static void check_display_response(void)
{
int byte;
while (DISPLAY_SERIAL.available() > 0) {
byte = DISPLAY_SERIAL.read();
if (byte < 0)
return; /* No additional data */
if (header_have < 2) {
header[header_have++] = byte;
continue;
} else
if (header_have == 2) {
response_have = 0;
response_more = byte;
if (byte < 1) {
/* Zero response length should not occur, but handle that too. */
header_have = 0;
response_pending = 0;
}
continue;
} else {
response[response_have++] = byte;
if (--response_more < 1) {
header_have = 0;
response_pending = 0;
if (response_have < 2)
continue;
if (header[0] != DISPLAY_HEADER1 || header[1] != DISPLAY_HEADER2)
continue;
if (response[0] == 0x81 && response[2] == response_have - 2) {
received_display_registers(response[1], response + 3, response[2]);
continue;
} else
if (response[0] == 0x83 && response[3] * 2 == response_have - 3) {
unsigned short r0 = response[1]*256 + response[2];
for (unsigned char r = 0; r < response[3]; r++)
received_display_value(r0 + r, response[4 + 2*r]*256 + response[5 + 2*r]);
continue;
}
}
}
}
}
If you call the above in a loop (that does other stuff too, obviously, like checking your sensors, whether enough time has elapsed to store a new RPM sample, and so on), it will eventually call
received_display_registers() and/or
received_display_value().
received_display_registers() is called for the entire set of registers received, since they consecutive registers contain interesting values. We could expand that a bit, to handle registers 0x07-0x0A (touch position), 0x0C-0x0F (uptime), and so on.
For example, to detect user touches, it'd make sense to read registers 0x05-0x0A inclusive (six registers) whenever there is no pending command, and no pending response (
header_have == 0). Then, changing the end of the above to
Code:
} else {
response[response_have++] = byte;
if (--response_more < 1) {
header_have = 0;
response_pending = 0;
if (response_have < 2)
continue;
if (header[0] != DISPLAY_HEADER1 || header[1] != DISPLAY_HEADER2)
continue;
if (response[0] == 0x81 && response_have == 9 &&
response[1] == 5 && response[2] == 6 && response[3] == 0x5A) {
if (response[4] == 0x01) {
display_touch_press(response[5] + response[6]*256, response[7] + response[8]*256);
} else
if (response[4] == 0x03) {
display_touch_move(response[5] + response[6]*256, response[7] + response[8]*256);
} else
if (response[4] == 0x02) {
display_touch_release(response[5] + response[6]*256, response[7] + response[8]*256);
}
continue;
} else
if (response[0] == 0x81 && response[2] == response_have - 2) {
received_display_registers(response[1], response + 3, response[2]);
continue;
} else
if (response[0] == 0x83 && response[3] * 2 == response_have - 3) {
unsigned short r0 = response[1]*256 + response[2];
for (unsigned char r = 0; r < response[3]; r++)
received_display_value(r0 + r, response[4 + 2*r]*256 + response[5 + 2*r]);
continue;
}
}
}
}
}
would cause
display_touch_press(x, y) to be called whenever the user touches the display;
display_touch_move(x, y) if the user still touches the display, and
display_touch_release(x, y) when the user lifts their finger from the display -- assuming you send the 0xA5 0x5A 0x03 0x83 0x05 0x06 register request often enough (whenever
response_pending==0; set it to nonzero whenever you send a register or memory read that the display responds).
It would make a lot of sense to write the serial commands/responses into a library (with callback functions for touches and register updates), but without such a display to test, it's not fun to write code without being able to test or verify it.