|
Before we release our code we have to anticipate all possible
sources of error. GUI code may fail miserably leading to nuisance, embedded
code may fail miserably leading to unimaginable losses. Yes, I want to
terrify you cause we usually think we have finished by the time we see
something working. We should constantly strive towards better code. By
the way, I remain open to any suggestions / corrections. OK, let's try to
identify possible errors.
- First of all, when we send a Reset signal, it is not for
sure that our thermo will be present. Our thermo might be dead.
- Also, after sending a command to our thermo there is a
possibility that we will never get a reply. Think of adding timeouts.
- But again, even if we get a temperature measurement, it
might be erroneous. The CRC stands there for this purpose.
- Finally, our code may fail without glory, unexpectedly.
Micros do fail. Yes, a nasty thing thus, we use the Watchdog timer.
What we are going to do is introduce error codes. In case
one of them appears we can display it, say "E2" for example.
At least, when your customers call you with maddening claims, telling
you there is an "E2" coming out instead of temperature, you
will know which routine has failed you. So ...
/// Globals ///////////
static volatile u8 error=0;
static u8 RAM[9];
/// Prototypes ////////
u8 GetT(u8 *data);
int main(void)
{
//{...}
error = GetT(RAM);
if (!error) DispTemp(temp);
else DispErr(error);
//{...}
}
The final code may not be exactly as the above but, you
see what I mean, the GetT routine has to return the error code. If it
is 0, there is no problem, we can display temperature, else, we display
the error code. Temperature has to be set by the routine somehow so, you
may use pointers or declare it global. Start writing the final GetT routine!
Before getting your hands dirty, look at the following trick which
is common for embedded systems. Usually microcontrollers have to poll
external devices, waiting for an event to occur. In our case we have to wait for
temperature conversion. The common practice here is to utilize either a timer or
a variable, which by expiring will indicate failure. See the following example
and you will get the idea.
// Convert Temperature
wTxbyte(convertT);
// Read a byte - Initialize timeout variable
convflag=wRxbyte(); timeout=0;
// Poll for convertion complete or timeout
while (!convflag && timeout<200)
{
Delay(1000);
convflag=wRxbyte(); // Read a byte
timeout++;
}
// if (!convflag) convertT timed out
// else convertT is OK
We start by requesting temperature conversion, then
instead of delaying we read a byte. As you expect, this is too fast for
our thermo which will return 0. We initialize the timeout variable and
we enter the loop. We will get out of the loop when one out of the two
conditions is met. Either the thermo will respond or timeout will occur.
In the loop, we keep polling the thermo patiently but, we advance our
timeout variable. After the end of the loop, we check what we've got.
Please, do the same for the skipROM command. I am not sure what it returns
or how quickly the thermo responds. By the way, think if the Delay is
needed or not. If conversion is completed as expected what is the value
of timeout?
Now, regarding the Reset signal, we have to be sure that our
thermometer will respond. It is straight forward.
// Reset Signal
temp = Reset1Wire();
// if (!Reset1Wire()) then no thermo is present
// else there is one
Nice, we have increased our code's reliability, I
would be glad if you could rewrite your GetT routine to return an error
code, 0 for none and set the global temperature variable. The latter should
be passed by reference so use pointers. Beware with its declaration. The
last think you should notice is that if a thermo is not present, it will
never do temperature conversion, but your error code may be altered. So,
do it in steps and after each step if there is an error return.
|