Digital logic

Looking at Signals on I2C on WeatherPiArduino

Next issue, SwitchDoc Labs is doing an article on WeatherPiArduino, an interface board for both the Raspberry Pi and Arduino to talk to weather instruments, including a new Lightning Detector. It uses a bunch of I2C devices and connects to an anemometer/wind vane and rain bucket. I am currently doing the final testing on this new board and thought I would use the logic analyzer to start looking at the I2C bus (Figure 4).

Figure 4: Arduino and WeatherPiArduino board with logic analyzer connected to I2C.

One of the most powerful features of this logic analyzer is its ability to record and then display protocol information. Take a look at the trace in Figure 5. It shows a trace of the I2C bus when the computer is writing to the WeatherPiArduino BMP180 Barometer/Temperature I2C device. The protocol analyzer states that I am writing to I2C address 0x77 (the address for the BMP180), setting up a write to address 0xF4 (Measurement Control), and then writing out the data to 0x2E, which sets up the BMP180 to start a temperature measurement.

Figure 5: Setting up a temperature read on an I2C BMP180 barometer.

The trace in Figure 6 shows a read of the DS3231 real-time clock [2] that is also connected to the WeatherPiArduino board. This trace shows a much more complex sequence, all nicely decoded by the logic analyzer. See how hard it would be to read these sequences by hand. This shows first a write to the I2C Address 0x68, which is the address for the DS3231, then a command to read out the time from the DS3231 (0x00), and then the read from the DS3231 address 0x68 consisting of seconds, minutes, hours, day, date, month, and year in seven single-byte read transfers.

Figure 6: A read of the DS3231 real-time clock.

The trace in Figure 7 is from a SunAir board talking to the MouseAir motor controller board driving a stepper motor in the SunTracker system (see the "Solar Power Management" article elsewhere in this issue). Figure 8 shows the setup.

Figure 7: Stepper motor drive from Arduino to SunAir.
Figure 8: Arduino, SunAir board, and MouseAir controller board instrumented with logic analyzer.

A stepper motor is a brushless DC electric motor that divides a full rotation into a number of equal steps. The motor's position can then be commanded to move and hold at one of these steps without any feedback sensor (an open-loop controller), as long as the motor is carefully sized to the application.

To make a stepper turn, you send the two coils of the motor specific signals (Figure 9 shows the trace) to attract the gear teeth with an electromagnet. With the right sequence, one coil is turned off and then the second coil is turned on, making the gear rotate slightly to align with the second one. Repeating this sequence makes the motor move step by step, hence the name. This allows the motor to be turned by a precise angle.

Figure 9: Zoomed in trace for stepper motor signals.

Listing 2 shows the main part of the code generating this trace.

Listing 2

Code Generating Stepper Motor Trace

001 // Stepper Motor Test for Logic Analyzer
002 // SwitchDoc Labs 1/14/2014
003
004
005 #define LEFTSTEP 0
006 #define RIGHTSTEP 1
007 int Motor1A = 8;   // GP2 on SunAir
008 int Motor2A = 13;   // Servo on SunAir
009 int Motor3A = 12;   // Limit0 on SunAir
010 int Motor4A = 11;   // Limit1 on SunAir
011 int EN12 =7;   // Not on on SunAir / on SunAirPlus
012 int EN34 = 6;   // Not on  on SunAir / on SunAirPlus
013
014
015 // stepper controls
016
017 void enable_motor()
018 {
019       digitalWrite(EN12, 1);
020
021       digitalWrite(EN34, 1);
022
023 }
024
025 void disable_motor()
026 {
027       digitalWrite(EN12, 0);
028       digitalWrite(EN34, 0);
029
030
031 }
032 void multipleStep(int count, int direction)
033 {
034
035   enable_motor();
036   int i;
037   Serial.print("multipleStep:  Count=");
038   Serial.print(count);
039   Serial.print(" direction = ");
040   if (direction == LEFTSTEP)
041     Serial.println("LEFTSTEP");
042   else
043     Serial.println("RIGHTSTEP");
044
045
046   for (i= 0; i < count; i++)
047   {
048     if (direction == LEFTSTEP)
049       forwardStep();
050      else
051       reverseStep();
052
053   }
054   disable_motor();
055
056 }
057
058
059
060 void forwardStep()
061 {
062    float StepDelay = 50;
063
064   // step 1
065   digitalWrite(Motor1A, 1);  // coil 1a
066   digitalWrite(Motor3A, 1);  // coil 2a
067   digitalWrite(Motor2A, 0);  // coil 1b
068   digitalWrite(Motor4A, 0);  // coil 2b
069   delay(StepDelay);
070
071
072   // step 2
073   digitalWrite(Motor1A, 0);  // coil 1a
074   digitalWrite(Motor3A, 1);  // coil 2a
075   digitalWrite(Motor2A, 1);  // coil 1b
076   digitalWrite(Motor4A, 0);  // coil 2b
077   delay(StepDelay);
078
079
080
081   // step 3
082   digitalWrite(Motor1A, 0);  // coil 1a
083   digitalWrite(Motor3A, 0);  // coil 2a
084   digitalWrite(Motor2A, 1);  // coil 1b
085   digitalWrite(Motor4A, 1);  // coil 2b
086   delay(StepDelay);
087
088   // step 4
089   digitalWrite(Motor1A, 1);  // coil 1a
090   digitalWrite(Motor3A, 0);  // coil 2a
091   digitalWrite(Motor2A, 0);  // coil 1b
092   digitalWrite(Motor4A, 1);  // coil 2b
093   delay(StepDelay);
094
095 }
096
097 void reverseStep()
098 {
099
100      float StepDelay = 50;
101   // step 4
102   digitalWrite(Motor1A, 1);  // coil 1a
103   digitalWrite(Motor3A, 0);  // coil 2a
104   digitalWrite(Motor2A, 0);  // coil 1b
105   digitalWrite(Motor4A, 1);  // coil 2b
106   delay(StepDelay);
107
108
109   // step 3
110   digitalWrite(Motor1A, 0);  // coil 1a
111   digitalWrite(Motor3A, 0);  // coil 2a
112   digitalWrite(Motor2A, 1);  // coil 1b
113   digitalWrite(Motor4A, 1);  // coil 2b
114   delay(StepDelay);
115
116   // step 2
117   digitalWrite(Motor1A, 0);  // coil 1a
118   digitalWrite(Motor3A, 1);  // coil 2a
119   digitalWrite(Motor2A, 1);  // coil 1b
120   digitalWrite(Motor4A, 0);  // coil 2b
121   delay(StepDelay);
122
123
124
125
126  // step 1
127   digitalWrite(Motor1A, 1);  // coil 1a
128   digitalWrite(Motor3A, 1);  // coil 2a
129   digitalWrite(Motor2A, 0);  // coil 1b
130   digitalWrite(Motor4A, 0);  // coil 2b
131   delay(StepDelay);
132
133
134 }
135
136
137 // the setup routine runs once when you press reset:
138 void setup() {
139   // initialize serial communication at 9600 bits per second:
140   Serial.begin(57600);
141   Serial.println("");
142   Serial.println("----------start of SunAir SunTracker script---------");
143   Serial.println("");
144
145   pinMode(Motor1A, OUTPUT);
146   pinMode(Motor2A, OUTPUT);
147   pinMode(Motor3A, OUTPUT);
148   pinMode(Motor4A, OUTPUT);
149   pinMode(EN12, OUTPUT);
150   pinMode(EN34, OUTPUT);
151
152
153 }
154
155 void loop() {
156
157
158
159    multipleStep(5, LEFTSTEP);
160
161
162    delay(100);
163
164    multipleStep(5, RIGHTSTEP);
165    delay(1000);
166
167 }

Question from a Reader

[UCC:interviewer]Q:[/UCC] What are some good vendors and software for making your own PC boards like the ones by SwitchDoc Labs?

[UCC:interviewee]A:[/UCC] I primarily use one vendor for prototype PCBs and production boards: TinySine [3]. This vendor has given excellent service and help (hats off to all of the folks at TinySine!) when things have been difficult. They are exceedingly pleasant to deal with, and believe me, when you are doing these kinds of project, you want to have a good relationship with your manufacturer. I do all of my PCB design using CadSoft Eagle software. It has a learning curve, but the free version works very well for small boards and design, and you'll find some great tutorials online.

Buy this article as PDF

Express-Checkout as PDF

Pages: 8

Price $2.95
(incl. VAT)

Buy Raspberry Pi Geek

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content