FIGURE 1. Upon
power-up, nodeB sends
a status message telling
nodeA that it has
turned off the nodeB
LED. The CAN receive
code running on nodeA
adds the bottom
two lines of status
information to the
original menu display.
FIGURE 2. Looks
like nodeB doesn’t
have much to say.
However, this
simple message
says it all.
That puts nodeA at the advantage when both nodes
attempt to transmit at the same time. That’s nice to
know, but the CAN bus won’t be that busy in this simple
CAN application.
Initially, we’re only going to control and monitor the
status of the LED on nodeB via nodeA. So, we must also
define the LED control commands that will be embedded
within the CAN message:
#define led_off 0xA0
#define led_on 0xA1
We now have definitions for all of the elements that we
must include in our CAN messages. All that is left to do
is establish the byte ordering within a transmitted CAN
message. Here’s how our CAN messages will be formatted:
CAN ID = sending node’s CAN ID
data[0] = logical address of receiving CAN node
data[1] = LED command
from the viewpoint of nodeA. Interaction with nodeA is
done via nodeA’s 57600 bps RS-232 port and Tera Term
Pro. Tera Term Pro is a personal computer terminal
emulator that you can get as a free download on the
Internet. In fact, both of our CAN nodes are fitted with
57600 bps RS-232 ports. That allows us to use the same
RS-232 driver code on both nodeA and nodeB. The RS-232
driver firmware on both of our CAN nodes is interrupt-driven. Our application uses the C printf function, which
does not utilize the CAN node’s transmit interrupt handler
code. Thus, the interrupt activity on the pair of CAN nodes’
RS-232 ports is only invoked by RS-232 receive activity. To
check for an incoming RS-232 character, we simply call
the CharInQueue function. If there are any characters in
the CAN node’s RS-232 buffer, the CharInQueue function
will return a logical TRUE. Retrieving a character
from the RS-232 receive buffer is accomplished by this
simple line of code:
bytein = recvchar();
If we turn all of our definitions into code, we end up
with a transmission sequence that looks like this:
dataLen = 0;
id = myid;
data[0] = nodeB;
++dataLen;
data[1] = led_on;
++dataLen;
while(!ECANSendMessage(id, data, dataLen,
ECAN_TX_STD_FRAME));
The transmission sequence code I have presented here is
sending a message to nodeB telling it to turn its on-board
LED on. Note that the dataLen variable value is calculated as
we add data elements to the message.
The standardization of our CAN message transmissions also forms the foundation for our CAN message
receive parsing sequence. Our CAN receive message
firmware will always look for the logical CAN node address
in the data[0] position. If the receiving CAN node sees
that the incoming CAN node address is its own, it then
parses the data[1] memory slot for the LED command.
Nothing to it.
Application in a CAN
Let’s look at the nodeA and nodeB CAN applications
56 SERVO 09.2007
Both of our CAN nodes are also equipped with a
firmware-implemented real-time clock. The clock is fed
by the PIC’s Timer3 and is interrupt-driven. The real-time
clock is behind the 1 Hz flash rate of the nodeA LED.
The nodeB CAN node has the same real-time clock
capability. However, we want to control the LED on
nodeB exclusively. To gain total control of the nodeB
LED, we must disable the nodeB real-time clock timer
(Timer3) or simply comment out the LED toggle statement
in the Timer 3 interrupt handler. Just in case we
need millisecond timing windows, both of our CAN
nodes also run their Timer2 clocks on a one millisecond
interrupt interval.
The very first task that nodeA executes is to clear
the Tera Term Pro terminal window. Note that in the
code I have provided for you that we are using VT-100
commands to place our characters in the Tera Term Pro
terminal window. Using VT-100 screen formatting
commands makes easy work of putting together a nice
looking menu. To clear the Tera Term Pro window, we
simply place a call to the cls function, which consists of
this line of code:
printf(“%c[2J”,esc);
The %c is replaced by the escape character
(0x1B). The escape character is defined in the CAN node
source code.