This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
Manipulacion de puertos.
#1
Me estoy haciendo un reloj binario con un arduino nano y un ds3210 de esos
que marcan los minutos con 6 leds (1,2,4,8,16,32) y las horas con 4(1,2,4,8).Para los minutos uso el portb(pines digitales del 8 al 13) para activar los leds que marcaran la hora y para los minutos me gustaria hacer lo mismo con el portc ,pero tengo el problema de que el ds3231 esta conectado a los pines A4 y A5 de este port.Alguien sabe si podria modificar los 4 primeros pines del portc de una vez pero sin afectar los tres siguientes (sda,scl y rst)??
  Responder
#2
Puedes... debes hacer una mascara a la hora de tocar ese puerto para asi no sobreescribirle los valores.

Ahora mismo no se de cuantos bit es ese puerto pero asumiendo que tienes pines del A0 al A5 y el rst tienes en total 7 bits.

Para modificar el puerto sin tocar los bit 5 (A4) y 6(A5) deberias hacer algo asi:

PORTC = ( PORTC & B11110000 ) | (valorQueQuieresEnElPuerto & B00001111)

He usado una mascara de 8 bits. Lo que se hace con "PORTC & B11110000" es borrar el contenido de los bit 0 a 3 y dejar intacto el de los bits 4 a 7.

"valorQueQuieresEnElPuerto & B00001111" lo que hace es cargarse el contenido de los bit 4 a 7 de tu variable y dejar intactos los bit 0 a 3

Finalmente con el or | harias una suma logica de ambos operandos. Como has hecho dos operaciones and para limpiar lo sobrante de las variables te quedara una variable limpia y lista para ponersela al puerto.

Busca lo que son las mascaras, son muy utiles y necesarias cuando debes tratar con puertos directamente asi como cuando debes trabajar con bits en general. Recuerda que puedes aplicar mascaras de 8 bit a un puerto aunque dicho puerto solo sea de 7 bits o menos.
  Responder
#3
Gracias! de momento estoy probandolo con:
Código:
PORTC |= hour;//Donde hour es el valor de la hora entre 1 y 12.
y los minutos cambian bien ,luego supongo que no esta afectando la comunicacion i2c con el reloj..... Sonrisa Sonrisa Sonrisa Sonrisa Sonrisa Sonrisa Sonrisa Sonrisa
  Responder
#4
Ummm... no, eso no vale, te pondre unos ejemplos de por que:

Como aclaración, aunque supongo que ya lo sabes:
"PORTC |= hour" es lo mismo que "PORTC = PORTC | hour"

Teniendo en cuenta esto, ahora pasare a darle unos valores al puerto seguidos y veremos lo que ocurre haciendolo como lo haces:
Código:
PORTC = 0;   Le doy al puerto entero un valor de 0 para inicializarlo y ver que ocurre con los siguientes cambios

PORTC |= 1;  -> resultado = B00000001   -> Esto en binario es un 1
PORTC |= 2;  -> resultado = B00000011   -> Esto en binario no es 2, es un 3! Como el OR no vale para introducir 0s el valor no es correcto!
PORTC |= 3;  -> resultado = B00000011   -> Esto en binario es un 3, correcto.
PORTC |= 4;  -> resultado = B00000111   -> Esto en binario es un 7!! Mismo caso que con el 2

Como ves, haciendo un OR nunca vas a conseguir eliminar los 1 del puerto, por ejemplo en el ultimo caso el valor que tu deseas obtener en dicho puerto es B00000100 (un 4), pero como realizas una operacion OR con el valor anterior que es B00000011 (un 3) lo que obtienes al final es B00000111 (Un 7).

B00000011
B00000100
B00000111


Por tanto si lo quieres hacer bien necesitas si o si hacerte una mascara que primero te limpie los bit 0 a 3 y seguidamente te ponga en dichas posiciones el valor de tu variable hour.
Código:
PORTC = ( PORTC & B11110000 ) | hour
... o mejor esta otra, pues si hour tuviese un valor superior a 15 por alguna razon (B00001111 --> 15) sobreescribirias el 5 bit y la liamos (B00011111 --> 16)
Código:
PORTC = ( PORTC & B11110000 ) | (hour & B00001111)
Haciendo esto nos aseguramos de que incluso aunque nos equivoquemos al programar no tocamos ningun pin que no debamos.





Por cierto, como extra. En el arduino nano los bit 0 y 1 del PORTD son los bit del RX y TX de tu arduino, por tanto mucho ojo al escribir variables directamente sobre ese puerto, pues probablemente interfieras con la comunicacion del arduino con el PC ya que son los pines utilizados en la interfaz usb.
Si quieres utilizar el PORTD para algo debes utilizar los pines 2 a 7 y para no interferir deberías aplicar esta mascara:

Código:
PORTD = (PORTD & B00000011) | (hour << 2);


Que basicamente lo que hace es dejar los bit 0 y 1 como estaban y luego ponerle a los bit 2 a 7 el contenido de la variable hour. El << sirve para correr los bits de la variable hour hacia la izquierda de forma que no sobreescribas los bit 0 y 1 con el contenido.
  Responder
#5
Pues lo habia visto asi en un par de webs ,pero efectivamente me mantenia los pines en alto una vez se habian encendido...Seria correcto tambien esto?:
Código:
PORTC &= B0000;

PORTC |= hour;
teoricamente solo haria una puesta a 0 de los 4 primeros bits sin tocar los demas y luego un or con la variable,que por cierto nunca va a pasar de 12.
  Responder
#6
Umm, no, no te valdría, ya que el registro del puerto es de 8 bits (Aunque físicamente en dicho puerto no haya 8 pines) y cualquier operación que le realices va a contemplar los 8 bits. Me explico... B0000 para el microcontrolador es lo mismo que B00000000. El microcontrolador le pases el dato que le pases siempre va a completar con 0s lo que no conoce.


Podrías hacerlo así:
Código:
PORTC &= B11110000;
PORTC |= hour;

Aun así... esto no es 100% correcto, ya que lo que ocurrirá al realizar esto es que primero apagarás los 4 leds que te indican la hora e inmediatamente encenderás los led que correspondan a la hora en binario. Si es algo visual y para ti entonces te vale, pues el microcontrolador es tan rapido ejecutando estos cambios que dudo que llegues a apreciar que se han apagado los led por ese pequeñisimo instante.
  Responder
#7
Bueno pues dejo el sketch de como ha quedado al final:
Código:
// Reloj Binario.

//----------------Librerias--------------

#include <Wire.h> // Libreria necesaria para la comunicacion I2C con el DS3231.
#include <RTC.h> // Libreria necesaria para usar el DS3231.

//--------------Constantes-------------

#define RTC_ADDRESS 0x68 // Direccion I2C del DS3231
#define REFRESH 1000 //La hora se comprueba cada segundo.
#define M_BUTTON 2 // Boton para ajustar minutos
#define H_BUTTON 3 // Boton para ajustar hora

//---------------Variables--------------

RTC rtc(DST_ON); // Objeto que representa el DS3231 y permite usar metodos.
Data data; // Variable tipo Data ,definida en la libreria RTC.h para almacenar hora y fecha.
unsigned long timeNow; //Variable para almacenar el tiempo actual de millis().
byte hour,minutes; //Variables donde se guardan la hora y minutos actuales para comparar con los leidos.

//-------------Funciones---------------

void getHour(){ // Consulta hora y minutos y enciende o apaga los leds correspondientes a la hora leida.
 data = rtc.getData(); // Metodo de la libreria RTC.h que lee la hora y la almacena en la variable data.
 if(data.minutes != minutes){ // Si los minutos han cambiado se encienden los leds correspondientes en los pines d8 al d13.
   minutes = data.minutes;
   PORTB = minutes;
 }
 if(data.hour != hour){ // Si la hora ha cambiado se encienden los leds correspondientes.
   if(data.hour == 0){ // Para evitar que a las 12 de la madrugada el ds3231 devuelva un 0.
     hour = 12;
   }
   else {
     hour = data.hour;
   }
   PORTC &= 11110000; // Apaga todos los leds
   PORTC |= hour;     // Enciende los leds correspondientes a la hora.
 }
}

void adjustHour() { // Incrementa y guarda la hora en el DS3231 cada vez que se pulsa el boton de ajuste de la hora.
 rtc.setHour(hour+1);
}

void adjustMinute() { // Incrementa y guarda los minutos en el DS3231 cada vez que se pulsa el boton de ajuste de los minutos.
 if(minutes+1 == 60){
   rtc.setMinutes(0); // Pasa del minuto 59 al 0.
 }
 else {
   rtc.setMinutes(minutes+1);
 }
}

//---------------Setup-------------

void setup() {
 pinMode(H_BUTTON,INPUT_PULLUP);
 pinMode(M_BUTTON,INPUT_PULLUP);
 for(byte pin = 8;pin < 18;pin++){
   pinMode(pin,OUTPUT);
 }
 timeNow = millis();
}

//-----------------Loop----------------

void loop() {
 if((millis() - timeNow) >= REFRESH) { // Si ha pasado mas de un segundo se lee la hora.
   getHour();
   timeNow = millis();
 }
 if(digitalRead(H_BUTTON) == LOW){ // Si se pulsa el boton de ajuste de las horas se incrementan las horas en 1 y se guardan.
   adjustHour();
   delay(60);
 }
 if(digitalRead(M_BUTTON) == LOW){ // Si se pulsa el boton de ajuste de los minutos se incrementan los minutos en 1 y se guardan.
   adjustMinute();
   delay(60);
 }
}
  Responder