AT30TS750A Tutorial: Alarms, Limits and Interrupts

Featured_Image-1-29

Reading temperature from the AT30TS750A is easy now, and so should be managing the configuration. It’s time to do something practical with our sensor and use it as a temperature alarm. Hang on to your hat, this one is going to be a in depth!

Objectives

  1. Understand the operation of the sensor when configured in comparator mode.
  2. Configure the fault tolerance and temperature limits to work as a temperature alarm.
  3. Understand how to use interrupts to capture and react to the AT30TS750A alarm.
  4. Use the shift register and LEDs to display the alarm status, as well as the serial monitor.
  5. Use buttons on the Education Shield as digital inputs.

Background
I2C Basics
AT30TS750A Functionality Overview
Retrieving Temperature Value
Atmel AT30TS750A Datasheet

Schematic
Education Shield – AT30TS750A Temperature Sensor Subsystem
Education Shield – Shift Register Subsystem

Setup
For this module, you’ll need the following equipment:

1. Place jumpers on the 74HC595 Enable block along the edge of the Education Shield. This will enable the microcontroller to read button presses.

2. Mate the Education Shield with your Arduino UNO R3. If you’re using the AT30TS750A Breakout Board and the Debounce Button Breakout Board, check the labels by the pins and for the AT30TS750A connect 5V to 5V, GND to GND, SC to Analog 5, SD to Analog 4 and AL to Digital2 and for the Debounce Button Board, connect 5V to 5V, GND to GND, and B1 to Digital8 and B2 to Digitl7.

3. Finally, connect your Arduino to your USB cable, and use the Arduino IDE to upload the “Bare Minimum” sketch from the Basics section of the Examples.


The AT30TS750A Alarm System

To be able to plan and build our temperature alarm, we need to understand the five aspects to the AT30TS750A alert system, configured in three locations, and how to respond to this with the interrupt system of the Arduino. First we’ll cover the sensor alert configurations.

If you haven’t already, or need a reminder, it would be helpful to read the AT30TS750A Functionality Overview module, so you have a solid understanding of the theory of the temperature limits, the interrupt and comparator modes and the fault tolerance settings.

The way in which these items are configured is critical to get right — in some cases, sending incomplete data will cause the sensor to completely abandon the configuration, leaving everything at default.

Alert Mode
The Alert Mode is specified in bit 9 of the Configuration Register 0x01. Specifying a 0 (the factory default) will enable comparator mode and specifying a 1 will enable interrupt mode. We are going to use comparator mode for our tests.

Fault Tolerance
The Fault Tolerance level is specified in bits 11-12 of the Configuration Register 0x01. The tolerance level can be set to the following levels…

ValueConfiguration
0x00Trigger alarm after 1 detection
0x01Trigger alarm after 2 detections
0x10Trigger alarm after 4 detections
0x11Trigger alarm after 6 detections

We will be using a fault tolerance of two in our tests.

Upper and Lower Temperature Limits
These are the limits the comparator will use to determine if the sensor should be in an alarm state or not. The Upper Limit Register, 0x03 and the Lower Limit Register 0x02, are both 16 bits wide, and you must write all 16 bits to the register otherwise the sensor will abandon the configuration and return to defaults.

Our code will sample the temperature at power up, and set the upper limit to “current temperature + 2°C” and set the lower limit to “current temperature + 1°C”. This will allow us to easily trigger and untrigger the alert system for testing.

Write a quick sketch to read the default temperature limits immediately after power up. (click here for a picture of the code)

Hover mouse to read values: The Upper Limit value is 80°C and the lower limit value is 75°C.

Interrupts

Interrupts are just that… things that interrupt the code flowing on your Arduino. Regardless of anything else your Arduino might be doing, if it detects the change you specify on either Digital3 (referred to as Interrupt0) or Digital4 (referred to as Interrupt1), it will immediately stop everything and execute the code you specify called an “interrupt service routine”, an ISR. It is crucial that the code in your ISR is very, very short — no more than a line or two — because while you’re in the ISR, nothing else can process… so just a blip of code, and don’t even think of doing any delaying or waiting in there!

For our purposes here, we are going to interrupt when there is a state change on the alarm pin of the AT30TS750A, which I connected to Digital3, Interrupt0, on the Education Shield. This will wind up creating a crude, but effective state machine.

State Machines are an incredibly complex topic in which you could easily lose yourself and create an entire career. More information can be read here: http://lamsonproject.org/docs/introduction_to_finite_state_machines.html

Temperature Alarm Design Goals

Let’s clearly define what we expect from our temperature sensor. It’s been very kind to us this far and it deserves that much forethought…

  1. We want the sensor to trigger the alert pin when the temperature rises above the Upper Limit value.
  2. We want the sensor to operate the alert system in comparator mode.
  3. We want the upper limit to be two degrees above the temperature at startup.
  4. We want the lower limit to be one degree above the temperature at startup.
  5. We want the fault tolerance to require two measurements in order to create the alert.
  6. We want the Education Shield LEDs to turn on in the event of an alarm and off when the alarm has passed.
  7. We want to measure the temperature when we press the DATA button.
  8. We want to issue a general call reset when we press the LATCH button.

With our goals in place, we can start to put together the framework for our code. We could do this using flow charts, but that’s getting a little too advanced. Let’s just write it out in pseudocode instead.

Step One: Definitions

This is pretty easy, because we’ve dealt with most of these already. The only new ones we need to add are limit registers, and to include definitions for the shift register pins.

One thing you’ll notice in there, is that I’ve defined digital8 and digital7 twice, once as getTempButton / resetButton and once as dataPin/latchPin. This does use up a little extra memory, but we’re not using a whole bunch in here. The reason I did this, is because those pins are going to be serving double duty. The majority of the time, 99.999% of the time, they’re going to be acting as inputs to either perform a temperature reading, or issue the general call reset. However, during the alarm state, we quickly need to take over control of those pins, and use them to control the shift register long enough to turn the LEDs on, then immediately turn control back over to the buttons. Using nicely descriptive variables when doing that will help to make the code more legible.

The only particularly unique statement in there is declaring the alarmState variable as “volatile”. Generally, this just means that we’re allowing every part of the code, even the special stuff that happens outside of the normal operation, like interrupts, to manipulate the value of the alarmState variable.

Let’s move to the next section.

Step Two: Building our Setup Functions

As before, we have a lot of this code already. We can just pull it from the other AT30TS750A sketches we’ve used so far. Here is the reused stuff, mixed with the pseudocode…

The first chunk of new code we’ll need is to set the limit registers, upper and lower. From our design goals, we know we want the upper limit set to two degrees above the temperature at startup and the lower set to one degree above the temperature at startup. We have to bare in mind, that the limit registers are 16 bits wide, so we have to supply the full value to them. So first we have to retrieve the current temperature, then add one to it, add to to it, and feed that back into the limit registers. Reading the temperature is nothing new, but the way we handle the limit registers is. Here is the code…

Down there at the bottom, are the two I2C statements that send the temperature value, with their respective additions, to the limit registers. However, we load the buffer with the Wire.write command three times: once to move the pointer to the correct register, once to send the most significant byte of temperature data, and finally once to pad the final 8 bits of the 16 bit register with zeros. If we don’t issue that second byte, the sensor will abandon the change. We could use the second byte to specify the limit values down to four decimal places, but that’s sort of overkill for our test here. Whatever the resolution level is that we set in the configuration register, that is the level to which the limit register will be compared.

This is what the command to set the lower limit looks like when viewed on the oscilloscope…

Setting the AT30TS750A Lower Temp Limit
Setting the AT30TS750A Lower Temp Limit

Now that we have the limits set, don’t forget to add setLimit(); to the setup section at the top of your code, we can focus on setting the fault tolerance limits. This is a little tricky, because we want to preserve the existing configuration and surgically change the value of the 11th and 12th bits. To accomplish this, we’ll use the technique of bit masking.

Just above the debug code, there is the statement OR it with the value 0x08. This effectively writes our fault tolerance value into the configuration, leaving the existing values outside the fault tolerance bits untouched.

Since the default values of the entire configuration register are 0, and all we change in our init routine is to up the resolution by setting the 13-14 bits to 11, we can view the change we’re making like this…

All you have to do is add setFaultTolerance(); to your setup and you can move on to interrupts!

Step Three: Interrupts

In order to successfully process an interrupt, we’ll need a couple of things.

  1. A function to call when we enter the alarm state
  2. A function to call when we exit the alarm state
  3. Some way of keeping track of our alarm state

For our alarm functions, we can keep it simple and just call them AlarmOn and AlarmOff. Remember, the functions called by the interrupt have to be very quick, so the only thing we’re going to do in there is set the value of a variable.

That variable is the way we’re going to keep track of the alarm state. This is the special “volatile” variable we created in the definitions called alarmState. It’s going to have three states: 0, 1 and 2.

  1. If we’re in alarm state 0 then we just entered the alarm state and we have to do something about it.
  2. If we’re in alarm state 1 then we just exited the alarm state and we have to do something about it.
  3. If we’re in alarm state 2 then we’ve processed either the entry or exit and we want our code to execute as usual.

You can see from the descriptions, that we should be spending the vast majority of our time in state 2. States 0 and 1 only come into play right when the interrupt has triggered or when it has released.

Ignoring all the other code in the sketch, we’ll isolate the interrupt code and describe it below…

The attachInterrupt commands are how we tell the Arduino that we’re going to be listening to digital3 for interrupts full time. In this case we’re defining an interrupt as either FALLING or RISING. That means I am causing my code to key off the transition from one state to another, rather than the state itself. If you told the code to interrupt processing when the state was LOW instead of FALLING, then it would constantly trigger over and over and over again. We just want this to edge trigger so it hits once.

Our ISRs are nice and tidy. One line each, setting the global alarm state and that’s all. Once the alarm state has been set, it will be evaluated back in the main loop() and action is taken on it. When the alarm state is 1, we Turn On Alarm Lights. When alarm state is 0, we Turn Off Alarm Lights.

Inside each of the Alarm Light functions, we change the interrupt to trigger on the opposite value of whatever sent us in there to begin with. We do that because once we’re in the alarm state (caused by a falling edge on interrupt0), we need to now be ready for a RISING edge on interrupt0 to let us know that we’ve exited the alarm state. In each instance, we set the alarm state to the nice, calm, 2 at the end, to let our regular code processing continue.

So, if the temperature rises above Upper Limit, interrupt0 will drop from 5V to GND (the alarm pin is open drain, so it’s default state is 5V, although that polarity can be changed in the configuration if you want to), triggering the FALLING state interrupt and launching AlarmOn, setting alarmState to 1. We reenter our loop and immediately process the IF statement evaluating alarmState, sending us to TurnOnAlarmLights. After taking action in there, we reset the alarmState to 2 and our code loops as usual, until the temperature drops below Lower Limit, in which case the RISING state of interrupt0 is detected, causing AlarmOff to be called, thus setting alarmState to 0 and causing us to turn our lights off and setup to listen for the interrupt triggering again on a FALLING edge.

Chances are, reading through the code makes more sense than my explanation 🙂

Step Four: Putting It All Together

The good news, considering how long this module has gotten, is that the remaining code is all reusable from previous modules: GeneralCallReset and GetTemperature are nothing new. So you can put it all together and get this…

After compiling and uploading the code, open up the serial monitor. You should see some debug output there, showing the values of the temperature limits and the new configuration value. Press DATA a couple of times and you should see the current temperature displayed. Now, take something hot, even as simple as rubbing your finger against your pants or the mousepad on your desk a couple of times to get the tip nice and warm and press it against the AT30TS750A on the Education Shield for a few seconds. If you can raise the temperature by two degrees that way you should see the LEDs pop on. Then, if you blow across the sensor gently to cool it off, the LEDs should turn off. There is corresponding debug code that appears in the serial monitor as well when both states execute.

The AT30TS750A packaging is very sturdy and robust, considering that it’s expecting to be either touched by a soldering iron or placed in a reflow oven. If you have trouble getting the chip to trigger or release the alarm, set the upper and lower limits 10 or 15 degrees higher, and use a hair dryer or something like that to create the sudden temperature increase