Posts with «bioengineering» label

Fifth day of freshman design seminar

Today we continued the design exercise I started last week (see also 4th class) designing a photospectrometer.

I started the class by collecting the work I had asked them to do on fleshing out the design of the photospectrometer, which I have not read yet.  Just glancing at the pile, it looks like most wrote very little, and just drew a picture of the components we talked about in class, not adding much. I’ll know more about the class once I’ve had a chance to look at what they did more carefully.  I have asked them to mail their work to the class e-mail list by tomorrow night, so that the rest of the class can see what everyone has done.

I then told them that we’d do some electronics and computer programming, since many of them had requested that on the first-day survey, and that we’d use Arduino boards to do that learning.  I suggested that they get Arduino Uno Rev 3 boards as being the current standard (about $30), but told them that almost any Arduino board that used an ATMega processor would be fine—the older boards, like a Uno that is not Rev 3, are often half the price.  They can probably get the boards from the University through BELS (the lab support group for the engineering labs), but it might be cheaper on line.

I then asked them for some details that they had added to the photospectrometer design.  The first one to come up was the photodetector, so we started talking about different photodetectors. They came up with photodiode, photomultiplier, and photocell, to which I added phototransistor and photoresistor.  I asked them what sort of characteristics might be important to a photodetector, and (with some prompting) got them to come up with the ideas of sensitivity and which wavelengths the detector was sensitive to.

One student came up with “resolution” for the sensor, and I took that as an opportunity for a digression into the differences between accuracy, precision, and resolution.  I also talked about resolution being a property of the whole system (how many digits were in the numbers), but that there was a property of sensors that was related—how much noise they had. Sometime later in the class (I forget exactly when), I talked about Arduinos having a 10-bit analog-to-digital converter, and asked them to guess what that meant.  The only guess was that it meant that there were 10 different levels.  I was actually fairly pleased with this answer, as it got to the notion of resolution, and I could correct it from 10 to 210 without making anyone feel stupid. I told them that they should remember 210=1024, as that was a frequently used “magic” number in computers.

I quickly sketched rough sensitivity plots for phototransistors/photodiodes and photoresistors, and explained that that was why photoresistors were used as ambient light sensors—because of how they matched human visual sensitivity.  I also mentioned the slowness of photoresistors and said that they weren’t used for much for other applications.

I told them how to find datasheets—either by Googling “photodiode data sheet” or by doing a search on Digi-key, choosing the cheapest part that seemed to do what they want, and looking up its data sheet.  I assigned them the task of finding and trying to read a photodiode and a phototransistor data sheet.  I’ll make that more explicit on the class web page later tonight.  I’ll probably give them a part number for one, and make them look for the other from just a description.

I showed them the schematic symbol for a phototransistor (though, unfortunately, not for a photodiode), but I didn’t attempt to explain how it works.  I just told them that the current through the phototransistor was proportional to the light intensity as long as voltage across the transistor was at least 0.7v.  (I’ll have to tell them where to find that information on the data sheet.)  I also mentioned the notion of “dark current”, which prevents the phototransistor from getting down to 0 current.

I then tried to get them to figure out how to convert the current into a voltage that could be measured by the Arduino.  After a few tries, one of them finally remembered Ohm’s Law (V=IR), and they decided they needed a resistance.  I told them that there were fairly constant resistance devices available (called “resistors”) and mentioned the notions of resistor tolerance and that resistors had thermal coefficients, so that the resistance changed as a function of temperature.

I then gave them the phototransistor circuit below (though not the photodiode circuit):

Simple circuits for measuring light with an Arduino. Update 2014 Feb 6: Q1 is intended to be an NPN phototransistor, not PNP as shown here!

We then spent a fairly long time before they figured out that they needed to know what value resistor to use in the circuit. I got them (eventually) to the point where they realized that the maximum light intensity determined the maximum current, and if we set the maximum voltage to be as high as possible while keeping the transistor properly biased, the desired resistor was determined by R=Vmax/Imax. I showed them how increasing the value of R made the circuit more sensitive, but that if we made R too big the circuit would not be able to handle high light intensity.

We then looked at the overall spectrometer design, and saw how the optics coupled everything together: the brightness of the light, the absorbance of the sample, the efficiency of the monochromator, and the sensitivity of the photodetector. I introduced the notion of interface specifications, so that design problems could be divided up among a team, and the need for negotiating changes to the interface specs rather than just “throwing problems over the fence” for some other part of the team to solve. I gave the example of the lamp designer finding out that the initial spec called for an expensive, bright light (like and HID bulb) but being able to reduce the cost and power enormously with a somewhat less bright LED. The change to the spec might be accommodated by shortening the optical path in the sample (but that would need non-standard cuvettes) or by making the light sensor more sensitive (which is pretty cheap to do).

We ran out of time then, so did not get to looking at any other parts of the design.

Some of the students were amazed at how much thinking went into just one little detail of the design (one resistor value). They are used to big-picture, fuzzy thinking, where getting the general idea is what is important, and are not used to sweating the details. Part of getting them to “think like engineers” is getting them to realize that the details do matter.

For homework, I’ll ask them to figure out good values for R1 and R2 for particular parts (or maybe for one part that I specify and one that they choose), based on the data sheets and some light spec. In class on Monday, I’ll build the design they specified, and we’ll test it with the Arduino data logger.  If I happen to pick a bad resistor choice, either because I gave them a bad light intensity to design for or because their math was wrong, we’ll get bad results, and I’ll show them how to debug the design and iteratively improve it.


Filed under: freshman design seminar Tagged: Arduino, bioengineering, engineering education, photodiode, phototransistor, spectrometer, spectrophotometer, spectroscope

Fifth day of freshman design seminar

Today we continued the design exercise I started last week (see also 4th class) designing a photospectrometer.

I started the class by collecting the work I had asked them to do on fleshing out the design of the photospectrometer, which I have not read yet.  Just glancing at the pile, it looks like most wrote very little, and just drew a picture of the components we talked about in class, not adding much. I’ll know more about the class once I’ve had a chance to look at what they did more carefully.  I have asked them to mail their work to the class e-mail list by tomorrow night, so that the rest of the class can see what everyone has done.

I then told them that we’d do some electronics and computer programming, since many of them had requested that on the first-day survey, and that we’d use Arduino boards to do that learning.  I suggested that they get Arduino Uno Rev 3 boards as being the current standard (about $30), but told them that almost any Arduino board that used an ATMega processor would be fine—the older boards, like a Uno that is not Rev 3, are often half the price.  They can probably get the boards from the University through BELS (the lab support group for the engineering labs), but it might be cheaper on line.

I then asked them for some details that they had added to the photospectrometer design.  The first one to come up was the photodetector, so we started talking about different photodetectors. They came up with photodiode, photomultiplier, and photocell, to which I added phototransistor and photoresistor.  I asked them what sort of characteristics might be important to a photodetector, and (with some prompting) got them to come up with the ideas of sensitivity and which wavelengths the detector was sensitive to.

One student came up with “resolution” for the sensor, and I took that as an opportunity for a digression into the differences between accuracy, precision, and resolution.  I also talked about resolution being a property of the whole system (how many digits were in the numbers), but that there was a property of sensors that was related—how much noise they had. Sometime later in the class (I forget exactly when), I talked about Arduinos having a 10-bit analog-to-digital converter, and asked them to guess what that meant.  The only guess was that it meant that there were 10 different levels.  I was actually fairly pleased with this answer, as it got to the notion of resolution, and I could correct it from 10 to 210 without making anyone feel stupid. I told them that they should remember 210=1024, as that was a frequently used “magic” number in computers.

I quickly sketched rough sensitivity plots for phototransistors/photodiodes and photoresistors, and explained that that was why photoresistors were used as ambient light sensors—because of how they matched human visual sensitivity.  I also mentioned the slowness of photoresistors and said that they weren’t used for much for other applications.

I told them how to find datasheets—either by Googling “photodiode data sheet” or by doing a search on Digi-key, choosing the cheapest part that seemed to do what they want, and looking up its data sheet.  I assigned them the task of finding and trying to read a photodiode and a phototransistor data sheet.  I’ll make that more explicit on the class web page later tonight.  I’ll probably give them a part number for one, and make them look for the other from just a description.

I showed them the schematic symbol for a phototransistor (though, unfortunately, not for a photodiode), but I didn’t attempt to explain how it works.  I just told them that the current through the phototransistor was proportional to the light intensity as long as voltage across the transistor was at least 0.7v.  (I’ll have to tell them where to find that information on the data sheet.)  I also mentioned the notion of “dark current”, which prevents the phototransistor from getting down to 0 current.

I then tried to get them to figure out how to convert the current into a voltage that could be measured by the Arduino.  After a few tries, one of them finally remembered Ohm’s Law (V=IR), and they decided they needed a resistance.  I told them that there were fairly constant resistance devices available (called “resistors”) and mentioned the notions of resistor tolerance and that resistors had thermal coefficients, so that the resistance changed as a function of temperature.

I then gave them the phototransistor circuit below (though not the photodiode circuit):

Simple circuits for measuring light with an Arduino. Update 2014 Feb 6: Q1 is intended to be an NPN phototransistor, not PNP as shown here!

We then spent a fairly long time before they figured out that they needed to know what value resistor to use in the circuit. I got them (eventually) to the point where they realized that the maximum light intensity determined the maximum current, and if we set the maximum voltage to be as high as possible while keeping the transistor properly biased, the desired resistor was determined by R=Vmax/Imax. I showed them how increasing the value of R made the circuit more sensitive, but that if we made R too big the circuit would not be able to handle high light intensity.

We then looked at the overall spectrometer design, and saw how the optics coupled everything together: the brightness of the light, the absorbance of the sample, the efficiency of the monochromator, and the sensitivity of the photodetector. I introduced the notion of interface specifications, so that design problems could be divided up among a team, and the need for negotiating changes to the interface specs rather than just “throwing problems over the fence” for some other part of the team to solve. I gave the example of the lamp designer finding out that the initial spec called for an expensive, bright light (like and HID bulb) but being able to reduce the cost and power enormously with a somewhat less bright LED. The change to the spec might be accommodated by shortening the optical path in the sample (but that would need non-standard cuvettes) or by making the light sensor more sensitive (which is pretty cheap to do).

We ran out of time then, so did not get to looking at any other parts of the design.

Some of the students were amazed at how much thinking went into just one little detail of the design (one resistor value). They are used to big-picture, fuzzy thinking, where getting the general idea is what is important, and are not used to sweating the details. Part of getting them to “think like engineers” is getting them to realize that the details do matter.

For homework, I’ll ask them to figure out good values for R1 and R2 for particular parts (or maybe for one part that I specify and one that they choose), based on the data sheets and some light spec. In class on Monday, I’ll build the design they specified, and we’ll test it with the Arduino data logger.  If I happen to pick a bad resistor choice, either because I gave them a bad light intensity to design for or because their math was wrong, we’ll get bad results, and I’ll show them how to debug the design and iteratively improve it.


Filed under: freshman design seminar Tagged: Arduino, bioengineering, engineering education, photodiode, phototransistor, spectrometer, spectrophotometer, spectroscope

Using KL25Z for measuring salinity

Continuing the series of posts on measuring salinity with a couple of resistors and microprocessor

  1. Towards automatic measurement of conductivity of saline solution describes another possible freshman design project: a conductivity meter using the KL25Z board.
  2. More on automatic measurement of conductivity of saline solution looks at waveforms for square waves generated using PWM on the KL25Z board.  In this post I found that 100kHz square waves would work well.
  3. Still more on automatic measurement of conductivity of saline solution looks at waveforms for bursts of square waves generated by an Arduino board.  The bursts are limited to about 4kHz, but that may be good enough for a conductivity meter.

Today I started over on using the KL25Z board.  Since I wasn’t interested in precise frequencies, I didn’t use the PWM output this time, but used the same trick I used on the Arduino board: flipping the output bit, reading a sample, and repeating in a burst.

I record the sum of the differences between the high and low readings, and report the average at the end of each burst.  By using 40,000 cycles of warmup in each burst (discarded), then averaging over the next 10,000 cycles, I get a voltage reading that has a standard deviation of about 0.1mV on a reading of 2.843V, which is about 14–15 bits of accuracy.  The voltage reading is not constant, though, but drifts downward.

(click to embiggen) Voltage difference at undriven electrode as a function of time. The two sudden steps were probably the result of my jostling the table by putting down my teacup too hard.

I don’t have an explanation of the gradual drift in the voltage. I don’t think that this is a change in the salinity of the solution (which should be unchanged or increasing slowly due to evaporation). but a change in the characteristics of the electrodes. More likely, it is a change in the characteristics of the electrodes.  The sudden shifts when the table was jostled may be due to electrodes shifting their position in the cup or the release of a bubble.  Releasing a bubble should increase the surface area of the electrode and hence increase the conductivity and the voltage difference at the undriven electrode.  The gradual downward shift could be due to building up tiny hydrogen bubbles (too small to see) on the negative electrode.  The changes in voltage observed here are less than 0.1%, which is fairly respectable for a homebrew instrument.

Here is the (undocumented, throw-away) code that I wrote today to test out the ideas of an automatic salinity measurement system using a KL25Z:

#include "mbed.h"

DigitalInOut square_out(PTB0);   // PTB0=arduino A0
//PTB0, PTB1, PTD6, and PTD7 I/O have both high drive and normal drive capability selected by the associated PTx_PCRn[DSE] control bit.

AnalogIn IN(PTB1);  // PTB1=Arduino A1

Serial USB_io(USBTX, USBRX);  // defaults to 9600 8N1 (reset in main to 115200 baud)
Timer since_start;

#define WARMUP (40000)    // number of cycles of toggling output before collecting data
#define COLLECT (10000)   // number of cycles of data to sum for each output
#define Vdd (3.3)      // High voltage at output
int main()
{
    USB_io.baud(115200);
    USB_io.printf("\nusec\tvolts\nN\tN\n");

    //DEFAULT configuration of analog input
    ADC0->CFG1 = ADC_CFG1_ADLPC_MASK    // Low-Power Configuration
               | ADC_CFG1_ADIV(3)       // Clock Divide Select: (Input Clock)/8
               | ADC_CFG1_ADLSMP_MASK   // Long Sample Time
               | ADC_CFG1_MODE(3)       // (16)bits Resolution
               | ADC_CFG1_ADICLK(1);    // Input Clock: (Bus Clock)/2

    ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK   // ADxxb channels are selected
               | ADC_CFG2_ADACKEN_MASK  // Asynchronous Clock Output Enable
               | ADC_CFG2_ADHSC_MASK    // High-Speed Configuration
               | ADC_CFG2_ADLSTS(0);    // Long Sample Time Select

    ADC0->SC2 = ADC_SC2_REFSEL(0);      // Default Voltage Reference

    ADC0->SC3 = ADC_SC3_AVGE_MASK       // Hardware Average Enable
                | ADC_SC3_AVGS(0);        // 4 Samples Averaged

    // FAST analog input
    ADC0->CFG1 =
                ADC_CFG1_MODE(3)       // (16)bits Resolution
               | ADC_CFG1_ADLSMP_MASK   // Long Sample Time
               | ADC_CFG1_ADICLK(0);    // Input Clock: (Bus Clock)

    ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK   // ADxxb channels are selected
               | ADC_CFG2_ADACKEN_MASK  // Asynchronous Clock Output Enable
               | ADC_CFG2_ADHSC_MASK    // High-Speed Configuration
               | ADC_CFG2_ADLSTS(0);    // longest "long" Sample Time Select

//             | ADC_CFG2_ADLSTS(3);    // shortest "long" Sample Time Select

    ADC0->SC2 = ADC_SC2_REFSEL(0);      // Default Voltage Reference
    ADC0->SC3 = 0;        // No hardware averaging

    // set PORTB pin 0 to high drive here
    PORTB->PCR[0]  |= PORT_PCR_DSE_MASK;

    since_start.start();
    while(1)
    {
         square_out.output();
         for (int i=0; i
         {
             square_out=1;
             wait_us(1);
             volatile uint16_t rise_read=IN.read_u16();
             square_out=0;
             wait_us(1);
             volatile uint16_t fall_read=IN.read_u16();
        }
        int32_t sum=0;
        for (int i=0;i<COLLECT; i++)
        {
             square_out=1;
             wait_us(1);
             int32_t rise_read=IN.read_u16();
             square_out=0;
             wait_us(1);
             sum += rise_read - IN.read_u16();
        }
        square_out.input(); // hiZ state when not driving pulses

        USB_io.printf("%10d\t%7.5f\n", since_start.read_us(), sum*(Vdd/COLLECT/(1<<16))); // scale output to volts
    }
 }

There is still a lot that needs to be done to make this a finished project, but I’ve convinced myself that it is doable as freshman design project, which is all I really needed to do.


Filed under: Circuits course, freshman design seminar Tagged: Arduino, bioengineering, circuits, conductivity, electrodes, KL25Z

Using KL25Z for measuring salinity

Continuing the series of posts on measuring salinity with a couple of resistors and microprocessor

  1. Towards automatic measurement of conductivity of saline solution describes another possible freshman design project: a conductivity meter using the KL25Z board.
  2. More on automatic measurement of conductivity of saline solution looks at waveforms for square waves generated using PWM on the KL25Z board.  In this post I found that 100kHz square waves would work well.
  3. Still more on automatic measurement of conductivity of saline solution looks at waveforms for bursts of square waves generated by an Arduino board.  The bursts are limited to about 4kHz, but that may be good enough for a conductivity meter.

Today I started over on using the KL25Z board.  Since I wasn’t interested in precise frequencies, I didn’t use the PWM output this time, but used the same trick I used on the Arduino board: flipping the output bit, reading a sample, and repeating in a burst.

I record the sum of the differences between the high and low readings, and report the average at the end of each burst.  By using 40,000 cycles of warmup in each burst (discarded), then averaging over the next 10,000 cycles, I get a voltage reading that has a standard deviation of about 0.1mV on a reading of 2.843V, which is about 14–15 bits of accuracy.  The voltage reading is not constant, though, but drifts downward.

(click to embiggen) Voltage difference at undriven electrode as a function of time. The two sudden steps were probably the result of my jostling the table by putting down my teacup too hard.

I don’t have an explanation of the gradual drift in the voltage. I don’t think that this is a change in the salinity of the solution (which should be unchanged or increasing slowly due to evaporation). but a change in the characteristics of the electrodes. More likely, it is a change in the characteristics of the electrodes.  The sudden shifts when the table was jostled may be due to electrodes shifting their position in the cup or the release of a bubble.  Releasing a bubble should increase the surface area of the electrode and hence increase the conductivity and the voltage difference at the undriven electrode.  The gradual downward shift could be due to building up tiny hydrogen bubbles (too small to see) on the negative electrode.  The changes in voltage observed here are less than 0.1%, which is fairly respectable for a homebrew instrument.

Here is the (undocumented, throw-away) code that I wrote today to test out the ideas of an automatic salinity measurement system using a KL25Z:

#include "mbed.h"

DigitalInOut square_out(PTB0);   // PTB0=arduino A0
//PTB0, PTB1, PTD6, and PTD7 I/O have both high drive and normal drive capability selected by the associated PTx_PCRn[DSE] control bit.

AnalogIn IN(PTB1);  // PTB1=Arduino A1

Serial USB_io(USBTX, USBRX);  // defaults to 9600 8N1 (reset in main to 115200 baud)
Timer since_start;

#define WARMUP (40000)    // number of cycles of toggling output before collecting data
#define COLLECT (10000)   // number of cycles of data to sum for each output
#define Vdd (3.3)      // High voltage at output
int main()
{
    USB_io.baud(115200);
    USB_io.printf("\nusec\tvolts\nN\tN\n");

    //DEFAULT configuration of analog input
    ADC0->CFG1 = ADC_CFG1_ADLPC_MASK    // Low-Power Configuration
               | ADC_CFG1_ADIV(3)       // Clock Divide Select: (Input Clock)/8
               | ADC_CFG1_ADLSMP_MASK   // Long Sample Time
               | ADC_CFG1_MODE(3)       // (16)bits Resolution
               | ADC_CFG1_ADICLK(1);    // Input Clock: (Bus Clock)/2

    ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK   // ADxxb channels are selected
               | ADC_CFG2_ADACKEN_MASK  // Asynchronous Clock Output Enable
               | ADC_CFG2_ADHSC_MASK    // High-Speed Configuration
               | ADC_CFG2_ADLSTS(0);    // Long Sample Time Select

    ADC0->SC2 = ADC_SC2_REFSEL(0);      // Default Voltage Reference

    ADC0->SC3 = ADC_SC3_AVGE_MASK       // Hardware Average Enable
                | ADC_SC3_AVGS(0);        // 4 Samples Averaged

    // FAST analog input
    ADC0->CFG1 =
                ADC_CFG1_MODE(3)       // (16)bits Resolution
               | ADC_CFG1_ADLSMP_MASK   // Long Sample Time
               | ADC_CFG1_ADICLK(0);    // Input Clock: (Bus Clock)

    ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK   // ADxxb channels are selected
               | ADC_CFG2_ADACKEN_MASK  // Asynchronous Clock Output Enable
               | ADC_CFG2_ADHSC_MASK    // High-Speed Configuration
               | ADC_CFG2_ADLSTS(0);    // longest "long" Sample Time Select

//             | ADC_CFG2_ADLSTS(3);    // shortest "long" Sample Time Select

    ADC0->SC2 = ADC_SC2_REFSEL(0);      // Default Voltage Reference
    ADC0->SC3 = 0;        // No hardware averaging

    // set PORTB pin 0 to high drive here
    PORTB->PCR[0]  |= PORT_PCR_DSE_MASK;

    since_start.start();
    while(1)
    {
         square_out.output();
         for (int i=0; i
         {
             square_out=1;
             wait_us(1);
             volatile uint16_t rise_read=IN.read_u16();
             square_out=0;
             wait_us(1);
             volatile uint16_t fall_read=IN.read_u16();
        }
        int32_t sum=0;
        for (int i=0;i<COLLECT; i++)
        {
             square_out=1;
             wait_us(1);
             int32_t rise_read=IN.read_u16();
             square_out=0;
             wait_us(1);
             sum += rise_read - IN.read_u16();
        }
        square_out.input(); // hiZ state when not driving pulses

        USB_io.printf("%10d\t%7.5f\n", since_start.read_us(), sum*(Vdd/COLLECT/(1<<16))); // scale output to volts
    }
 }

There is still a lot that needs to be done to make this a finished project, but I’ve convinced myself that it is doable as freshman design project, which is all I really needed to do.


Filed under: Circuits course, freshman design seminar Tagged: Arduino, bioengineering, circuits, conductivity, electrodes, KL25Z

Still more on automatic measurement of conductivity of saline solution

In More on automatic measurement of conductivity of saline solution, I suggested using a simple voltage divider and a microcontroller to make conductivity measurements with polarizable electrodes:

Simplified circuit for conductivity tester.

I found that putting in a 100kHz square wave worked well:

At 100kHz, both the voltage waveforms (input and output) look like pretty good square waves.

I have not yet figured out a good way on the KL25Z to provide the 100kHz signal, sample the outputs at fixed points, and communicate the result out the USB port.  Using PWM for the output was handy for just generating the output (once I fixed mbed’s off-by-one bug in their pwmout_api.c file), but that makes connecting up the analog reads more difficult.  I think that I may be better off not using PWM, but using a timer interrupt to read the analog value, change the output, and do the subtraction.  It would be fairly easy to arrange that (though I’ll probably have to figure out all the registers for the sample-and-hold and the analog-to-digital converter, as the mbed AnalogIn routine is unlikely to have the settings I want to use).   The hard part remains the interface to the host computer, as mbed does not include a simple serial interface and serial monitor like the Arduino IDE. [Correction 2013 Dec 25: my son points out that the mbed development kit has a perfectly usable serial USB interface—I had overlooked the inheritance from "Stream", which has all the functions I thought were missing. I should be able to use the Arduino serial monitor with the Freedom KL25Z board, as long as the serial interface is set up right.]

Because I’m more familiar with the Arduino environment, and because I already have Arduino Data Logger code for the host end of the interface, I started by making a simple loop that toggles the output and reads the value after each change in output.  After repeating this several times (40 or 100), I take the last difference as the output and report that to the data logger.  I couldn’t get the frequency up where I really want it (100kHz), because the Arduino analog-to-digital converter is slow, but I was able to run at about 4kHz, which would be adequate.

Because there needs to be time for the serial communication, I did bursts of pulses with pauses between bursts.  The bursts were alternating as fast as the analog inputs were read for a fixed number of cycles, and the start of the bursts was controlled by the Arduino data logger software. Although the ends of the bursts looked the same on the oscilloscope, with the same peak-to-peak voltage, I got different readings from the Arduino depending on the spacing between the bursts. I’m not sure what is causing the discrepancy.

A difference at the beginnings of the bursts I would understand as the space between the bursts put a DC voltage across the electrodes which gradually charged them up, so that the first few pulses actually end up going outside the range of the ADC:

The bottom of the grid is 0v, and the first pulse goes up to 5.442v. The pulses are at about 4kHz, but the bursts start 50msec apart.

The differences at the ends of the bursts as I change the spacing between bursts are probably also due to the charging, though I don’t see that clearly on the oscilloscope. I really don’t like the idea of having a DC bias across the electrodes, as we get electrolysis, with hydrogen bubbles forming on the more negative electrode. No oxygen bubbles form, probably because any oxygen released is reacting with the stainless steel to form metal oxides. If I increase the voltage and current, I get a lot of hydrogen bubbles on the negative electrode, some rusty looking precipitate coming off the positive electrode (probably an iron oxide), and a white coating building up on the positive electrode (probably a chromium oxide).

By putting a 4.7µF capacitor between the Arduino output and the electrode, I can reduce DC bias on the electrodes and get a more consistent signal from the Arduino, almost independent of the spacing between the bursts:

By using a 25msec spacing between the beginnings of bursts, I can get both the end of the burst and the beginning of the burst on the oscilloscope at once.
Using a 4.7µF capacitor between the square wave output and the electrodes results in sharp peaks across the resistor, but a more consistent reading from the Arduino ADC.

The voltage across the electrodes still does not average to 0v, as the pair of resistors provides a bias voltage halfway between the rails, but the pulse does not really swing rail to rail, but from 0.28v to 4.28v.  I think that the low-pass filter for setting the bias voltage that I suggested in More on automatic measurement of conductivity of saline solution may be a good idea after all, to make sure that there is no residual DC bias.

I can use the differential inputs of the Bitscope DP01 to look at the voltage across the electrodes and across the resistor to get voltage and current traces for the electrodes:

The central horizontal line is 0V for both traces here. The green trace is the voltage at the undriven electrode (@ 2v/division) and so corresponds to the current, and the yellow trace is the voltage between the electrodes (@0.2v/division).

Note that the voltage on the undriven electrode does run a little below 0V, outside the range of the Arduino ADC.  The voltage ratio of 0.248v/4.16v, together with the 100Ω Thévenin equivalent resistance results in a 5.47Ω resistance between the electrodes.  (Note: this is no longer a 1M NaCl solution—there has been evaporation, plus contamination from iron oxides, and the electrodes are not covered to the depth defined by the plastic spacer.)

I don’t know whether the conductivity meter is a good project for the freshman design seminar or not—I don’t expect the students to have the circuit skills or the programming skills to be able to do a design like this without a lot of coaching.  Even figuring out that they need to eliminate DC bias to eliminate electrolysis may be too much for them, though I do expect all to have had at least high-school chemistry. It is probably worth doing a demo of putting a large current through electrodes in salt solution, to show both the hydrogen bubbles and the formation of the oxides.  I could probably coach freshmen through the design, if they were interested in doing it, so I’ll leave it on the feasible list.

The square-wave analysis is not really suitable for a circuits course, so I think I’ll stick with sine-wave excitation for that course.


Filed under: Circuits course, freshman design seminar Tagged: Arduino, bioengineering, circuits, conductivity, electrodes, KL25Z, voltage divider

Still more on automatic measurement of conductivity of saline solution

In More on automatic measurement of conductivity of saline solution, I suggested using a simple voltage divider and a microcontroller to make conductivity measurements with polarizable electrodes:

Simplified circuit for conductivity tester.

I found that putting in a 100kHz square wave worked well:

At 100kHz, both the voltage waveforms (input and output) look like pretty good square waves.

I have not yet figured out a good way on the KL25Z to provide the 100kHz signal, sample the outputs at fixed points, and communicate the result out the USB port.  Using PWM for the output was handy for just generating the output (once I fixed mbed’s off-by-one bug in their pwmout_api.c file), but that makes connecting up the analog reads more difficult.  I think that I may be better off not using PWM, but using a timer interrupt to read the analog value, change the output, and do the subtraction.  It would be fairly easy to arrange that (though I’ll probably have to figure out all the registers for the sample-and-hold and the analog-to-digital converter, as the mbed AnalogIn routine is unlikely to have the settings I want to use).   The hard part remains the interface to the host computer, as mbed does not include a simple serial interface and serial monitor like the Arduino IDE. [Correction 2013 Dec 25: my son points out that the mbed development kit has a perfectly usable serial USB interface—I had overlooked the inheritance from "Stream", which has all the functions I thought were missing. I should be able to use the Arduino serial monitor with the Freedom KL25Z board, as long as the serial interface is set up right.]

Because I’m more familiar with the Arduino environment, and because I already have Arduino Data Logger code for the host end of the interface, I started by making a simple loop that toggles the output and reads the value after each change in output.  After repeating this several times (40 or 100), I take the last difference as the output and report that to the data logger.  I couldn’t get the frequency up where I really want it (100kHz), because the Arduino analog-to-digital converter is slow, but I was able to run at about 4kHz, which would be adequate.

Because there needs to be time for the serial communication, I did bursts of pulses with pauses between bursts.  The bursts were alternating as fast as the analog inputs were read for a fixed number of cycles, and the start of the bursts was controlled by the Arduino data logger software. Although the ends of the bursts looked the same on the oscilloscope, with the same peak-to-peak voltage, I got different readings from the Arduino depending on the spacing between the bursts. I’m not sure what is causing the discrepancy.

A difference at the beginnings of the bursts I would understand as the space between the bursts put a DC voltage across the electrodes which gradually charged them up, so that the first few pulses actually end up going outside the range of the ADC:

The bottom of the grid is 0v, and the first pulse goes up to 5.442v. The pulses are at about 4kHz, but the bursts start 50msec apart.

The differences at the ends of the bursts as I change the spacing between bursts are probably also due to the charging, though I don’t see that clearly on the oscilloscope. I really don’t like the idea of having a DC bias across the electrodes, as we get electrolysis, with hydrogen bubbles forming on the more negative electrode. No oxygen bubbles form, probably because any oxygen released is reacting with the stainless steel to form metal oxides. If I increase the voltage and current, I get a lot of hydrogen bubbles on the negative electrode, some rusty looking precipitate coming off the positive electrode (probably an iron oxide), and a white coating building up on the positive electrode (probably a chromium oxide).

By putting a 4.7µF capacitor between the Arduino output and the electrode, I can reduce DC bias on the electrodes and get a more consistent signal from the Arduino, almost independent of the spacing between the bursts:

By using a 25msec spacing between the beginnings of bursts, I can get both the end of the burst and the beginning of the burst on the oscilloscope at once.
Using a 4.7µF capacitor between the square wave output and the electrodes results in sharp peaks across the resistor, but a more consistent reading from the Arduino ADC.

The voltage across the electrodes still does not average to 0v, as the pair of resistors provides a bias voltage halfway between the rails, but the pulse does not really swing rail to rail, but from 0.28v to 4.28v.  I think that the low-pass filter for setting the bias voltage that I suggested in More on automatic measurement of conductivity of saline solution may be a good idea after all, to make sure that there is no residual DC bias.

I can use the differential inputs of the Bitscope DP01 to look at the voltage across the electrodes and across the resistor to get voltage and current traces for the electrodes:

The central horizontal line is 0V for both traces here. The green trace is the voltage at the undriven electrode (@ 2v/division) and so corresponds to the current, and the yellow trace is the voltage between the electrodes (@0.2v/division).

Note that the voltage on the undriven electrode does run a little below 0V, outside the range of the Arduino ADC.  The voltage ratio of 0.248v/4.16v, together with the 100Ω Thévenin equivalent resistance results in a 5.47Ω resistance between the electrodes.  (Note: this is no longer a 1M NaCl solution—there has been evaporation, plus contamination from iron oxides, and the electrodes are not covered to the depth defined by the plastic spacer.)

I don’t know whether the conductivity meter is a good project for the freshman design seminar or not—I don’t expect the students to have the circuit skills or the programming skills to be able to do a design like this without a lot of coaching.  Even figuring out that they need to eliminate DC bias to eliminate electrolysis may be too much for them, though I do expect all to have had at least high-school chemistry. It is probably worth doing a demo of putting a large current through electrodes in salt solution, to show both the hydrogen bubbles and the formation of the oxides.  I could probably coach freshmen through the design, if they were interested in doing it, so I’ll leave it on the feasible list.

The square-wave analysis is not really suitable for a circuits course, so I think I’ll stick with sine-wave excitation for that course.


Filed under: Circuits course, freshman design seminar Tagged: Arduino, bioengineering, circuits, conductivity, electrodes, KL25Z, voltage divider

Data logging software for circuits course working

Over winter break, my son has been working nearly full time on writing data logging software for my students to use in the Applied Circuits for Bioengineers course. He has made the first public beta release (v1.0.0b1) today on BitBucket. (Note: you may have to click on the “tags” tab to get to the view that shows the v1.0.0b1 link. The BitBucket link directly to that view seems to be broken—that’s open issue 5504 in BitBucket’s own issue tracker.)

We’ve only tested the code on Mac OS X computers with Arduino Duemilanove and Uno boards, though we’ve tested a slightly earlier version on Windows.  The code should also run on Linux and with Leonardo and Mega boards, but has not been tested on these platforms. We welcome users testing the code for us—report any problems using the BitBucket issue tracker for the project.  The documentation is still in a fairly primitive state—report issues with that also, so that they can be fixed.

The overall goal is fairly simple: to have an easy-to-use way to record timestamps, voltages, and digital values from the Arduino into files on a host computer, without needing auxiliary hardware (like the Adafruit data logger shield that I bought for myself and assembled yesterday).

The user can specify what analog and digital pins to record and when to record the values.  When to record can be specified either   as interrupts on pins or as fixed timing intervals:

View of the two windows of the user interface.

The “volts measured” for the reference is stored as metadata in the output file and can be used for scaling the Arduino numbers (if “Convert to Volts” is checked).  The scaling can be an arbitrary value for the full-scale reading or can be the voltage measured with an external multimeter at the AREF pin.

This software has been through several versions:

  1. The first version of the code was one I wrote last spring that just recorded interrupt times in an Arduino array and dumped them out over the USB cable after it was done (see Homemade super pulley).
  2. My son was not happy with that crude program of mine and rewrote it in June to have use the Arduino memory as a queue and send the time stamps to a Python program on the laptop (see Improved super pulley code).  That program introduced him to three new concepts: circular buffers for queues, interrupts, and multi-threading, all of which he researched for himself. That version of the code mainly used a command line interface, but he used the curses package for a crude user interface.
  3. He added a PyGUI graphical user interface, but that slowed down the code on the laptop and eventually grew to be difficult to maintain.
  4. He decided to try to make the software by portable between three platforms (Mac OS X, Windows, and Linux) despite their very different ways of dealing with the USB serial ports, to run under both Python2.7 and Python3, and to require only minimal non-standard packages (mainly PySerial and the Arduino package Timer1).  He refactored the code completely and built the GUI using Tkinter. This has lead to the current version of the code, which is finally working robustly enough to let the bioengineering students use it.

It has been a good software-engineering experience for my son, and he has learned a lot.  In the process of developing this code, he has learned a lot about interrupts, using queues to communicate between processors and between threads, platform-independence, a couple of different GUI libraries, the value of version control and bug-tracking, race conditions, interface design for non-expert users, and even some things about documentation.

I’ve been acting mainly as a customer for this code, entering bug reports and suggesting new features, though I have occasionally helped him debug.  For example, we just spent fifteen minutes reading Section 15 “16-bit Timer/Counter1 with PWM” of the ATMega328 data sheet, trying to figure out why the first time interval was wrong.  It turns out that timer interrupt is raised immediately when the interrupt is enabled, unless the timer-overflow flag is turned off first.

My son may use this project as a science fair entry this year, though it was not started with that idea, and we discussed that possibility for the first time today.  The big problem is that this is purely an engineering project, not a “science” project, and trying to fake a hypothesis is not something we’ll consider.

 


Filed under: Circuits course, Data acquisition, home school, Science fair Tagged: Arduino, bioengineering, BitBucket, circuits, data logger

Data logging software for circuits course working

Over winter break, my son has been working nearly full time on writing data logging software for my students to use in the Applied Circuits for Bioengineers course. He has made the first public beta release (v1.0.0b1) today on BitBucket. (Note: you may have to click on the “tags” tab to get to the view that shows the v1.0.0b1 link. The BitBucket link directly to that view seems to be broken—that’s open issue 5504 in BitBucket’s own issue tracker.)

We’ve only tested the code on Mac OS X computers with Arduino Duemilanove and Uno boards, though we’ve tested a slightly earlier version on Windows.  The code should also run on Linux and with Leonardo and Mega boards, but has not been tested on these platforms. We welcome users testing the code for us—report any problems using the BitBucket issue tracker for the project.  The documentation is still in a fairly primitive state—report issues with that also, so that they can be fixed.

The overall goal is fairly simple: to have an easy-to-use way to record timestamps, voltages, and digital values from the Arduino into files on a host computer, without needing auxiliary hardware (like the Adafruit data logger shield that I bought for myself and assembled yesterday).

The user can specify what analog and digital pins to record and when to record the values.  When to record can be specified either   as interrupts on pins or as fixed timing intervals:

View of the two windows of the user interface.

The “volts measured” for the reference is stored as metadata in the output file and can be used for scaling the Arduino numbers (if “Convert to Volts” is checked).  The scaling can be an arbitrary value for the full-scale reading or can be the voltage measured with an external multimeter at the AREF pin.

This software has been through several versions:

  1. The first version of the code was one I wrote last spring that just recorded interrupt times in an Arduino array and dumped them out over the USB cable after it was done (see Homemade super pulley).
  2. My son was not happy with that crude program of mine and rewrote it in June to have use the Arduino memory as a queue and send the time stamps to a Python program on the laptop (see Improved super pulley code).  That program introduced him to three new concepts: circular buffers for queues, interrupts, and multi-threading, all of which he researched for himself. That version of the code mainly used a command line interface, but he used the curses package for a crude user interface.
  3. He added a PyGUI graphical user interface, but that slowed down the code on the laptop and eventually grew to be difficult to maintain.
  4. He decided to try to make the software by portable between three platforms (Mac OS X, Windows, and Linux) despite their very different ways of dealing with the USB serial ports, to run under both Python2.7 and Python3, and to require only minimal non-standard packages (mainly PySerial and the Arduino package Timer1).  He refactored the code completely and built the GUI using Tkinter. This has lead to the current version of the code, which is finally working robustly enough to let the bioengineering students use it.

It has been a good software-engineering experience for my son, and he has learned a lot.  In the process of developing this code, he has learned a lot about interrupts, using queues to communicate between processors and between threads, platform-independence, a couple of different GUI libraries, the value of version control and bug-tracking, race conditions, interface design for non-expert users, and even some things about documentation.

I’ve been acting mainly as a customer for this code, entering bug reports and suggesting new features, though I have occasionally helped him debug.  For example, we just spent fifteen minutes reading Section 15 “16-bit Timer/Counter1 with PWM” of the ATMega328 data sheet, trying to figure out why the first time interval was wrong.  It turns out that timer interrupt is raised immediately when the interrupt is enabled, unless the timer-overflow flag is turned off first.

My son may use this project as a science fair entry this year, though it was not started with that idea, and we discussed that possibility for the first time today.  The big problem is that this is purely an engineering project, not a “science” project, and trying to fake a hypothesis is not something we’ll consider.

 


Filed under: Circuits course, Data acquisition, home school, Science fair Tagged: Arduino, bioengineering, BitBucket, circuits, data logger

Hysteresis board

Now that we’re using a 74HC14 Schmitt trigger in the capacitive touch sensor for the hysteresis oscillator, that lab can be the first soldering project, in addition to learning about hysteresis.

I tried laying out a very compact PC board for the students to solder (still requiring them to do some design—they’ll have to breadboard their design first to get appropriate R and C values). I came up with one very compact design that could get 4 copies into the 50mm×50mm limit of the $1 boards from ITEAD, making the boards only 25¢ each.

Compact layout to get 4 hysteresis oscillator boards out of one 50mm×50mm board. The gutters are pretty narrow, though, and I’m not sure I’m skillful enough with the board shears to cut that accurately.  The yellow “airwires” are Eagle telling me that the Gnd and +5V wires are not connected between the different copies.

It seemed a little silly to try to squeeze the price down to 25¢, when the other parts cost 90¢: 59¢ for the screw terminals, 28¢ for the Schmitt trigger chip, 1¢ for the resistor, and 2¢ for the capacitor. With this layout it is also a little tricky for the students to properly wire the unused inputs high.

Given the high risk of ruining the boards trying to cute them with the board shears, I decided to redesign for a 50¢ board.

Much looser layout, having only two copies on the 50mm x 50mm board. This version makes it easier for the students to see how things are connected, and has lots of room for the board shears to make the cut.

The lab would now require that the students measure the thresholds of the Schmitt trigger, breadboard the hysteresis oscillator, make a touch pad out of foil and packing tape, measure the frequency of the oscillation to estimate the touch pad capacitance, adjust the parameters of the Arduino program to match the frequencies of their oscillator, solder up the board, and demonstrate it working to control an LED. I think that is plenty for a 3-hour lab.

When I set up the web pages for the course, I’ll try to make sure I put the Eagle design files (.brd and .sch) for each board the students use on the web, so that future instructors can easily order more copies of the board, even if my laptop gets run over by a beer truck.  That will also make it easier for instructors at other schools to try to duplicate the course.


Filed under: Circuits course, Printed Circuit Boards Tagged: Arduino, bioengineering, capacitive touch sensor, circuits, course design, Printed circuit board, Schmitt trigger, sensors, teaching

Hysteresis lab

Schmitt-trigger oscillator.

Since I decided in Capacitive sensing with Schmitt trigger to use an off-the-shelf Schmitt trigger chip (like a 74HC14) and a very simple oscillator, I needed to rethink the lab and expand it.  Students will no longer be spending much time on building the circuit, so we need to play with other uses for the oscillator circuit and other applications of Schmitt triggers.

The Schmitt trigger is a useful device for students to learn about, since hysteresis is an important concept in detecting signals.  Probably the first thing to have them do is to use the oscilloscope in x-y mode to see the Vout vs. Vin curve for the Schmitt trigger inverter. It would be good for them to devise a way to measure the threshold voltages accurately (with their lab writeup describing both the method used and the thresholds measured), using the equipment they have available.  Perhaps bonus points for methods that don’t require any of the bench equipment? (There are some fairly easy methods using the Arduino for voltage measurements, though precision would be limited to about 5mV.)

After characterizing the inverter, they should design and measure one-inverter oscillators for different frequencies, using different combinations of resistors and capacitors (some low-resistance, high-capacitance designs and some high-resistance, low-capacitance designs).  They should show computations for the frequency using the threshold voltages and the R and C values.  It might be worthwhile to have them estimate the parasitic capacitance of the input to the Schmitt trigger (together with the wiring).

Then they should measure capacitance by hooking up an unknown capacitor with a known resistance, measuring the frequency, and computing the capacitance.  We would have to make up some unknowns with a wide range of different values.

Finally, they should make a capacitive touch pad (a piece of aluminum foil covered with a layer of packing tape). I’ve decided that I like foil covered with packing tape better than foil wrapped in plastic wrap.  The tape may be a bit thicker, but the lack of an air bubble makes for a much more repeatable capacitance, and it is less likely to fall apart when handled.

They should use the oscillator frequency to estimate the capacitance of both the plain pad and the pad when touched by a finger.  After observing the oscillator output on the oscilloscope they should adjust the parameters of a simple hysteresis program to turn an LED on and off with the touch sensor so that a firm touch is needed to light the LED and it doesn’t flicker with a light touch:

void setup(void)
{  pinMode(2,INPUT);
   pinMode(13,OUTPUT);
}

void loop(void)
{   digitalWrite(13, LOW);
    while (pulseIn(2,HIGH) &lt;= 60) {}
    digitalWrite(13, HIGH);
    while (pulseIn(2,HIGH) &gt;= 45) {}
}

 


Filed under: Circuits course Tagged: Arduino, bioengineering, capacitive touch sensor, circuits, course design, Schmitt trigger, sensors, teaching