Traduccion o creacion de manual para microcontroladores AVR

Creo que encontré la librería junto a muchas otras muy interesantes como control de GLCD,Decodificacion de protocolo NMEA, RC5, etc....en cuanto la pruebe pongo mis resultados.
 
Hola a todos , bueno luego de dar algunas vueltas y hacer varios ejemplos con WInAVR me embarque en la tarea de hacer funcionar una memoria eeprom 24C256, con resultados por el momento negativos.
Quisiera saber si alguien ha tenido experiencias con el bus I2C por software.
Les dejo la librería y el programa para un ATTINY2313.
1º - La librería I2C:
Código:
/*************************************************
 LIBRERÍA DE CONTROL PARA BUS I2C EN MODO MASTER.
 PROGRAMADOR: Moyano Jonathan.
 Fecha: Setiembre del 2010.
 Compilador: WinAVR 
 ************************************************/

// Acá definimos el puerto y los pines involucrados en la comunicación I2C.
// Puerto SCL.
#define SCLPORT    PORTD    // PUERTO RELOG I2C.
#define SCLDDR    DDRD    // DIRECCIÓN PUERTO RELOG.
// Puerto SDA.
#define SDAPORT    PORTD    // PUERTO DATOS I2C.
#define SDADDR    DDRD    // DIRECCIÓN PUERTO DATOS.
#define SDAPIN    PIND    // PUERTO DE ENTRADA DE DATOS.
// Asignaciones de pines.
#define SCL    PD4     // PUERTO DE RELOG SCL I2C.
#define SDA    PD3    // PUERTO DE DATOS SDA I2C.

// i2c 1/4 bit delay. (5uS)
#define QDEL    asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop");
// i2c 1/2 bit delay. (10uS)
#define HDEL    asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop");

#define I2C_SDA_LO      SDAPORT &= ~(1<<SDA); // Pone la línea SDA, en bajo nivel.
#define I2C_SDA_HI      SDAPORT |= 1<<SDA;    // Pone la línea SDA, en nivel alto.

#define I2C_SCL_LO      SCLPORT &= ~(1<<SCL); // Pone la línea SCL, en bajo nivel.
#define I2C_SCL_HI      SCLPORT |= 1<<SCL;    // Pone la línea SCL, en nivel alto.

#define I2C_SCL_TOGGLE  HDEL I2C_SCL_HI HDEL I2C_SCL_LO
#define I2C_START       I2C_SDA_LO QDEL I2C_SCL_LO      // Condición de START.
#define I2C_STOP        HDEL I2C_SCL_HI QDEL I2C_SDA_HI HDEL // Condición de STOP.

// Definición de funciones:

// Iniciamos las comunicaciones.
static void i2c_start(void); 

// Paramos las comunicaciones;
static void i2c_stop(void);

// Enviamos datos por el bus I2C.
int i2c_write(int data);

// Recibimos datos por el bus I2C.
int i2c_read(void);
/*****************************************************************************************/

// FUNCIONES PARA TRABAJAR CON EL BUS I2C.
static void i2c_start(void) {
 I2C_START
 }
static void i2c_stop(void) { 
 I2C_SDA_LO // Limpiamos la línea de datos.
 I2C_STOP
 }

int i2c_write(int data) {
 
  uint8_t mascara = 0x80;
  uint8_t i = 8;
   
    while(i--) {

        if(data & mascara)  //Si es 1.....
         
         I2C_SDA_HI // Pone a nivel alto la salida SDA.
         else       // Si no es 1....
         I2C_SDA_LO // Pone a nivel bajo la salida SDA.
       
      mascara >>= 1;
           
       I2C_SCL_TOGGLE // Cambio de flanco en el pin SCL.
   }
  
 I2C_SDA_HI           // Dejamos SDA en alto.
 SDADDR &= ~(1<<SDA);    // Configuramos SDA como entrada.        
 HDEL                 // Esperamos 10us.
 I2C_SCL_HI          // Dejamos SCL en alto.

      i = SDAPIN & (1<<SDA);    // Obtenemos el bit ACK.

 HDEL                 // Esperamos 10us.
 I2C_SCL_LO          // Dejamoslínea SCL en bajo.
 SDADDR |= 1<<SDA;    // Configuramos nuevamente SDA como salida.
 HDEL                 // Esperamos 10us.
 return i;     // Retornamos el valor de ACK. 

          }
     
int i2c_read(void) {

  uint8_t datos = 0;
  uint8_t i = 8;

   I2C_SDA_HI          // Dejamos SDA en alto.
   SDADDR &= ~(1<<SDA);     // Configuramos SDA como entrada.    

   while (i--)
    {
        HDEL                 // Esperamos 10us.
        I2C_SCL_HI         // Dejamos SCL en alto.
        datos <<= 1;         // Rotamos el resultado a la izquierda.
        if (SDAPIN & (1<<SDA))
            datos += 1;      // Si hay un uno en la línea de datos lo agregamos
                             // al arreglo.

        HDEL                 // Esperamos 10us.
        I2C_SCL_LO           // Dejamoslínea SCL en bajo.
    }

   SDADDR |= 1<<SDA;    // Configuramos nuevamente SDA como salida.
   I2C_SCL_TOGGLE       // Cambio de flanco en el pin SCL. 
   I2C_SDA_HI           // Dejamos SDA en alto.
   return datos;      // retornamos con el dato leido.
}
y 2º el programa que implementé...me compila bien pero no me está funcionando , en la salida siempre obtengo 0xFF ....:rolleyes:

Código:
/*************************************************
 PROGRAMAS DE EJEMPLO PARA EL ATTINY2313 - 20PU.
 PROGRAMADOR: Moyano Jonathan.
 Fecha: Setiembre del 2010.
 Programa: Graba 4 datos en una memoria EEPROM 24CL256. Luego
           lee las memorias y muestra los valores guardados en 
           el puerto B.
 Cristal:  8Mhz.
 Programador: PK2-ISP.
 ************************************************/
#include <avr/io.h>     // Definiciones de hardware.
#include <util/delay.h> // Librería para generar retardos.
#include <util/i2c_software.c> // Librería para el manejo de I2C por 
                               // software.

void init_ext_eeprom()
{
   SDAPORT |= 1<<SDA;    // Pone la línea SDA, en nivel alto.
   SCLPORT |= 1<<SCL;    // Pone la línea SCL, en nivel alto.
}

void write_ext_eeprom(uint32_t address, uint8_t valor)
{
   int status;
   i2c_start();
   i2c_write(0xa0);
   i2c_write((address>>8)&0x1f);
   i2c_write(address);
   i2c_write(valor);
   i2c_stop();
   i2c_start();
   status=i2c_write(0xa0);
   while(status==1)
   {
      i2c_start();
      status=i2c_write(0xa0);
   }
}

uint8_t read_ext_eeprom(uint32_t address) {
        uint8_t _datos;
        i2c_start();
        i2c_write(0xa0);
        i2c_write((address>>8)&0x1f);
        i2c_write(address);
        i2c_start();
        i2c_write(0xa1);
        _datos =i2c_read();
        i2c_stop();
        return(_datos);
}
int main(void)
{
    DDRB = 0x1F;  // PB0-PB4 salidas.
    PORTB = 0x00; // Ponemos todas las salidas a 0. 

    uint8_t k; // Variable auxiliar.

        init_ext_eeprom();
        write_ext_eeprom(0x01,0x01);
        write_ext_eeprom(0x02,0x02);
        write_ext_eeprom(0x03,0x03);
        write_ext_eeprom(0x04,0x04);
    
    while(1) // Loop infinito.
    {
        for(k=0; k<=4; k++){
        PORTB = read_ext_eeprom(k);
        _delay_ms(250);
    }
}
}
 
Acá les dejo el código arreglado y funcionand para que todos lo puedan aprovechar. Está en AVR GCC compilado con WINAVR.
Código:
/*************************************************
 PROGRAMAS DE EJEMPLO PARA EL ATTINY2313 - 20PU.
 Fecha: Setiembre del 2010.
 Programa: Guarda 1 dato en la EEPROM y luego lo lee.
 Cristal:  8Mhz.
 Programador: PK2-ISP.
 ************************************************/
#include <avr/io.h>
#include "i2cmaster.h"
#include <util/delay.h>

char i,status;

int main(void)
{
    DDRB = 0x07;  // PB0-PB2 salidas.
    PORTB = 0x00; // Ponemos todas las salidas a 0. 
    
    i2c_init(); // Iniciamos I2C.
    
    i2c_start_wait(0xA0+I2C_WRITE);
    i2c_write(0x00); // Dirección ALTA.
    i2c_write(0x01); // Dirección BAJA.
    i2c_write(0x05); // Datos.
    i2c_stop(); 
    
    
    i2c_start_wait(0xA0+I2C_WRITE);
    i2c_write(0x00); // Dirección ALTA.
    i2c_write(0x01); // Dirección BAJA.
    
    status = i2c_rep_start(0XA0+I2C_READ);
    if(status != 0) {
      i2c_stop();
        PORTB = 0x04;
         _delay_ms(2000);
           }
             else
  
    i = i2c_readNak(); // Leemos dato.
    PORTB = i;
    _delay_ms(2000);
    i2c_stop();
}
 
Te agradezco que te hayas tomado el tiempo de hacer funcionar este codigo para i2c y además que todo este comentado asi es mas facil de entender:D... esta es una buena solucion en micros que no tengan i2c por hardware, también debo agradecerte por el tuto que subiste del manejo del AVR studio con AVRGCC (y), hasta el momento solo había compilado en WINAVR, pero gracias a ese tutorial me inicié en AVR studio.

Aparte tengo una pequeña duda, no se si utilizaste el grabador USBASP, bueno este es de programación serial y según las hojas de datos, para grabar un micro con cristal externo con grabadores seriales se debe introducir una señal de clock externa al pin XTAL1. el hecho es que nunca lo he probado, No sabes si ¿realmente se puede grabar con el USBASP un micro configurado en cristal externo...? o por intentarlo el micro puede quedar -ingrabable- para programadores seriales...
 
Aparte tengo una pequeña duda, no se si utilizaste el grabador USBASP, bueno este es de programación serial y según las hojas de datos, para grabar un micro con cristal externo con grabadores seriales se debe introducir una señal de clock externa al pin XTAL1. el hecho es que nunca lo he probado, No sabes si ¿realmente se puede grabar con el USBASP un micro configurado en cristal externo...? o por intentarlo el micro puede quedar -ingrabable- para programadores seriales...

Yo utilizo el Pickit2 para grabar mis micros, es mucho más facil que armar un programador dedicado.
El USBasp , tiene algunos bug's no muy sustanciales pero los tiene. Que es lo que pasa ??
1º - En caso de configurar mal el bit SPIEN de los fuses de cualquier AVR, el micro queda inutilizable para las prácticas salvo que tengas un STK500 o un HVPROG paralelo de alto voltaje con el que podés recuperar el micro para seguirlo trabajando con ISP.

2º - En caso de que la velocidad configurada en los fuses no coincidad con el cristal conectado al micro, el mismo se vuelve inestable y no sincroniza. Por lo tanto el micro te queda inutilizable ( por carne propia lo he visto ).

3º - Lo que tenés que hacer antes de grabar cualquier programa en un micro AVR es ver lo siguiente.

a - PRIMERO QUE NADA configurar bien los fuses para el cristal que vallas a usar, luego de esto conecta el cristal al micro y luego el programador. En tu ventana de programación graba los fuses antes configurados.
Una vez hecho esto ya tenés sincronizado el grabador y el micro.

b - En tu programa declara la frecuencia de clock utilizada (caso de usar WINAVR solo) o si trabajas con el AVRstudio , desde las configuraciones del menu pone la frecuencia de trabajo.

c - luego de tener la Frecuencia configurada , compilas tu código y grabás el microcontrolador con tu programa.

Esos pasos te van a asegurar un buen funcionamiento.

En caso de trabajar en WINAVR...te recomiendo que uses directamente el IDE de winavr y compiles con MAKEFILES, es menos laborioso.
 
Hola amigo moyano y StrySG.
ustedes que saben del tema:aplauso:, que tal es el BASCOM AVR. y creo que mikrobasic tambien los
maneja..algun tuto sobre esto existe por la red..
 
BASCOM está bueno , pero su optimización del código no es del todo buena. Algo para tener en cuenta al igual que con Mikrobasic PRO para AVR es que disponen de muchas librerías.
 
Bueno gracias por la info acerca del USBASP, creí que este era el grabador ideal dado su relativa sencillez.
Pero viendo esto de los fuses... dado que ya bloqué un micro via programación serial por usar fuses configurados en crsital externo y otro micro mas pequeño quedó bloqueado por habilitar el fuse -RSTDSBL-.
Mejor me limitaré a configurar los Micros con oscilador RC interno, aparte me parece interesante este grabador Pickit2 no había planeado construirlo, pero dado sus ventajas creo que comenzare a conseguir los materiales para armarlo...
 
Hola StrySG a mi ya me paso eso de perder sincronia con el oscilador en los AVR pero se soluciona facil con el 555, ademas si usaste PonyProg el mismo no te deja deshabilitar la programacion serial por lo que todo mal que le puedas hacer al micro queda en solo la perdida de sincronia que repito se puede solucionar con el 555
 
Hola COSMICO, ami se me hace muy bien programar con el BASCOM-AVR, igual estoy aprendiendo C te dejo una pagina donde puedes descargar informacion de Bascom en español, pero es para el 8051 es casi similar al AVR igual te puede servir: http://www.dinastiasoft.com.ar/Software.htm
tambien hay algunos manuales para el AVR son fotocopiados pero no recuerdo la pagina buscalos en TARINGA.

Saludos
 
Acá les dejo el código para manejar dispositivos mediante SPI usando la USI del ATtiny2313:
Código:
/***************************************************************** 
   Fecha: Setiembre del 2010.
   Cristal:  4Mhz.
   Programador: Moyano Jonathan
 *****************************************************************/
#include <avr/io.h>     // Definiciones de hardware.
#include <util/delay.h>

// Declaramos funciones utilizadas.
void    spi_init(uint8_t velocidad);  // Inicia el bus SPI y setea velocidad de trabajo. 
uint8_t spi_write(uint8_t dato);      // Escribe un dato en el bus SPI.

// Definimos los pines para la comunicación SPI.
#define SDI PINB6  
#define SDO PINB5  
#define SCK PINB7  

void spi_init(uint8_t velocidad) {

 if (velocidad==1) { // Si velocidad = 1, la velocidad del bus es máxima.
        PORTB |= (1<<SDO)|(1<<PINB4);       
        DDRB = (1<<SCK)|(1<<SDI)|(1<<PINB4);
        USICR = (1<<USIWM0)|(1<<USICS1)|(1<<USICLK);
        PORTB &= ~(1<<PINB4);    // Habilitamos esclavo.
    } else { // Si velocidad es 0....
        PORTB |= (1<<PINB4);     // Deshabilitamos esclavo.
        DDRB &= ~((1<<SCK)|(1<<SDO)|(1<<SDI)|(1<<PINB4));
        USICR = 0;
    }
}

uint8_t spi_write(uint8_t dato) {

 USIDR = dato; // Carga el dato a enviar.
    USISR = (1<<USIOIF);
    do {
        USICR = (1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC); // Configuramos la USI.
    } while ((USISR & (1<<USIOIF)) == 0); // En caso de que termine de enviar el dato, retorna el valor
                                           // De USIDR.
    return USIDR;    
}
 
Acá les dejo el código para manejar dispositivos mediante SPI usando la USI del ATtiny2313:
Una vez más gracias por la info, me agrada mucho que coloques códigos con comentarios asi son fáciles de entender...


eso de perder sincronia con el oscilador en los AVR pero se soluciona facil con el 555
Una vez intente hacerlo con un oscilador en base a AO's pero no funcionó, pls será que puedes darnos algun Link...
 
Atrás
Arriba