0% found this document useful (0 votes)
9 views7 pages

Arduino LED Control with Bitwise Manipulation

This document describes a practical exercise to control LEDs using an Arduino, utilizing both Arduino libraries and direct register manipulations. It explains how to blink an internal and external LED, using transistors to manage the current, and offers variations of the code for direct access to hardware ports. Finally, it presents a challenge to blink two LEDs alternately, adhering to specific timing.

Translated by

ScribdTranslations
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views7 pages

Arduino LED Control with Bitwise Manipulation

This document describes a practical exercise to control LEDs using an Arduino, utilizing both Arduino libraries and direct register manipulations. It explains how to blink an internal and external LED, using transistors to manage the current, and offers variations of the code for direct access to hardware ports. Finally, it presents a challenge to blink two LEDs alternately, adhering to specific timing.

Translated by

ScribdTranslations
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

In this exercise, we will manipulate digital outputs using both the libraries of

the Arduino environment and more directly by 'bitwise manipulation' of the registers. The goal
It will be to control an LED interfaced with the Arduino using the appropriate electronic circuits.

First, we use a modified version of the exampleBlink program. This one makes blink
the surface-mounted LED on the board is connected to connector 13 of the Arduino. Periodically, the
LED will be lit for two seconds, then turned off for one second. Messages will be
products output via the serial connection to report the result.

Type the following code in the editor:

Select
/*
MyBlink
Make an LED blink in a loop
with display on the serial monitor
*/

Connector 13 is connected to a surface-mounted LED.


// on most Arduino boards. It is assigned a name:
#define LEDPIN 13

void setup()
{
Configure the output connector
pinMode(LEDPIN, OUTPUT);
Configure the serial communication at a speed of 9600 bits per second.
second
[Link](9600);
}
voidloop()
{
[Link]("On");
digitalWrite(LEDPIN, HIGH);// Turn on the LED
delay(2000);// Delay for 2 seconds
Off
digitalWrite(LEDPIN, LOW);// Turn off the LED
delay(1000);// Delay 1 second
}

Compile the code and upload it to the board. Open the Serial Monitor. You should see some
messages display, reflecting the state of the surface-mounted LED on the board.

The code is rather obvious, but some clarifications are necessary. First of all, connector 13 of
The Arduino Uno is connected to a small surface-mounted LED on the board. The connector is connected
to a current limiting resistor, itself connected to the anode of the LED, the cathode
returning to the mass. Thus, applying voltage to the connector lights up the LED. The
routinesetupconfigures the output connector and establishes the serial communication system. The
Routine loop uses digitalWrite() to alternately toggle the output of the connector to the state
high or low, which allows you to turn the LED on or off. The delay() function is used to
maintain the state temporarily, thus allowing the blinking of the LED to be observed with the naked eye.
This timing function works very well here, but it's just a simple loop.
waiting that prevents any other useful task from being executed during this period of time. It is
a serious limitation for programs with intensive tasks, but we will make do
for the moment.

We are now leaving the use of the internal LED on the board for an external LED. While
the AVR 328P can deliver a current of 20 mA per pin, if one chooses to control multiple LEDs, it
It is preferable to use a transistor to limit the current requested from the microcontroller.
The general outline is as follows:

The NPN transistor will saturate and the LED will light up with a high voltage on its base, while
in the version with the PNP transistor, it will saturate with a low voltage on its base. In
In both cases, the current flowing through the LED is the saturation current of the transistor which is
approximately equal to the supply voltage Vcc, minus the forward voltage of the LED, all of it
divided by the collector resistance Rc. For example, to obtain 10 mA with a power supply
5 V and a red LED (threshold voltage at about 2 V), the necessary resistor Rc is about
300Ω. The base resistor Rb should be approximately equal to 20 times this value for a current of
Pilotage of approximately 700 microamperes. This should ensure saturation for the current values.
of gain in current β. Transistors like the 2N3904 or 2N3906 are classic choices,
but if a large number of components need to be controlled, it may be interesting to turn to
into an integrated circuit like the ULN2003.

Now modify the code of the previous example using an NPN transistor this time controlled
with connector 8 of the Arduino. To anticipate what follows, it is specified that this connector corresponds
At port B, bit 0 (PB0) of the ATmega328P. First, the components need to be wired on a board.
of tests using standard resistance values (330Ω and 6.8 kΩ will do). Connect
Vcc to the 5 V connector of the Arduino, and the ground to the GND connector (the two connectors being
on the same portPOWER of the board).

Now connect the control pin (Vbb) to the D8 connector of the Arduino. The modified code is
the following:

Select
/* Blinking (Blink) of an external LED */

#define LEDPIN 8

void setup()
{
pinMode(LEDPIN, OUTPUT);
}

voidloop()
{
digitalWrite(LEDPIN, HIGH);
delay(2000);// pause for 2 seconds
digitalWrite(LEDPIN, LOW);
delay(1000);// delay 1 second
}

Compile the code and upload it to the board. Upon execution, you should observe a beautiful
blinking of the LED. Also observe the timing. Now, prepare the new
assemble it with the PNP transistor, then connect it to the D8 connector instead of the NPN version of
transistor (without dismantling the NPN assembly, just by disconnecting it from the microcontroller). Do not change
Nothing in the code. You should notice a difference in the on/off cadence of the LED. If
you notice no change, reconnect the NPN and observe again.

Now let's consider direct access to hardware resources, without going through the libraries.
from the Arduino environment. There are two methods to do this: the first is to search
the actual addresses of hardware ports and registers, and assign pointers to them.
The second method (a bit easier) involves using predefined macros for the ports and
the registers.

The following is a variation of the Blink LED program using direct access.
at the port using pointers. Note that the variables for the port and the direction registers of
data is declared, then hard-coded with the numerical values of the addresses.

All of this varies from one processor to another, making the code non-portable, and it is not
desirable. However, this process helps to illustrate what is really happening at the level of
microcontroller and it results in a compact assembly code. Note the use of the mask
LEDMASK. Changing its value allows you to access the different bits of the port. Also note
the use of bitwise operators OR, AND and COMPLEMENT (|,&,~) to configure the bit or bits
appropriate register.

Select
/* Direct Blink: Direct access and bit by bit via pointers */
Port B bit 0 is connected to connector D8

#define LEDMASK 0x01

void setup()
{
unsigned char* portDDRB;
portDDRB=(unsigned char*)0x24;
Configure the pin as output
*portDDRB|=LEDMASK;
}

voidloop()
{
unsigned char* portB;
portB=(unsigned char*)0x25;

Turn on the LED


*portB|=LEDMASK;
delay(2000);

Turn off the LED


*portB&=(~LEDMASK);
delay(1000);
}
Type the code above and connect the NPN transistor circuit to connector 8 of the Arduino.
Compile the code, then upload it to test. It should work like the program.
previous.

Editorial note: access to the registers

According to the documentation (datasheet) of the ATmega 328P:

The I/O registers are located between addresses 0X0020 and 0x005F:

The connector 8 of the Arduino Uno is connected to Port B, bit 0.

To configure the connector 8 of the Arduino Uno as an output, you need to access the register of
data direction selection at address 0x0024:
If the DDB0 bit is set to 1, PB0 is configured as a digital output.

We can then configure the state of the connector to high or low using the data register at
the address 0x0025 :

If the PORTB0 bit is 1, the PB0 output is high.

We can improve the Direct Blink program with a new version using macros.
predefined as PORTB. These are defined in a header file, and can therefore be
adjusted for any device. This makes the code portable across an entire family of microcontrollers
rather than having a specific code for each unit. And as you will see, the code
tends to be easier to read.

Select
Direct Blink 2: Direct access and bit by bit through predefined variables.
*/

Mask corresponds to port B bit 0, connector D8 of the Arduino


#define LEDMASK 0x01

void setup()
{
Configure the pin as output
DDRB |= LEDMASK;
}

voidloop()
{
Turn on the LED
PORTB |= LEDMASK;
delay(2000);

Turn off the LED


PORTB &= (~LEDMASK);
delay(1000);
}

Type the code above, compile it, and upload it to the Arduino to test it. It should also
function as before.

All versions of this program can be improved and extended to control multiple
logical outputs, each connected to a different device. For example, an output
could control an LED while another drives a relay or a power transistor to
activate a motor. By using the Direct Blink 2 version, you will be able to control multiple outputs
in a single instruction, simply by an appropriate masking operation. Try the quick one.
next experience: modify LEDMASK with the value 0x21 in the Direct program
Blink 2 to control the surface-mounted LED on the board and the external LED in tandem.

Editorial Note

The D8 connector that controls the external LED is connected to port B bit 0 (PORTB0) of the microcontroller.
and the D13 connector that drives the surface-mounted LED on the Arduino board is connected to port B bit
5 (PORTB5).

The appropriate mask to drive the two LEDs in tandem is:

Select
#define LEDMASK (0b00000001 | 0b00100000)
let LEDMASK=0x21

We then turn on both LEDs simultaneously by writing:

Select
PORTB |= LEDMASK; // Turn on both LEDs simultaneously

It is quite common to want to control several outputs simultaneously, but it is also


it is possible to individually configure each output by manipulating the bits one by one by inserting
a delay between each modified bit. It's a somewhat clumsy method, which is
neither particularly precise nor flexible when many outputs need to be controlled. But
We will examine the appeals later.

Editorial note

If we take back the control of the two previous LEDs, we can turn on each one individually.
LED :

Select
mask for the external LED, connector D8
#define LEDMASK1 0b00000001

Mask for the surface-mounted LED, connector D13


#define LEDMASK2 0b00100000

To light up both LEDs, one after the other:

Select
PORTB|=LEDMASK1;// turn on the external LED
// delay(10);
PORTB|=LEDMASK2;// turn on the surface-mounted LED

Challenge

Create a program that will alternately blink two LEDs, one red and one green.
When the red LED lights up, the green one must turn off and vice versa, when the green LED
lights up, the red one must turn off. The red LED must remain on for two seconds, and
the green one must stay on for one second. At no time should the two LEDs be
turned on simultaneously or turned off simultaneously (or at least, it should not be noticeable
by the ordinary human eye). This blinking pattern will have to repeat again and again: the LED
red lit for two seconds, green for one second, red for two
seconds, the green for one second, and so on.

You might also like