User Tools

Site Tools


Writing /var/lib/dokuwiki/data/meta/teaching/ie0107/ie-0107_laboratorio_de_microcontroladores_proyectos/acelerometro/codigo.meta failed
teaching:ie0107:ie-0107_laboratorio_de_microcontroladores_proyectos:acelerometro:codigo

Código fuente

Primero se inicializaron las funciones y variables globales necesarias según lo especificado por las hojas de fabricante del MPU-6050 y del microcontrolador ATmega16 para el protocolo I2E o tambien llamado TWI:

// Encabezados de las funciones usadas.
void TWI_init_SCL(void);   // Inicializa el SCL con los valores de bit rate (TWBR) y prescala (TWSR).
void TWI_start_condition(void);   // Se manda la condición de inicio (START).
void TWI_device_address(unsigned char);   // Se escribe la dirección del esclavo (MPU-6050) cuando se está escribiendo.
void TWI_register_address(unsigned char);   // Dirección del registro del MPU-6050 que se desea leer (ACCEL_XOUT[15:8])
void TWI_start_repeated(void);   // Se repite condicion de inicio (START) para lectura.
void TWI_device_address_read(unsigned char);   // Se escribe la dirección del esclavo (MPU-6050) cuando se está leyendo.
unsigned char TWI_read_data(void);   // Se devuelve la lectura del dato del MPU-6050.
void TWI_stop(void);   // Condición de parada.

// Variables globales usadas.
unsigned char slave_address=0xD0;   // Dirección del MPU-6050 con AD0 a tierra 0b1101000X, el último bit es para indicar lectura o escritura.
unsigned char register_acelX_address=0x3C;   // Dirección del registro que tiene la aceleración en eje X.
unsigned char read=1, write=0;   // Estados de lectura (1) y escritura (0).

Luego de esto viene el programa principal encargado de controlar el comportamiento del ATmega para la aplicación desarrollada, la primera línea de código define una matriz que posee la palabra “EIE” formada por columnas de 8 bits, estas columnas son las que desplegaran en los leds:

// Programa principal.
int main(void) {	

  // Matriz con las letras a desplegar en los leds.
  unsigned char letras[] = {0x00,0xFF,0xFF,0xDB,0xDB,0xDB,0xC3,0x00,0x00,0xFF,0xFF,0x00,0x00,0xFF,0xFF,0xDB,0xDB,0xDB,0xC3,0x00};	

A continuación viene la secuencia de uso del protocolo I2C ya visto anteriormente en una imagen, simplemente se llaman las funciones que conforman cada parte del esquema del I2C:

  DDRA = 0xFF;   // Activa los 8 puertos DDRA.
      
  TWI_init_SCL();   // Inicializa el SCL.
  PORTA = (1<<PA0);	
  TWI_start_condition();   // Condición de inicio.
  TWI_device_address(slave_address + write);   // Dirección del dispositivo + escritura.
  TWI_register_address(register_acelX_address);   // Direccion del registro a leer.
  TWI_start_repeated();   // Repeticion de la condicion de inicio.
  TWI_device_address_read(slave_address + read);   // Dirección del dispositivo + lectura.

Sigue la lectura del bus SDA, se guarda este valor de aceleración en el eje X en una variable para poder hacer comparaciones con los valores que vienen después y analizar si se movió el dispositivo; si este se movió hacia la derecha lo que se ve en los leds es la columna izquierda junto a la columna actual que se está iluminando; si el movimiento fué hacia la izquierda se ilumina la columna de la derecha:

  char acel_X_init = TWI_read_data();   // Se lee el dato del bus.   

  int i=0;   // Ubicación inicial de la matriz de letras que se despliega en los leds.
  // Cliclo para estar leyendo datos del acelerómetro y compararlos con el valor anterior para ver si se movió.
  while (1) {
    char acel_X_fin = TWI_read_data();
	
    // Si la aceleración fue positiva.
    if (acel_X_fin > acel_X_init) {
      if (i == 20) {
        i = 0;
        PORTA = letras[i];
      }
      else {
        i = i+1;
        PORTA = letras[i];
      }
    }
	
    // Si la aceleración fue negativa.
    if (acel_X_fin < acel_X_init) {
      if (i == 0) {
        i = 20;
        PORTA = letras[i];
      }
      else {
        i = i-1;
        PORTA = letras[i];
      }
    }
	
    acel_X_init = acel_X_fin;	
    
  }
  TWI_stop();
}   

Se implementan las funciones definidas al principio para poder establecer la comunicación; primero hay que definir el reloj SCL a partir de dos registros que dan en la hoja del fabricante:

// Inicializa el SCL con los valores de bit rate (TWBR) y prescala (TWSR).
void TWI_init_SCL(void) {
	TWBR=0x08;   // Bit rate.
	TWSR=(0<<TWPS1)|(0<<TWPS0);   // Bits de preescala.
}

A continuación se sigue la funcion de inicio de la transmisión de datos:

// Se manda la condición de inicio (START).
void TWI_start_condition(void) {
  // Se limpia la bandera de interrupción del TWI, pone condicion de inicio en SDA, habilita el TWI.
  TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  while(!(TWCR & (1<<TWINT)));  // Espera a que se limpie TWINT, indica que la condicion de inicio se transmitió.
  while((TWSR & 0xF8)!= 0x08);  // Chequea que se de el bit de reconocimiento (ACK) con el código de estado $08.
}

Luego hay que pasar la dirección del esclavo (MPU-6050), con el último bit en 0 se indica que se está escribiendo:

// Se escribe la dirección del esclavo (MPU-6050) y que se está escribiendo.
void TWI_device_address(unsigned char data) {
  TWDR=data;   // Direccion + escritura (0) en TWDR, que se envia por el bus SDA.
  TWCR=(1<<TWINT)|(1<<TWEN);   // Limpia la bandera de interrupción y abilita el TWI.
  while (!(TWCR & (1<<TWINT)));   // Espera a que se transmita el byte TWDR por el bus SDA.
  while((TWSR & 0xF8)!= 0x18);   // Chequea que se de el bit de reconocimiento (ACK) con el código de estado $18.
}
// Se escribe la dirección del registro del MPU-6050 que se desea leer (ACCEL_XOUT[15:8])
void TWI_register_address(unsigned char data) {
  TWDR=data;   // Pone la dirección del registro que contiene la aceleración en el eje X en TWDR.
  TWCR=(1<<TWINT)|(1<<TWEN);   // Limpia la bandera de interrupción y habilita el TWI.
  while (!(TWCR & (1<<TWINT)));   // Espera a que se transmita el byte TWDR por el bus SDA.  
  while((TWSR & 0xF8) != 0x28);   // Chequea que se de el bit de reconocimiento (ACK) con el código de estado $28.
}
// Se repite condición de inicio (START) para lectura.
void TWI_start_repeated(void) {
  // Se limpia la bandera de interrupción del TWI, pone condicion de inicio en SDA, abilita el TWI.
  TWCR= (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
  while(!(TWCR & (1<<TWINT)));   // Espera a que se limpie TWINT, indica que la condicion de inicio se transmitió.
  while((TWSR & 0xF8)!= 0x10);   // Chequea que se de el bit de reconocimiento (ACK) con el código de estado $10.
}
// Se escribe la dirección del esclavo (MPU-6050) y que se está leyendo.
void TWI_device_address_read(unsigned char data) {
  TWDR=data;   // Direccion + lectura (1) en TWDR.
  TWCR=(1<<TWINT)|(1<<TWEN);   // Limpia la bandera de interrupción y abilita el TWI.
  while (!(TWCR & (1<<TWINT)));   // Espera a que se transmita el byte TWDR.
  while((TWSR & 0xF8)!= 0x40);   // Chequea que se de el bit de reconocimiento (ACK) con el código de estado $40.
}
// Se devuelve la lectura del dato del MPU-6050.
unsigned char TWI_read_data(void) {	
  while (!(TWCR & (1<<TWINT)));   // Espera a que se reciba el byte TWDR.
  unsigned char data = TWDR ;   // Se lee el dato en el bus.
  return data;   // Se devuelve el dato que viene del bus SDA.
}
// Condición de parada.
void TWI_stop(void) {
  // Se limpia la bandera de interrupción del TWI, pone condicion de parada en SDA, abilita el TWI.
  TWCR= (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
  while(!(TWCR & (1<<TWSTO)));   // Espera hasta que la condición de parada sea transmitida.
}

Inicio

teaching/ie0107/ie-0107_laboratorio_de_microcontroladores_proyectos/acelerometro/codigo.txt · Last modified: 2022/09/20 00:08 (external edit)