Sunteți pe pagina 1din 15

El Registro PORT (Puerto) en Arduino

En este post veremos qu son los PORT y cmo se utilizan. Al final


lograremos manipular en bajo nivel y de manera ms rpida los contactos
de entrada/salida del microcontrolador de las placas Arduino.
Los pines usados en la placa Arduino (el ATmega8 y el ATmega168) poseen
tres puertos (El ATmega328 (Arduino Uno) usa la misma configuracin de
pines que el ATmega168):

B (pines digitales del 8 al 13)

C (entradas analgicas)

D (pines digitales del 0 al 7)

Puertos que posee el Arduino ATmega328


Para ms detalles sobre cmo estn mapeados los nmeros de los pines de
Arduino a los puertos y los bits observa la siguiente imagen:

Nmeros de los pines de Arduino a los puertos y los bits.


El Arduino Mega presenta varios puertos B,C,D,E,F, etc.
Cada puerto es controlado por tres registros, los cuales tambin estn
definidos como variables en el lenguaje del Arduino.

El registro DDR, determina si el pin es una entrada o una salida.

El registro PORT controla si el pin est en nivel alto o en nivel bajo.

El registro PIN permite leer el estado de un pin que se ha configurado


con entrada usando la funcin pinMode().

Los registros DDR y PORT pueden ser ambos, escritos y ledos. El registro
PIN corresponde al estado de las entradas as que solo puede ser ledo.
El PORTD mapea los pines digitales del 0 al 7

DDRD El registro de configuracin del modo de los pines del puerto


D lectura/escritura

PORTD Registro de datos del puerto D lectura/escritura

PIND Registro de pines de entrada solo lectura

El PORTB mapea los pines digitales del 8 al 13. Se debe recordar que Los
bits altos (6 & 7) estn mapeados a los pines del cristal de cuarzo y no
pueden ser usados. Estos son solamente accesibles en el Arduino Mini.

DDRB El registro de configuracin del modo de los pines del puerto


B lectura/escritura

PORTB Registro de datos del puerto D lectura/escritura

PINB Registro de pines de entrada solo lectura

El PORTC mapea los pines de entrada analgica del 0 al 5.

DDRC El registro de configuracin del modo de los pines del puerto


B lectura/escritura

PORTC Registro de datos del puerto D lectura/escritura

PINC Registro de pines de entrada solo lectura

Cada bit de estos registros corresponden con un solo pin; por ejemplo el bit
menos significativo de los registros DDRB, PORTB, y PINB hace referencia al
pin PB0 (pin digital 8)
Normalmente antes para declarar un pin lo hacamos de la
siguiente manera:
void setup(){
Serial.begin(9600);
pinMode(2,INPUT);
pinMode(3,OUTPUT);

void setup(){
Serial.begin(9600);
pinMode(2,INPUT);
pinMode(3,OUTPUT);
}
Entonces si quisiramos declarar 7 pines (desde el digital 0 al digital 7),
tendramos que repetir pinMode 7 veces. Al igual que escribir tendramos
que poner digitalWrite(pin,estado) pin 0 estado alto, pin 1 estado bajo, etc.
Al utilizar Registros PORT (Puerto) tenemos la ventaja de que con solo
una instruccin podemos declarar el pin como entrada o salida y tambin
podemos escribir, si lo queremos, como estado HIGH o LOW.
Para controlar cualquiera de los tres puertos, debemos usar dos
instrucciones.

Primera instruccin: se debe declarar en la estructura void


setup() y nos sirve para declarar si el pin se va a usar como INPUT o
como OUTPUT.

Dato Importante:
Los pines 0 y 1 son la transmisin serial (RX y TX respectivamente). Si
utilizas Serial.begin en alguno de esos 2 puertos; no tendrs
comunicacin serial. Cuidado con eso.
Ejemplo:
1 = OUTPUT

0 = INPUT

DDRX = B11111110;
donde X es la letra del puerto a usar (BCD). Sin embargo si queremos tener
comunicacin Serial tendramos que hacer esto:

DDRX = DDRX | B11111100;


Esta manera es ms segura ya que configura los pines del 2 al 7 como
salidas sin cambiar los pines 0 y 1, que como mencionamos son RX y TX
Para tener ms referencia de los operadores bit a bit tipo AND, visita el
siguiente post de Arduino:

Tutorial de operaciones con bits.

Tenemos el siguiente cdigo:


B11111110;
Colocamos B, porque el nmero a marcar es Binario. Para ampliar ms
sobre los tipos de datos en Arduino visitemos el siguiente blog:

Tipos de Datos en Arduino.

Para saber el estado que le daremos al pin siempre lo pondremos


escribiendo de derecha a izquierda.
Nmero 1
a
marcar

Ubicaci 7
n del
pin en
Arduino
.

Segunda instruccin: es la escritura del puerto (esta variar en


funcin del programa que estemos desarrollando). Lo localizamos en
la funcin void loop().

Ejemplo:
1 =HIGH

0 = LOW

PORTX= B11111110;
En este ejemplo los pines del 1 al 7 permanecern encendidos (HIGH) y el
pin 0 LOW. Veamos un ejemplo aplicando estos conceptos:
En este ejemplo lograremos que durante dos segundos todos los leds
enciendan, durante dos segundos ms alumbren los impares y durante dos
ms todos se apaguen. Veamos:
Configuracin Utilizada:

Configuracin Utilizada para este proyecto.


Abrimos Arduino IDE y escribimos el siguiente cdigo:
int contador=0;//declaramos la v
void setup(){
DDRD= B11111100;//Utilizamos

int contador=0;//declaramos la variable interna como contador.

void setup(){
DDRD= B11111100;//Utilizamos D porque es del 0 al 7 y B porque es
Binario.
//En este ejemplo no utilic los pines 0 y 1 del Arduino.
/*Esta instruccin es lo mismo que hacer esto:
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT); */
}

void loop(){
for (contador=0; contador <3; contador ++){//establecemos contador
menor que 3 porque solo son 3 casos.
switch(contador){
case 0:
PORTD= B11111111;//aqu encenderemos todos los leds
delay(2000);
case 1:
PORTD= B10101010;//aqu encenderemos solo los impares.
delay(2000);
case 2:
PORTD= B00000000;//aqu los apagaremos todos.
delay(2000);
}
}
}
Para ver otro ejemplo utilizando Registro PORT (Puerto), visitemos el
siguiente post:

Control de Display 7 Segmentos mediante Pulsadores.

Ventajas y Desventajas que nos ofrece al utilizar el Registro PORT


(Puerto):
Desventajas:

El cdigo es mucho ms difcil de depurar y mantener, y es


mucho ms difcil de entender para la gente. Solo lleva algunos
microsegundos al procesador ejecutar cdigo, pero podra llevarte
horas descubrir por qu no funciona y arreglarlo.

Es mucho ms fcil causar mal funcionamiento no intencionado


usando el acceso directo a un puerto. Observa como la lnea DDRD =
B11111110, de arriba, menciona que el pin 0 se debe dejar como
una entrada. El pin 0 la lnea de recepcin (RX) en el puerto
serial.Podra ser muy fcil causar que tu puerto serial deje de
funcionar por cambiar el pin 0 a una salida.

Ventajas:

Puede que puedas cambiar los pines de estado muy rpido, en


fracciones de microsegundos. Las funciones digitalRead() y
digitalWrite() son cada una cerca de una docena de lneas de cdigo,
lo cual al ser compilado se convierte en unas cuantas instrucciones
mquina.

Cada instruccin maquina necesita un ciclo de reloj a 16MHz, lo cual puede


sumar mucho tiempo en aplicaciones muy dependientes del tiempo. El
Registro PORT (Puerto) puede hacer el mismo trabajo en muchos menos
ciclos de trabajo.

Algunas veces necesitamos configurar muchos pines


exactamente al mismo tiempo. Por lo que usar las funciones
digitalWrite (10,HIGH), seguida de la funcin digitalWrite (11,HIGH),
causar que el pin 10 se ponga en nivel alto varios microsegundos
despus que el pin 11, lo cual puede confundir circuitos digitales
conectados al Arduino, cuyo funcionamiento dependa del tiempo
preciso del cambio de esos bits.

Si te ests quedando sin memoria para tu aplicacin, puedes usar


estos trucos para hacer que tu cdigo sea ms pequeo. Usando
este mtodo se necesitan muchos menos bytes de cdigo compilado
que si se hace un bucle para que se vaya cambiando cada pin uno
por uno.

Mapear Puertos de Arduino


julio 31, 2015 Gustavo Circelli Arduino, Electrnica, Programacin, Proyectos
con Arduino
Mapear puertos en Arduino es una tcnica muy utilizada en
programacin para facilitar la generacin posterior de cdigo.
En algunas situaciones requerimos la posibilidad de mapear una cierta
cantidad de bits en forma directa a los puertos de Arduino o de un
microcontrolador en general, por ejemplo modificar el estado de una cierta
cantidad de salidas digitales a partir de algn mtodo, que nos permita
enlazar ( lo que llamo mapear) un bit de una variable de cdigo con un bit
fsico de los puertos.
Supongamos que necesitamos controlar 12 pines digitales de salida de
nuestro Arduino , para lo cual ya conocemos que deberamos utilizar
digitalWrite(pin, LOW/HIGH) para cada uno de los pines de salida.
Arduino simboliza los pines digitales desde el 0 al 13 , lo que nos facilita la
construccin de Sketches hardcodeando el cdigo. Hardcodear significa
hacer referencia en el cdigo en forma directa a un pin fsico especfico de
nuestro Hardware. Cuando hacemos digitalWrite(3,HIGH) estamos
hardcodeando, es decir refirindonos al pin fsico 3 de nuestro Arduino Uno
y mas precisamente el bit PD3 del PORTD.
Mapeo de los pines en el Atmega328
El micro Atmega328 o 168 que utiliza Arduino poseen los siguientes puertos
con la consiguiente simbologa en lo que respecta al Hardware de este chip:

Hardware Chip Atmega328, mapear ports


Ciertos aspectos de lo que se ver en esta entrega ya fue tratado en otra
entrada dentro de este mismo sitio. Para ms informacin consultar: El
registro PORT (puerto) Arduino
Si consideramos solo los pines digitales del 0 al 13, podemos extraer la
siguiente tabla de relaciones entre los pines digitales de Arduino y su mapeo
en los PORTS fsicos del Atmega328:

PortD y PortB de Arduino


Donde PDx y PBx son los puertos D y B del Atmega que indican los bits
asociados a cada Puerto. Por ejemplo PD0 es el bit0 del PuertoD.
Planteo
Imaginen ahora que poseo conectados 12 Leds a cada pin con excepcin de
los pines 0 y 1 que se utilizan para el Serial del monitor de Arduino, y los
dispongo de la siguiente manera:

Mapear el Problema presentado


Sabemos que en Arduino el mapeo previo de los pines es el siguiente:
dp0: rx, dp1: tx, dp2 PD2 , dp3 PD3, dp4:PD4, dp5 PD5, dp6 PD6, dp7 PD7,
dp8 PB0, dp9 PB1, dp10 PB2, dp11 PB3
dp12 PB4, dp13(led13 Arduino) PB5.
Hay un libro muy interesante que trata el Hardware interno del Atmega pero
muy entendible donde trata adems el acceso a este Hardware con el
lenguaje del skecth de Arduino lo que lo hace muy til. Introduction to
Embedded Systems: Using ANSI C and the Arduino Development
Environment (Synthesis Lectures on Digital Circuits and Systems).
Se me ocurrieron Leds para facilitar la explicacin, pero podran ser
cualquier tipo de otros dispositivos digitales.
Mi deseo es crear una funcin que podamos utilizar en nuestros sketches y
que me permita modificar el estado de los 12 Leds sin tener que recurrir a
las ya conocidas digitalWrite().
La funcin o Mtodo de mapeo
Mi funcin podra ser algo como esto
escribirLed(0b1111111111110000);
Como podrn notar la indicacin 0b indica que es un numero en formato
binario y cada bit representa el estado de cada led, en este caso todos
ON=1.
El formato del mtodo es el siguiente:
escribirLed(0bLed1 Led2 Led3 Led4 Led5 Led6 Led7 Led8 Led9
Led10 Led11 Led12); donde Ledx representa el Nmero led cuyo valor
puede ser 1 ON o 0 OFF
Implementacin
Como primera medida el valor a pasar es un tipo de dato de 2 Bytes,
entonces en Arduino podramos utilizar el unsigned int , de manera que el
prototipo de mi mtodo sera:
void escribirLed( unsigned int le
{ . }

void escribirLed( unsigned int leds)

{ . }
El mtodo deber ir tomando cada bit de la posicin del valor pasado como
variable Leds a la funcin y mapear directamente su valor al Port que
corresponda y en la posicin que corresponda. Por ejemplo si Leds
=0b100.., el Led1 est en ON y por lo tanto dicho 1 deber ser
escrito en el PortD en el tercer bit = PD2.
Si observamos el PortD es un Byte (8bits), al igual que el PortB, aunque
este ltimo solo usa 5 bits. En la siguiente tabla vamos a representar la
variable leds (16 bits), el PORTD(8bits), PORTB(5 bits) y una variable
auxiliar (aux) tipo byte de 8 bits
Se puede apreciar el MSB o byte ms significativo que es la parte alta o
Nible Alto de la variable leds y el LSB o byte menos significativo o Nible
Bajo de la variable leds. El MSB de los PortD/B no existen.

Relacin de mapeo entre Variables de cdigo y Ports Fsicos


Cmo hacemos entonces por ejemplo para llevar el BIT15 de la variable
leds que representa el LED1 , al BIT2=PD2 del PuertoD ?,.. en eso se
resume lo que va a hacer nuestro mtodo, no solo con LED1 sino con el
resto. Para esto hay que ir analizando pin a pin.
Vamos a utilizar las funciones que provee implementadas en el compilador
de Arduino y que son las de desplazamiento de bits.
Crearemos una variable local, dentro del mtodo, evitando el uso de
Globales y optimizar memoria, ya que las Locales se destruirn al no
ejecutarse el mtodo y se crearn temporalmente dentro de nuestro mtodo
de mapear.
Vamos a explicar para el caso del LED1. Creamos la variable byte Led1; y
otra variable auxiliar del tipo byte aux,.
aux= leds>>8; es decir que en aux ahora se guardaran los bits resultado
de desplazar a la derecha 8 posiciones a la variable leds, esto es el BMSB
( Byte ms significativo de leds) y que contiene desde el LED1 al LED8.

variable byte aux para mapear PORTD


Si observamos ahora, LED1 en aux y LED1 en PortD, hay 5 espacios a la
derecha, de esta manera hacemos:
led1= (aux >>5) & 0b00000100; logrando que led1 ya creada, tenga el
estado solo del LED1, esto es 0 o 1. La operacin AND con 0b00001000,
permite descartar y asegurarse que solo el bit2 de aux tenga el valor del
Led1. La operacin AND se realiza bit a bit, de manera que 1.0=0 y 1.1=0.
De la misma manera observamos que :

led2=(aux>>3) & 0b00001000; desplazo 3 a la derecha

led3=(aux>>1) & 0b00010000; desplazo 1 a la derecha

led4= (aux<<1) & 0b00100000; desplazo 1 a la izquierda

led5=(aux <<3) & 0b01000000; desplazo 3 a la izquierda

led6=(aux<<5) & 0b10000000; 5 a la izquierda

Hasta aqu tendremos logrado casi el mapeo en el PortD , cada variable


ledx posee el estado de cada led, solo resta mapearlos en el puerto.
Para esto creamos otra variable byte puertoD=0; y hacemos lo siguiente
puertoD=puertoD | led1|led2|led3|led4|led5|led6; puertoD se armar
realizando las sucesivas operaciones OR bit a bit . Para ilustrar el caso
supongamos que cada variable tenga seteado su bit
led1=00000100,
led2=00001000,led3=00010000,led4=00100000,led5=01000000 y
led6=10000000
Haciendo OR bit a bit portD=0B111111xx , el xx que queda son los bit de
rx y tx y que no debemos afectar su valor. Antes de escribir
directamente al PortD debemos cuidar de no afectar el valor de rx, tx. Para
esto creamos una variable byte d; que va a leer los bits del PortD , de la
siguiente manera:

d= PIND; esta es una macro con acceso directo solo a la lectura del
PortD. En el tutorial mencionado antes El registro PORT (puerto)
Arduino , se describe muy bien. Para resumir, cada puerto del
Arduino B,C y D, existen macros para su acceso directo de la forma:

DDRx lectura escritura del registro de direccin (entrada o salida


digital) del Port x

PORTx lectura escritura sobre el puerto x

PINx lectura de los pines del puerto x.

En mi caso utilic PINx para la lectura del PortD y as ver en qu estado


estn los pines rx y tx.
Lo que hacemos ahora finalmente es
d=d&0b00000011; nos interesa rescatar solo los pines 0 y 1, su estado,
AND 00000011
puertoD=puertoD|d; Hacemos OR bit a bit entre puertoD y d y guardamos
en la misma variable , ahora est completo con el estado de los Leds y el
estado real de rx/tx sin afectar
PORTD = puertoD; / escritura final al puerto D.
Resta ahora poder mapear los leds restantes del 7 al 12 sobre el PortB de
PB0 a PB5.
Si volvemos a ver la tabla con la variable leds, PortD y PortB, y la variable
aux que tenamos como resultado de leds>>8 , el LED7 deber ir al PortB
PB0 y el LED8 al PB1.
Para lograr esto hacemos:

led7=(aux>>1) & 0b00000001;

led8=(aux<<1) & 0b00000010;

Con lo cual ya nos quedan formateadas las variables led7 y 8 con la


posicin, al igual que los leds del 1 al 6 ya analizados.
El LED9 ya no lo podemos recuperar de la variable aux ya que posee 8 bits
y el LED9 est en una novena posicin que no existe, por este motivo
hacemos:
Aux=leds; y aqu viene lo divertido, al igualar un byte a un int , la
informacin se recorta ya que aux solo tomar el LSB de la variable leds, y
de esta manera el nuevo aux queda como sigue:

Variable byte aux para mapear PORTB


Luego.

led9=(aux>>5) & 0b00000100;

led10=(aux>>3) & 0b00001000;

led11=(aux>>1) & 0b00010000;

led12=(aux<<1) & 0b00100000;

Creamos otra variable byte puertoD y la armamos con la OR entre lo leds


que faltan.
puertoB=puertoB|led7|led8|led9|led10|led11|led12;

y finalmente enviamos la informacin al PuertoB


PORTB = puertoB & 0b00111111; con la mscara de esos 6 bits que nos
interesan
Con esta explicacin ya podrn seguir el cdigo completo, para lo cual les
dejo el mismo para este del mtodo. Este mtodo es muy til, por ejemplo
lo estoy usando para hacer un cubo de leds de 33.
Esta es una manera de hacerlo, puesto que en lugar de desplazar
previamente aux , 8 posiciones a la derecha, quizs otro mtodo podra ser
lograr desplazamientos acordes al bit a mapear, por ejemplo si tomo LED1
,y desplazo 13 posiciones a la derecha la variable leds y lo
guardo directamente en la variable led1 ya estaramos en la posicin:

led1=(leds>>13) & 0b00000100, ya estara.

led2=(leds>>11) & 0b00001000; led3=(leds>>9) &


0b00010000; led4=(leds>>7) & 0b00100000;

led5=(leds>>5) & 0b01000000; led6=(leds>>3) &


0b10000000; led7=(leds>>9) & 0b00000001;

led8=(leds>>7) & 0b00000010; led9=(leds>>5) &


0b00000100; led10=(leds>>3) & 0b00001000;

led11=(leds>>1) & 0b00010000 y led12=(leds<<1) &


0b00100000.

Como ven este otro enfoque es mas sinttico e incluso se podra optimizar
usando vectores ya que los desplazamientos son impares, entonces se
podra usar una variable ndice que incrementara en forma impar, pero esa
es otra historia. La idea aunque parece rebuscada fue la mejor manera de
explicar que encontr para mostrar el tema de las posiciones en variables y
puertos de diferente tamao.
void escribirLed2( unsigned int
{
/*

void escribirLed2( unsigned int leds)


{

/*
Esta funcion mapea los pines del 2 al 10 que son Led 1 al 10 en los puertos
PORTD y PORTD
PORTD =dp7,dp6,dp5,dp4,dp3,dp2,tx,rx
=L6, L5, L4,L3, L2, L1, x, x

PORTB = x,x,dp13, dp12, dp11 , dp10,dp9, dp8


= x,x,L12,

L11,

L10, L9 , L8 , L7

El parametro a pasar de lafuncion es el estado de los 9 bits


0bL1,L2,L3,L4,L5,L6,L7,L8,L9,L10,L11,L12,x,x,x,x es in int 16 bits

*/
byte led1,led2,led3,led4,led5,led6,led7,led8,led9,led10,led11,led12;
// variables que van a mapear el estado en los puertos D y B
byte puertoD=0;
byte puertoB=0;
byte aux;
byte d; // la lectura del byte del puerto D
aux=leds>>8; // BLSB del int tiene la info de los leds 2 al 8
led1= (aux >>5) & 0b00000100;
led2=(aux>>3) & 0b00001000;
led3=(aux>>1) & 0b00010000;
led4= (aux<<1) & 0b00100000;
led5=(aux <<3) & 0b01000000;
led6=(aux<<5) & 0b10000000;
//Serial.println(aux,BIN);
led7=(aux>>1) & 0b00000001;
led8=(aux<<1) & 0b00000010;
// hasta aqui se mapearon del led 1 al 8 donde se desplazo el MSB de leds
al LSB de aux
// nuevo
aux=leds; // aux tiene el LSB de leds : L9,L10,L11,L12,x,x,x,x
led9=(aux>>5) & 0b00000100;
led10=(aux>>3) & 0b00001000;
led11=(aux>>1) & 0b00010000;
led12=(aux<<1) & 0b00100000;
puertoD=puertoD | led1|led2|led3|led4|led5|led6;
puertoB=puertoB|led7|led8|led9|led10|led11|led12;
d=PIND; // d lee el puertoD esto es para no afectar la escritura de rx/tx bit

1y0
d=d&0b00000011;
puertoD=puertoD|d;
PORTD = puertoD; // escritura al puerto D
PORTB = puertoB & 0b00111111;

S-ar putea să vă placă și