Wireless Embedded Internetworking Short Course

David E. Culler

University of California at Berkeley

Department of Electrical Engineering and Computer Science



Lab 4 – Inputs, Switches, Alerts




Simple circuits for binary inputs and outputs.


Sensor Networks tie together several distinct, but related worlds:

  • The physical world of space, things, mechanical actions, positions, forces, heat, motion, gravity, acceleration, light, chemical concentrations, magnetism, radio waves, and so on.
  • The analog world of electronics, with voltage, current, resistance, capacitance, and inductance.
  • The digital world of Boolean values (true and false), logic, bits, and numbers.
  • The information world where we give meaning to logical and numerical values, process and manipulate them, visualize information, draw conclusions, and elect to take actions.

We move between these worlds often in every day life; we flip switches and push buttons to turn on lights and gadgets, we read meters and say “its hot”, we turn dials to select particular radio stations, we track packages on the web, we run spreadsheets over all sorts of data, and so on.  There are literally thousands of different sensors are available for all sorts of different phenomena using all sorts of different sensing mechanisms and many different interfaces.  Here we will explore some extremely simple ones.


We begin with the simplest classes of devices – those that operate in the binary domain of On/Off, Yes/No, True/False, and Black/White – no shades of gray.  A huge class of interesting input and output devices fall into this class and are easily integrated into your embedded wireless web.


Probably the simplest “sensor” in every day life is the switch.    Physically, the switch is a mechanical device that has an orientation – up/down, in/out – that we think of an On/Off.  Electrically, it an analog device with two configurations – open and closed.  Viewed from a slightly different perspective, it is a position sensor that has infinite resistance (open circuit) in one position and zero resistance (closed circuit) in the other.  Indeed, many switches are used to detect the physical presence of an object that moves the switch – in addition to the more conventional uses of switches to turn electrical devices on and off.



Figure 1. Simple Circuit Converting an Analog Switch into a Binary Digital Signal


The translation from the analog switch (open/closed) to a digital value (true/false) is performed by a very simple circuit, shown in Figure 1.  In essence, this is a 1-bit analog-to-digital converter (ADC).  When the switch is open, the capacitor charges until it reaches the supply voltage, Vacc.  At this point, the voltage at D represents a logical 1 or TRUE value.  When the switch is closed it creates a path to ground allowing current to flow.  The low voltage at D represents a logical 0 or FALSE value. This digital input can be connected directly to a microcontroller through General Purpose IO (GIO) pin, where it can be processed and acted upon.  This simple circuit is also a low-pass filter that debounces the switch, so even if the opening and closing of the switch contacts is not perfect, the microcontroller sees a discrete change in the Boolean value. 


Although we translated the mechanical switch into a digital input, some analog aspects remain – especially power.  When the switch is closed, current flows and power is consumed.


Suppose that we want to run for 2 years on two AA alkaline batteries and we want the switch support circuitry to consume only 10% of that energy budget.

-         Find the energy capacity of the batteries in mAh (milliamp-hours)

-         Assuming the switch is essentially always closed, determine the allowable current for the switch.

-         Since you know the voltage of the battery and Ohm’s law, determine the size resistor that should be used for the pull-up.


For this R, diagram the rise and fall time of the input as a function of C.



Trip Sensors


We usually think of switches as the mechanical devices that control lights and appliances, but switch-based binary sensors are extremely common.  A few examples are illustrated in Figure 4.  Many irrigation equipment providers offer rain gauges that open when a configured water level is obtained.  Similar devices are used for tank levels, floats and the like. Mechanical vibration and tilt sensors open when a slight tilt causes an internal metal ball to roll off one of the contacts.  The magnetic reed contact sensors used widely in home and building security are magnetically controlled switches.  When the magnet attached to the window or door is adjacent to the sensor, the switch is closed; it opens when the magnets are separated.  Miniature magnet reed switches are often used on rotating shafts so that a pulse is generated whenever the magnet passes by; such techniques are used for tachometers, flow sensors, weather veins, and many other applications.  Pressure, water flow and current trip-sensors cause a circuit to be formed or broken when a certain threshold is obtained.

Figure 2 Example Switch-based Sensors



Your Epic interface board provides two such digital inputs with jumpers to enable the capacitor and pull up.  Locate the ports and pins for these inputs.  There are lots of the other inputs.  They can be connected directly to digital devices with a digital output, such as other MCUs, or they can be connected to analog devices with the appropriate matching circuit.




If we set a pin to input, how do we detect that it has changed state?

-         We could always set a timer and read it periodically, this is called polling.

-         Another option is to enable the hardware to detect the change and generate an interrupt.  


-         What are the advantages of waiting for an interrupt?

-         How would you poll an input and still allow the processor to sleep most of the time?


We’ve provided a very simple example driver in ButtonP.nc.  Open it up and take a look.  Both of our platforms have a User Interrupt button with the appropriate conditioning circuit attached to port 2 pin 7.  In fact the kernel uses this button for various user interface gestures.  Holding it down while reseting the mote will cause it to go into Associate mode.


For an interrupting input pin there is more work to do in the booted event.  The code for that event handler is reproduced here.  The entire sequence of pin configuration operations is placed in an atomic section.  To be absolutely sure we disable interrupts on this pin, clear any pending interrupts, configure the pin for input, and configure it so that the interrupt will occur on the falling edge.  (This latter aspect is somewhat unique to the MSP.  It requires that interrupts be associated with a particular edge.  Some MCUs permit the interrupt on either edge.)  Finally, we enable interrupts.


event void Boot.booted() {

    atomic {

      /*  Kernel configures pins as output IO function by default */

      P2IE  &= ~PIN7;        /* Disable interrupt cf. 9.2.5 of user guide*/

      P2IFG &= ~PIN7;        /* Clear interrupt flag */

      P2DIR &= ~PIN7;        /* Configure as input pin */

      P2IES |= PIN7;              /* Select Hi->Lo Transition */

      P2IE  |= PIN7;              /* Enable interrupts */




At this point, if the edge occurs, the hardware will generate an interrupt which will be cause control to be transferred asynchronously to the interrupt handler in the kernel.  We want to handle that interrupt.  The kernel provides HplSignal interfaces for just this purpose.  (TinyOS defines three layers of hardware abstraction.  The Hardware Presentation Layer [HPL] provides a thin veneer over the physical hardware, the Hardware Adaptation Layer [HAL] provides useful services in a possibly hardware specific form, the Hardware Independence Layer [HIL] utilizes these services to offer a hardware independent form.)  The HplSignal interface is very close to the raw hardware.


The hardware interrupt is dispatched directly to the signal handler on the port.  This code executes within the interrupt handler, so interrupts are disabled and it needs to do the absolute minimum amount of work, just like the lowest levels of drivers in any operating system.  Here, the TinyOS concurrency model make this much easier.  Notice that this handler is marked as an async event.  It can potentially preempt any of the higher level activity.  The compiler performs whole system concurrency analysis to eliminate race conditions and deadlocks.  


async event void HplSignalPort2.fired() {

    if ( P2IFG & PIN7 ) {    /* Button interrupt */

      P2IFG &= ~PIN7;        /* Clear interrupt flag */

      post fired();




This is a good example of what to do in the lowest levels.  It does just enough processing to know what occurred and to record enough information to handle the event, clears the interrupt and posts a task to finish the job outside the async context.  In this case, we verify that it our pin generated an interrupt, we clear it without changing the others, and post a button-specific task.  That task, shown below is atomic relative to all the other tasks in the system, so we don’t have to worry about preemption and the like.


task void fired() {

    signal Button.pressed(); /* Signal event to upper layers */



In this case, the task signals the application level event.  By transferring the interrupt to a task, the upper levels get timely notification of the salient event, but don’t have to write the kind of ultra-careful code that is appropriate for interrupt handlers.




  • Modify your application so that it supports trip sensors attached to the Digital IN terminals on your Epic Interface board.  What might you want to do with these events besides toggle LEDs and local output devices?
  • Integrate timing with sensing.  Can you determine when multiple events, say 4, happen with a certain time interface, say 2 seconds?  This might be the kind of thing you do to filter out spurious events.
  • Can you modify the driver and the interface to detect both edges of a binary input?




Note that when you are dealing with low level drivers you can write code that causes the entire OS to fail and won’t even be able to be remotely upgradable. If you are really unlucky, you can get it so that it re-enters this state when you reset or power cycle the node.  To get out of this state, you can physically reprogram your nodes over the USB.