Вы находитесь на странице: 1из 11

Microcontroladores LAB 3 Jueves 24/Nov/2016

Laboratory 3 Microcontrollers II Analog Read + 7 Segment


Group Name: .

Group Members: , , .

Grade (max = 10, no pre-lab this time): .

Lab report is due one week from the completion of the lab.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
Reading: Practical Electronics for Inventors Chapter 13.

Objective: Deepen our understanding of the Arduino microcontroller: more programming


structures, functions, multiplexing of data, loading libraries, one-wire communication.

a) Arduino pinout and basics

Fig. 1. Arduino nano. It is always useful to have a blown-up figure with the pins labeled!
Also, please have handy the pin function descriptions of Lab 12, Fig. 2.

In the last laboratory we learned some basics about the Arduino code structures:
1. declaration and scope of constants and variables (const int v = 0, float voltage, etc.)
2. setting-up pins for input or output (pinMode(pin, INPUT/OUTPUT))
3. reading and writing from/to pins: digital, analog, PWM (digitalWrite(pin,
HIGH/LOW), digitalRead(pin), analogRead(pin), analogWrite(pin, value)).
4. waiting a specified time (delay(timeinms))
5. writing and reading from the serial interface (Serial.begin(baud), Serial.print(), etc.)
6. if/then structures and logical operations (and &, or ||, not !)
7. performing functions in a loop (for(int j = 0; j <= 5; j++){\\stuff})

For more information, please consult the textbook, in particular Table 13.6, and/or the Ar-
duino language reference at http://arduino.cc/en/Reference/HomePage.

2016 Carlos Wexler Page 1 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

In this lab we will continue our understanding of the structure of the arduino code and
build up our experience to make more sophisticated programs.

b) A digital voltmeter

Task 1: Lets continue our play with analogReading and the LEDs we set-up for our
Knight Rider! Build a circuit that measures the voltage in some input and displays it to the
computer using Serial.print() and Serial.println(). Please be neat make all the conversions
and add the units, dont just print 1.37 but 1.37 V). OK, that is simple now lets also
display the voltage in binary using 4 LEDs (a very rudimentary voltmeter in case we cant
use the computer!). A typical quantization scheme may be as follows:

Vin (V) 0.0-0.1 0.1-0.2 0.2-0.3 0.3-0.4 0.4-0.5 0.5-0.6 0.6-0.7 0.7-0.8
LEDs 0000 0001 0010 0011 0100 0101 0110 0111

Vin (V) 0.8-0.9 0.9-1.0 1.0-1.1 1.1-1.2 1.2-1.3 1.3-1.4 1.4-1.5 1.5-1.6
LEDs 1000 1001 1010 1011 1100 1101 1110 1111

Hint: do not work with the float voltage, but operate directly with the integer that comes
out of analogRead(pin).

You can decide which LEDs to turn on or off using if/then/else if/else structures:

if (voltage < 0.1)


{
// do Thing A
}
else if (voltage < 0.2)
{
// do Thing B
}
// etc., etc.
else
{
// do Thing C
}

Note the following ways to perform comparisons:

x == y // (x is equal to y)
x != y // (x is not equal to y)
x<y // (x is less than y)
x>y // (x is greater than y)
x <= y // (x is less than or equal to y)
x >= y // (x is greater than or equal to y)

2016 Carlos Wexler Page 2 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

Please show your working system to the instructor, save the code and attach it to your re-
port. Note that doing things this way requires about 16 (24) decisions. It is becoming cum-
bersome!

It is probably not very practical here, but other branching uses the switch case structure:

switch (var) {
case 1:
//do something when var equals 1
break;
case 2:
//do something when var equals 2
break;
default:
// if nothing else matches, do the default
// default is optional
}

c) Integer division and bit manipulation (better methods!)

As noted, the approach used in Part b to decide which LEDs should be on or off (when us-
ing the 4 LEDs to represent the voltages between 0.0 and 1.6 V) is very cumbersome, re-
quiring a sequence of ~16 if/else if/else decisions and those decisions were based on
comparison of floating point variables.

There are some advantages to these methods: code is simple to understand, and the use of
floats makes it very clear where the cut-offs are. This is something that is often very desir-
able for large codes and when computer resources are not an issue (e.g., coding for a desk-
top computer with a quad-core processor running at 3 GHz and 16 GB of RAM). However,
for small devices that have very limited resources like an Arduino (just 2 kB of RAM, 4 bil-
lion times less than a new PC, and running at a mere 16 MHz), using floats should be
avoided when possible. Floats take more RAM (4 bytes vs. 2 for an int, and some opera-
tions could be done with mere bytes) and math operations with floats are a lot slower than
with ints (the Arduinos do not have a floating point co-processor!).

A second, and perhaps more important issue is that the ~16 decisions that had to be made
to turn on/of the 4 LEDs is clearly not scalable for larger number of bits. E.g., if one wanted
to fully represent the 10 bits that analogRead() gives, then ~1024 decisions should have
been made! This is clearly not practical. The two methods below scales only like the num-
ber of bits (4 decisions for 4 bits/LEDs, 10 for 10 bits/LEDs).

2016 Carlos Wexler Page 3 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

Task 2: Lets do the same in a more practical way (requiring O(n) operations, where n is the
number of bits, rather than the O(2n) operations in Task 1). The idea is to use integer divi-
sion and the remainder or by doing crazy bit manipulations.

(i) With integer math:

In integer math, the division has two operations: / and % which correspond to the
quotient and remainder. For example:

5/3 1
5%3 2

Lets see how this works:

int sensorread = analogRead(A0); // 0 V 0, 5.0 V 1023, e.g., for 1.3 V gives 266
int tenths = sensorread/(1023/50); // e.g., for 1.3 V tenths = 13
int b3 = tenths/8; // b3 = 13/8 = 1, the 2^3 coefficient
int b2 = (tenths % 8)/4; // b2 = (5)/4 = 1, the 2^2 coefficient
int b1 = (tenths % 4)/2; // b1 = (1)/2 = 0 , the 2^1 coefficient
int b0 = tenths % 2; // b0 = 1, the 2^0 coefficient
// 1.3 V 1310 = 11012
digitalWrite(Pinb3, b3); // turn LED3 on or off (in this case ON)
digitalWrite(Pinb2, b2); // LED2 = ON
digitalWrite(Pinb1, b1); // LED1 = OFF
digitalWrite(Pinb0, b0); // LED0 = ON

(note that with only 4 bits we can only go 0 to 15, hence 0 to 1.5 V, if you want to reach 5.0
V using this scale you have to use 6 bits, and 6 LEDs)

(ii) Bit manipulation (bit shift operations):

Professional programmers like to use bit manipulation which is faster and uses less
memory resources. I will not get into how it works, and we will not use it very often as it is
hard to read for novices (that includes myself!). But you can search for it if you are inter-
ested (e.g., http://playground.arduino.cc/Code/BitMath#bit_shift). The code above would
read:

boolean b3 = tenths & (1<<3);


boolean b2 = tenths & (1<<2);
boolean b1 = tenths & (1<<1);
boolean b0 = tenths & (1<<0);
// etc.

Implement the 4-bit (or more bits if you have the LEDs wired!) Digital to Analog Converter
(DAC) using either method (i) or method (ii). Show your working system to the instructor,
save your code, print it and attach to the report.

2016 Carlos Wexler Page 4 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

But who wants to really read binary?? This brings us to

Task 3: display the binary output in a more human-friendly format (besides the output to
the computer). We will use a 7-segment display to do this. It is possible to do this in hard-
ware (e.g. using the binary7-segment decoder chip CD4511), but we will do it in soft-
ware within the Arduino instead! We will use the common cathode 7-digit display SC08-
11SRWA, see Fig. 2. One of pins 3, 5, 11, or 16 should be connected to GND. The other
pins, when brought to +5V by the Arduino output (each through a 220-1k resistor!)
will lit the corresponding segment.

Fig. 2. SC08-11SRWA single digit numeric displays.

Recommendation: use your solderless breadboard to make the connections between the
seven segment LED and your Arduino nano (if you find better ways of connecting it, please
do so I did it this way, but it wasnt pretty ). Think ahead wiring this circuit should
help you with the next section too, so plan for adding a 2nd digit later!

Arduino Pin 7 Segment Pin Connection


2 1 (A)
3 14 (B)
4 12 (C)
5 10 (D)
6 4 (E)
7 2 (F)
8 13 (G)

The following listing will help you understand what to do, and introduce you to how to or-
ganize programs using functions
(see http://arduino.cc/en/Reference/FunctionDeclaration):

2016 Carlos Wexler Page 5 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

Listing 1: a seven-segment display driver. Please note that there are MUCH MORE ELE-
GANT ways of doing this, but the way below is easy to understand (the elegant ways often
are not easy to read but use some clever wizardry not recommended).
THIS CODE IS AVAILABLE FOR YOU TO COPY PASTE

// Here is a neat trick: using pre-compiler directives:


// here the compiler will replace any mention of the names by the values,
// this will not use any memory at all! (this may save a lot of memory!)
#define PinA 2
#define PinB 3
#define PinC 4
#define PinD 5
#define PinE 6
#define PinF 7
#define PinG 8

// Setup here.
void setup() {
pinMode(PinA, OUTPUT);
pinMode(PinB, OUTPUT);
pinMode(PinC, OUTPUT);
pinMode(PinD, OUTPUT);
pinMode(PinE, OUTPUT);
pinMode(PinF, OUTPUT);
pinMode(PinG, OUTPUT);
pinMode(9, OUTPUT);
}
// Loop here
void loop(){

// DO ALL OTHER NECESSARY STUFF HERE


// display value using
// sevensegment(value)
// where value should be an integer between 0 and 9
// you may want to extend the function sevensegment to include 10-15 (A-F) if you want
// if you do, please share the code with me.

// here I am defining a function that writes the right stuff to the 7-segment display
// depending on the value of its input n which should be between 0 and 9
// you may want to extend the function sevensegment to include 10-15 (A-F) if you want
// if you do, please share the code with me.
// NOTICE HOW THE INDENTATION OF THE CODE MAKES ITS STRUCTURE CLEAR!
void sevensegment(int n){
switch (n) {
case 0:
// write '0'
digitalWrite(PinA, 1);

2016 Carlos Wexler Page 6 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

digitalWrite(PinB, 1);
digitalWrite(PinC, 1);
digitalWrite(PinD, 1);
digitalWrite(PinE, 1);
digitalWrite(PinF, 1);
digitalWrite(PinG, 0);
break;
case 1:
// write '1'
digitalWrite(PinA, 0);
digitalWrite(PinB, 1);
digitalWrite(PinC, 1);
digitalWrite(PinD, 0);
digitalWrite(PinE, 0);
digitalWrite(PinF, 0);
digitalWrite(PinG, 0);
break;
case 2:
// write '2'
digitalWrite(PinA, 1);
digitalWrite(PinB, 1);
digitalWrite(PinC, 0);
digitalWrite(PinD, 1);
digitalWrite(PinE, 1);
digitalWrite(PinF, 0);
digitalWrite(PinG, 1);
break;
case 3:
// write '3'
digitalWrite(PinA, 1);
digitalWrite(PinB, 1);
digitalWrite(PinC, 1);
digitalWrite(PinD, 1);
digitalWrite(PinE, 0);
digitalWrite(PinF, 0);
digitalWrite(PinG, 1);
break;
case 4:
// write '4'
digitalWrite(PinA, 0);
digitalWrite(PinB, 1);
digitalWrite(PinC, 1);
digitalWrite(PinD, 0);
digitalWrite(PinE, 0);
digitalWrite(PinF, 1);
digitalWrite(PinG, 1);
break;
case 5:
// write '5'
digitalWrite(PinA, 1);

2016 Carlos Wexler Page 7 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

digitalWrite(PinB, 0);
digitalWrite(PinC, 1);
digitalWrite(PinD, 1);
digitalWrite(PinE, 0);
digitalWrite(PinF, 1);
digitalWrite(PinG, 1);
break;
case 6:
// write '6'
digitalWrite(PinA, 1);
digitalWrite(PinB, 0);
digitalWrite(PinC, 1);
digitalWrite(PinD, 1);
digitalWrite(PinE, 1);
digitalWrite(PinF, 1);
digitalWrite(PinG, 1);
break;
case 7:
// write '7'
digitalWrite(PinA, 1);
digitalWrite(PinB, 1);
digitalWrite(PinC, 1);
digitalWrite(PinD, 0);
digitalWrite(PinE, 0);
digitalWrite(PinF, 0);
digitalWrite(PinG, 0);
break;
case 8:
// write '8'
digitalWrite(PinA, 1);
digitalWrite(PinB, 1);
digitalWrite(PinC, 1);
digitalWrite(PinD, 1);
digitalWrite(PinE, 1);
digitalWrite(PinF, 1);
digitalWrite(PinG, 1);
break;
case 9:
// write '9'
digitalWrite(PinA, 1);
digitalWrite(PinB, 1);
digitalWrite(PinC, 1);
digitalWrite(PinD, 0);
digitalWrite(PinE, 0);
digitalWrite(PinF, 1);
digitalWrite(PinG, 1);
break;
default:
// if nothing else matches, do the default
// default is optional

2016 Carlos Wexler Page 8 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

// draw a single bar in the center of the display


digitalWrite(PinA, 0);
digitalWrite(PinB, 0);
digitalWrite(PinC, 0);
digitalWrite(PinD, 0);
digitalWrite(PinE, 0);
digitalWrite(PinF, 0);
digitalWrite(PinG, 1);
}
}

Your Arduino should now display the tenths of Volts in human-readable form from the
analog input!

d) Multiplexing

The voltmeter you built above works well, but only displays 1 digit (it is limited to dis-
playing [0.0,1.0) V. Can we do two digits and improve the capabilities of the multimeter (so
that it can do 0-5V? Naively, one would add another 7-segment display, with the seven new
A-G connections wired to other 7 outputs of the Arduino. Whereas this is feasible, it does
not make much sense to use almost all Arduino pins for just that, and is clearly not easy to
scale-up to 4, 5 or more digits.

To display more digits, a method called multiplexing is used. It relies on the fact that the
eye is not able to discern changes that occur very fast (persistence of vision). The idea is to
share the information of the two digits, switching them on and off very quickly (> 50 Hz).

Fig. 3. (textbook Fig. 13.39) Multiplexing 3 7-segment displays. Notice how easy it is to
scale-up to larger number of digits (limited only by the speed of the multiplexing, and pos-
sible loss of brightness in the display as each digit is on only 1/N of the time).

How to proceed? Figure 3 gives the idea (for a 3 digit display, we will only do 2). All seg-
ments A-G are wired in parallel, but the common cathodes are no longer directly connect-
ed to ground. Instead, transistors driven between cut-off and saturation by the microcon-

2016 Carlos Wexler Page 9 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

troller decide which of the digits is operational. For example, initially the microcontroller
sends 100 to the transistors: a 1 to the leftmost transistor (making it saturate) and 0 to the
other ones (cut-off). It then sends the A-G bits corresponding to the leftmost digit. After
some short time (a few ms, tipically), 010 is sent to the transistors (turning on the center
display) and the A-G bits for the second digit are sent. Then the third digit is activated, and
finally the cycle repeats itself. If this cycle is repeated more than 50 times per second, this
gives the illusion that all digits are working at the same time and only 10 pins are used in-
stead of 21 (and the more digits you add the better the savings!).

Task 4: In this lab we will wire only 2 digits, see Fig. 4. Take the circuit you last wired for
the 1 digit display, and simply add another display in parallel (add 7 wires connecting the
two digits together A1-A2, B1-B2, etc, you still need the resistors between the Arduino pins
and the first digit). The cathode that was first connected to the ground now should go
through a transistor as shown (for these low-current displays a pair of 2N3904 will work
well, but it is also possible to use n-channel enhancement mode MOSFETs, which is a good
choice for driving large currents). Use Pins 9 & 10 to control the transistors (other pins are
OK too).

Fig. 4. Multiplexing 2 7-segment displays. Dont forget that each Segment is wired to the
microcontroller through a 220-1k resistor!

In more sophisticated programs, the switching of the Pins 9 and 10 is done by a timer-
based interrupt subroutine (timer interrupts allow the code to run a normal code, which
periodically is stopped very briefly to do some maintenance task, e.g., switch Pin 9 and 10
every 1/50th of a second, we will do this next lab). Now, for simplicity we will bit-bang
these changes within the main part of the code: loop(){}.
The following code extract shows some idea on how to do it test it on your own!

2016 Carlos Wexler Page 10 of 11


Microcontroladores LAB 3 Jueves 24/Nov/2016

Listing 2: Multiplexing portion of a two-digit seven-segment display driver. In addition,


you will need the integer division or bit manipulation conversion parts and Listing 1
(the subroutine sevensegment(int n) that decodes the numbers into the segments to lit).
Note: this is not the best or most elegant way of doing this, but it is reasonably easy to un-
derstand!
THIS CODE IS AVAILABLE FOR YOU TO COPY PASTE

//these two pins control which of the two digits will be on


#define PinL 9
#define PinR 10
#define tdisplay = 10 //time on for each display. Frequency of display will be 50/tdisplay Hz

// Setup here.
void setup() {
pinMode(PinL, OUTPUT);
pinMode(PinR, OUTPUT);
}

// Loop here
void loop(){
// put here the portion with analogRead()
// calculate the volts in terms of tenths of volts, e.g., 2.3 V 23
// separate the right and left digits using integer division and the modulus (see Listing 1)
// these should go into integer variables numberR and numberL:

// This block bit bangs the data to the 2 displays


// sends the right digit, waits 10 ms, then sends the left digit, waits 10 ms
// and now the loop restarts (roughly 50 times per second)
digitalWrite(PinL,LOW);
digitalWrite(PinR,HIGH);
sevensegment(numberR);
delay(tdisplay);
digitalWrite(PinL,HIGH);
digitalWrite(PinR,LOW);
sevensegment(numberL);
delay(tdisplay);
}

Task 3: Increase tdisplay until you can clearly see the two digits switching. Also: reduce
tdisplay and see if there is a point (too fast) where the display stops working correctly.
Show your working system to the instructor and save your code, print it and include in
your report.

Next lab we will understand how to do this swapping of the digits in a more elegant way
using timer interrupts (which almost resemble multi-tasking at a very crude level).

Do not disassemble this circuit! You will use it again in the next lab.

2016 Carlos Wexler Page 11 of 11

Вам также может понравиться