Arduinoplatformiovscode
Arduinoplatformiovscode
página 1 de 28
página 2 de 28
A continuación vemos el diagrama en bloques del ATMEGA328P en le cual se muestra sus unidades
funcionales
página 3 de 28
Tensión de trabajo:
de 2.7V a 5.5V for ATmega328P
Rango de temperatura:
de –40°C a +125°C
Consumo de corriente:
Modo activo: 1.5mA para 3V a 4MHz
Modo Power-down 1μA a 3V
página 4 de 28
Ahora veámoslo desde elpunto de vista del Arduino
Placas Arduino
El arduino es una placa muy popular para diseño por lo que la misma tiene muchos modelos
Por ejemplo aquí discribiremos a los arduinos mas clasicos:
Arduino UNO:
Microcontrolador: ATmega328
Voltaje Operativo: 5v
Voltaje de Entrada (Recomendado):7 – 12 v
Pines de Entradas/Salidas Digital:14 (De las cuales 6 son salidas PWM)
Pines de Entradas Análogas:6
Memoria Flash:32 KB (ATmega328) de los cuales 0,5 KB es usado por Bootloader.
SRAM:2 KB (ATmega328)
EEPROM:1 KB (ATmega328)
Velocidad del Reloj:16 MHZ.
Sabiendo que hay arduinos que tienen microcontrolador ATMEG328 con encapsulado TQFP y
QFN/MLF tiene 8 canales de conversión A/D y los que tiene encapsulado PDIP tienen 6 canales, sin
embargo los ARDUINOS UNO solo tiene 6 canales de conversión A/D tenga con cualquier tipo de
encapsulado para el microcontrolador.
página 5 de 28
A continuación veamos al Arduino UNO y la relación de las señale con los puertos del ATMEGA328
Arduino NANO:
página 6 de 28
A continuación observemos dos vistas del Pin Out, aquí se ve una de ellas
en la cual vemos que también están disponibles las entradas para canales de conversión A/D ADC6
y ADC7.
página 7 de 28
Aquí vemos otra vista del mismo
Programación de ARDUINO
Hay varias formas de programarlos, mediante el IDE de ARDUINO o mediante editores
https://www.youtube.com/watch?v=5sn4L_y3ncA
página 8 de 28
primero vamos a utilizar las funciones nativas de Arduino, mas adelante pero muy pronto veremos el
manejo desde el punto de vista de los puertos de E/S y sus bits
sintaxis:
pinMode(pin,modo):
Configura el pin especificado por su número indicado en el parametro pin para comportarse como lo
indica el parámetro modo
ejemplos:
pinMode(2,INPUT);
pinMode(4,INPUT_PULLUP);
pinMode(8,OUTPUT);
sintaxís:
digitalWrite(pin, valor);
página 9 de 28
LOW o 0 para envíar un 0 a la salida
Ejemplos:
digitalWrite(6,HIGH);
o
digitalWrite(6,1);
digitalWrite(11,0);
o
digitalWrite(11,LOW);
sintaxis:
valor = digitalRead(pin);
En la cual valor es el valor lógico que entro por el pin configurado como entrada o el último valor
almacenado
en un pin configurado como salida.
Ejemplo:
sensor=digitalRead(3);
Para cambiar el estado del pin digital de salida 7 mostramos el siguiente tramo de código
vaux=digitaRead(7);
vaux=vaux^1; //transforma 0 en 1 0 1 en 0
digitalWrite(7,vaux);
La función delay:
página 10 de 28
Detiene el programa un tiempo determinado expresado en milisegundos
sintaxis:
delay(nmilisec);
La función delayMicoseconds:
Detiene el programa un tiempo determinado expresado en microsegundos
sintaxis:
delayMicroseconds(nmicrosec);
Ejemplo:
Se dispone de 1 pulsador pin digital 3. . También hay un de un led conectado en el pin digital 10.
El funcionamiento será el siguiente:
Al accionar el pulsador se debe apagar el LED y si se suelta se debe prender,(el led esta
inicialmente prendido
void loop()
{dpuls1=digitalRead(PULS1);
digitalWrite(LED1,dpuls1)
}
página 11 de 28
Como el pulsador está conectado en modo PULLUP el led estara prendido por hacer una
tranferencia directa al mismo
Como hacemos lo mismo pero manejandonos con los puertos del ATMEGA328
Los registros DDRx sirven para programa el sentido de transferencia de los bits de los puertos, es
decir si son de entrada o de salida
Los registros PORTx sirven enviar datos hacia la de salida o leer su estadon configurados los bits
como salida
Los registros PINx sirven recibir datos desde la entrada estando configurados sus bits como entrada
un 1 en un bit del registro DDRx configura el bit correspondiente del PORTx como salida
un 0 en un bit del registro DDRx configura el bit correspondiente del PORTx como entrada
pero utiliza para la lectura al registro PINx
página 12 de 28
Vemos que:
el pin digital 3 esta ubicado en el bit 3 del PORTD
el pin digital 10 esta ubicado en el bit 2 del PORTB
Primero configuremos el bits 3 del PORTD como entrada y el resto como salida y luego al bit 2 del
PORTB como salida y le resto como entrada, esto se hace para ver bien clara la diferencia
DDRD=0b11110111;
DDRB=0b00000100;
(0b delante del número significa que el número que sigue es binario)
En este microcontrolador para activar el modo PULLUP de los bits de entrado se requiere se envíe
un 1 al bit configurado como entrada
PORTD=0b00001000;
#include <Arduino.h>
unsigned char bitl;
void setup() {
DDRD=0b11110111;
página 13 de 28
DDRB=0b00000100;
PORTD=0b00001000;
}
void loop() {
Veamos que este 1° ejemplo es muy tosco por no tener en cuenta el estado de los otros bits de
ambos puertos
Ya vimos que se usan los registros DDRB, DDRC y DDRC para los puertos respectivos que tienen la
misma letra final y además un 1 configura un bit corresponiente del puerto como salida y un 0 lo hace
como entrada
ejemplo 1)
En el puerto B se quieren configurar los bits 0 y 2 como entradas y el 7 y 5 como salidas
los otros bits no interesan:
Por lo dicho anteriormente hay que usar el registro DDRB
Un gráfico del como quedan los bits del regsitro DDRB se muestra a continuación
7 6 5 4 3 2 1 0
DDRB 1 x 1 x x 0 x 0
En los cuales la x significa estado indiferente, pero como algo hay que ponerle si le ponemos 0
el DDRB nos quedará así:
7 6 5 4 3 2 1 0
DDRB 1 0 1 0 0 0 0 0
DDRB=0b10100000;
página 14 de 28
Pero la anterior forma es tosca pues no tiene en cuenta un posible estado anterior de los otros bits
pues los configura forzosamente como entradas.
Veamos ahora un método que deja el estado de los otros bits como estaban,
es el método del enmascaramiento
DDRB=(DDRB | 0b10100000);
en la cual el operador | efectúa la operación Or lógica entre los bits del DDR y dato binario
10100000 que tiene en 1 a los bits correspondientes a configurar como salida en el DDRB y el resto
e 0 y como resultado final los bits 7 y 5 se pondrán en 1 independientemente de su estado pues or
entre 1 y cualquier otro estado da simpre 1.En cambio en los otros bits el or entre estos y 0 dará 0 si
valia 0 a 1 si valía 1 por lo tanto los deja inalterados. Para mas claridad veamos un ejemplo numérico
Al dato que sirve para establecer los estados lo denominarémos máscara1
7 6 5 4 3 2 1 0
DDRB 0 1 1 1 0 1 1 0
mascara1 1 0 1 0 0 0 0 0
DDRB | mascara1 1 1 1 1 0 1 1 0
Y se muestra en rojo que los bits 7 y 5 están en 1 independientemete del resto de los bits
Ahora vamos a configurar a los bits que tienen que ser configurados como entradas,
vemos ahora que la máscara tiene 0 el la posición de los bits a configurar como entradas y 1 en los
restantes y además la operación es la AND lógica:& y como resultado final los bits 2 y 0 se pondrán
en 0 independientemente de su estado pues AND entre 0 y cualquier otro estado da siempre 0.En
cambio en los otros bits el and entre estos y 1 dará 0 si valia 0 o 1 si valía 1 por lo tanto los deja
inalterados: Si aplicamos estos al resultado del ejemplo anterior siendo que ahora la máscara se
denominará mascara0
7 6 5 4 3 2 1 0
DDRB 1 1 1 1 0 1 1 0
mascara0 1 1 1 1 1 0 1 0
DDRB & mascara0 1 1 1 1 0 0 1 0
página 15 de 28
Viendo de nuevo que los bits que estásn en rojo son los que cambiamos dejando inalteraros al resto
de los bits
En dicho modo si el pulsador SW1 se acciona se produce un circuito cerrado que envía a
tierra al pin del microcontrolador,(0 volts), por lo tanto este recibe el estado lógico 0.
Si el pulsador se levanta el pin recibe practicamente 5 v atravez de la resistencia R1,(esto
es así porque la corriente que circula por la misma es muy baja y no genera caída de
tensión sobre ella, por lo tanto el pin recibe el estado lógico 1
Este y otros microntroladores tienen la posiblidad de programar las resistencias de PULLUP la que
de denomina ressistencia de PULLUP programada, y la hacelo evitamos poener una resistencia
externa. Si se quiere activar las resistencia de PULLUP en un bit configurado como entradad se debe
escribir un 1 al bit del puerto corresponiente,(no del DDRX)
Para nuestro ejemplo anterior si queremos que los dos bits de entrada tenga resistencia de PULLUP
programada
PORTB=(PORTB | 0b00000101);
página 16 de 28
Lectura de un bit de entrada
En este caso debemos usar la técnica de enmascaramiento no para cambair el estado de un bit sino
para determinar el estado del mismo, para ello el microcontrolador ATMEGA328 usa los regsitros
PINX en ekl cual la X es la letra del puerto corresponiente es decir PINB para el PORTB, PINC para
el PORTC y PIND para el registro PORTD
Por ejemplo determinemos el estado del bit 2 del ejemplo anterior
orden en la cual si el bit 2 vale 0 el AND dara 0 y este se asignará a la variable bitl, pero se vale 1
se asignará un valor distinto a 0 en la variable bitl, por eso le procedimiento se completa con un if
if(bitl != 0)
{
Entonces con este ejemplo podemos modifica el ejemplo anteriormente visto para que no modifique
ninguna configuración anterior
página 17 de 28
#include <Arduino.h>
unsigned char bitl;
void setup() {
DDRD=(DDRD & 0b11110111);//configura solo el bit 3 del PORTD como entrada
DDRB=(DDRB | 0b00000100);//configura solo el bit 2 del PORTB como salida
PORTD=(PORTD | 0b00001000);//activa la R de PULLUP interna del bit 3 del PORTD
}
void loop() {
Ejercicios de repaso
1. Configurar el bit 5 del puerto C como salida y el bits 4 del PORTD como entrada
2. Configurar los bits 3 y 4 del puerto D como salidas y los bits 0 y 5 del puerto B como entradas
3. Modificar el ejemplo anterior para que el bit de entrada que tiene conectado el pulsador sea el
bit 0 del PORTB y el de salida que tiene conectado el ledesea el 2 del PORTD y que además
el led se inice apagado y al accionar y mantener accionado el pulsador se encienda
Como vimos anteriormente si queremos por ejemplo escribir un 1 en el bit 3 del PORTB sin cambiar
los otros bits
PORTB=(PORTB | 0b00001000);
pues la operación OR en este caso no configura, sino escribe un 1 en el bit 3 del PORTB,pues la
operación OR con 1 da siempre un 1 y la operación OR con 0 deja inalterados los otros bits.
página 18 de 28
en la cual el operador ~ invierte cada bit de las mascara con 1 en el bit a poner a 1 y la transforma
en la máscara de la sentencia que está mas arriba. Esto último sera muy util en el tema que viene a
continuación
if(bl4 !=0)
{
//hacer algo para el caso en que e bit 4 es 1
}
else
{
// hacer algo para el caso en que e bit 4 es 0
}
Al efectuar la operación AND lógica entre el registro PINB y un dato que tenga todos los bits en 0
menos el que quiero inspeccionar en 1, si dicha operación da 0 quier decir que el bit vale 0, pues el
and bits entre el 1 de la posición 4 y el bit 4 da 0 si ese bit vale 0. En cambio si el and lógico da
distinto a 0 quiere decir que dicho bit vale 1. Si llamamos mascara4 al dato 00010000
7 6 5 4 3 2 1 0
PINB 1 0 0 1 0 1 1 1
mascara4 0 0 0 1 0 0 0 0
PINB & mascara4 0 0 0 1 0 0 0 0
página 19 de 28
mayor fuerza, la misma tendría la siguiente tabla
pasos F4 F3 F2 F1
1 0 0 1 1
2 0 1 1 0
3 1 1 0 0
4 1 0 0 1
5 0 0 1 1
Para que la situación sea mas complicada. Asumamos que los controloes de las fases no están en
bits concecutivos ni en un mismo puerto es decir
#include <Arduino.h>
void setup() {
DDRB=(DDRB | 0b00000001);
DDRC=(DDRC | 0b00000010);
DDRD=(DDRD | 0b00001000);
DDRB=(DDRB | 0b00100000);
//ahora ponemos a 0 cada bit
void loop() {
PORTB=(PORTB | 0b00000001);
PORTC=(PORTC | 0b00000010);
PORTD=(PORTD & (~0b00001000));
PORTB=(PORTB & (~0b00100000));
delay(1000);
página 20 de 28
delay(1000);
delay(1000);
PORTB=(PORTB | 0b00000001);
PORTD=(PORTD & (~0b00001000));
delay(1000);
}
Ejemplo en el cual se ve que si bien fijamos el estado inicial de todas la fases y luego cambiamos
solo las que pasan de 1 a 0 o viceverza el programa es engorroso e inmanejable
Primero veamos una forma elejante de armar las mascaras para un solo bit
por ejemplo para crear la máscara que controla al bit 5 del PORTB se puede poner
1<<5
pues el operador << aplicado a un número equivale a desplazamiento a izquierada tantos bits como
indica en número, es decir
PORTB=(PORTB | (1<<5));
PORTB=(PORTB | (1<<n));
prenderbit(PORTB,5);
página 21 de 28
Del mismo modo la macroorden para pone a 0 se escribiría así
apagarbit(PORTD,3);
#include <Arduino.h>
#define prenderbit(puerto,nbit) puerto=((puerto | (1<<nbit)))
#define apagarbit(puerto,nbit) puerto=(puerto &(~(1<<nbit)))
void setup() {
prenderbit(DDRB,0);
prenderbit(DDRC,1);
prenderbit(DDRD,3);
prenderbit(DDRB,5);
//ahora ponemos a 0 cada bit
apagarbit(PORTB,0);
apagarbit(PORTC,1);
apagarbit(PORTD,3);
apagarbit(PORTB,5);
}
void loop() {
prenderbit(PORTB,0);
prenderbit(PORTC,1);
apagarbit(PORTD,3);
apagarbit(PORTB,5);
delay(1000);
apagarbit(PORTB,0);
prenderbit(PORTD,3);
delay(1000);
página 22 de 28
apagarbit(PORTC,1);
prenderbit(PORTB,5);
delay(1000);
prenderbit(PORTB,0);
apagarbit(PORTD,3);
delay(1000);
}
Par el caso de la expresión para leer en estado del bit 4 del PORTB
Solo que en este caso sei el bit vale 0 pregunto por 0 pero si vale 1 pregunto por distinto a 0
Si queremos mas claridad a la hora de hacer el programa tal que si el bit vale 1 preguntemos por 1 y
se vale 0 preguntemos por 0 podemos utilizar la sentencia
if inline que tiene la siguiente forma:
en la cual si la pregunta es verdadera se resuelve exprev y se asigna a la variable resultado, por otro
lado si la pregunta es falsa se resuelve expref y se asigna a la variable resultado
por ejemplo:
x = 10;
y = x > 9 ? 100 : 200;
página 23 de 28
#define leerbit(puerto,nbit) (((puerto & (1<<nbit)) != 0) ? 1 : 0)
(NOTA:los paréntesis que engloban a toda la expresión se deben poner para que la
macro expasión funciones correctamente por el problema de la precendencia)
Veamos las 3 macros en un ejemplo anterior que hacia que un led siga esl estado de un pulsador
El cambio que hacemos es que el led está conectado en el bit 0 del PORTB,(pin digital 8) y el
pulsador está conectado en el bit 2 del PORDT,(pin digital 2) y tiene activada su resistencia de
PULLUP
#include <Arduino.h>
void loop() {
if(leerbit(PIND,2)==1)
prenderbit(PORTB,0);//pone a 1 solo el bit 0 del PORTB
else //sino
apagarbit(PORTB,0);//pone a 0 solo el bit 0 del PORTB
}
finalmente para mas practicidad nos conviene copiar las 3 macros en un archivo de cabacera y
luego la unimos en cada proyecto y la incluimos la podemos llamar manejodebits.h
y la misma contiene las tres macros,(el archivo los podemos crear desde el editor del VSCODE
con el menú file-new y luego lo tenemos que salvar en el directorio include del proyecto con dicho
nombre. Despues le compiamos las macros lo salvamos, incluimos el archivo de cabacera y el
proyecto nos queda ahora así:
página 24 de 28
#include <Arduino.h>
#include "manejodebits.h"
void loop() {
if(leerbit(PIND,2)==1)
prenderbit(PORTB,0);//pone a 1 solo el bit 0 del PORTB
else //sino
apagarbit(PORTB,0);//pone a 0 solo el bit 0 del PORTB
}
Si bien se puede invertir el estado de un bit utilizando las macoexpansiones vista es recomendable
tener una macroexpasión para invertir el estado de un bit, pues el operador lógico en lenguaje C
existe y se puede usar para tal motivo. Se trata del operador lógico bit a bit para implementar la
operación lógica OR Exclusiva o XOR, que se implementa con el caracter ^,(si es dificil tipearlo con
teclado se puede obtener tipeando ALT+94 del teclado keypad)
Poe ejemplo si queremos invertir el estado del bit 4 del PORTd escribimos
PORTD=(PORTD ^ 0b00010000);
expresión en la cual solo se invierte del PORTD los bit que se corresponden a los que en la máscara
valen 1 es decir solo el bit 4 para nuestro caso, pues la operación XOR entre un bit y 0 no cambia el
bit y la operación XOR con 1 si lo invierte
página 25 de 28
Entonces las macros sería ahora las siguientes
Por ejemplo si queremos configurar como salidas todos los bits del PORTC
DDRC=0b01111111;
(los bits son y 7 porque este puerto en el ATMEGA328 tiene disponibles los bits que van del 0 al 6, el
7 no existe)
Para configurar ahora como salidas los bits del PORTB que van desde en 0 a 5 sin tocar las otras,
(Pues en 6 y 7 estan las líneas que corresponden al oscilador a cristal XTAL1 y XTAL2
respectivamente)
DDRB=(DDRB | 0b00111111);
Por último si quermos configurar los bits 0 a 3 como entradas y 4, 5 como salidas recomiendo esta
forma porque son menos sentencias
página 26 de 28
Primero configuro los 4 primeros bits como entrada sin tocar los otros bits
y ahora configuro los bits 4 y 5 como salidas sin tocar los otros
DDRB=(DDRB | 0b00110000);
Igual este es un ejemplo de como configurar bits de un puerto sin tocar otros,(6 y 7 del PORTB en
este caso) pues las unidades funcionales como las del cristal tiene una configuración que es
prioritaria por sobre la que se logra con los DDRx y las seencias anteriores se pueden resumeir en
esta
DDRB= 0b00110000;
o esta
DDRB= 0b11110000;
DDRB= 0bxx110000;
Pero ahora veamos un caso en que si es importante mantener el estado de los bits que no tenemos
en cuenta
Conigurar los bits 1 a 3 del PORTB como salidas, el bit 5 como entrada y no tocar a los bits 0 y 4
(bits 6 y 7 son indiferentes)
DDRB=(DDRB | 0b11001110);
Por ejemplo para enviar el dato binario 1010011 al PORTC qu está totalmente configurado como
salida se ejecuta
PORTC=0b01010011;
página 27 de 28
Si el puerto esta configurado como entrada también se le pueden enviár datos pero esto equivale a
habilitar o desabilitar la resistencia de PULLUP interna
Tomemos de nuevo el PORTC y configuremos a los bits 0,1,2 y 6 como entradas y a los bits 3,4 y 5
como salidas
DDRC=0b00111000;
y ahora activemos las resistencias de PULLUP internas de los bits 0,2 y 6 y desactivemos
del del bit 1
PORTC=0b01000101;
Si ahora se necesitan leer varios bits que está ubicados en un mismo puerto también lo podemos
hace con una sola orden como lo hacíamos con un puerto de salida.
Por ejemplo:
Si queremos leer el dato de 8 bits que proviene del PORTB en forma completa y asignarlo a una
variable,(recordando que es estado de los bits 6 y 7 no tiene sentido
unsigned char A;
...
DDRB=0b00000000;
A=PINB;
Si queremos enviar el dato de 8 bits que proviene del puerto D,(configurado como entrada hacia el
puerto B,(configurado como salida)
PORTB=PIND;
página 28 de 28