# Practicas para iniciar con el atmega32 utilizando el avrstudio 4 y el lenjuage C



## fitocondria (May 19, 2008)

Inicio este tema, debido a que varios habían expresado su interes en los microcontroladores de atmel, y debido a mi asesor de tesis, el cual me sugirio que utilizara el microcontrolador atmega32 de la compañia atmel, inicio estas series de prácticas mientras veo futurama.

Lo siguiente que utilizaré para las prácticas es lo siguiente.

Software:

AVRStudio 4 - version 4.13.528
WINAVR20080402

Hardware:

avrispmkII
microcontrolador atmega32
componentes varios.


----------



## fitocondria (May 19, 2008)

Primero pondre el código fuente, despues los pasos para llevar este programa hasta el microcontrolador y ejecutarlo.


```
#include <avr/io.h>
#include <avr/delay.h>

int main(void)
{
   //Set PORTD for output
   DDRD = 0xFF;
   int i;
      while(1) {
            for (i = 1; i <=128; i = i*2)
            {
               PORTD = i;
               _delay_loop_2(30000);
            }

            for (i = 128; i > 1; i -= i/2)
            {
               PORTD = i;
               _delay_loop_2(30000);
            }
      }
}
```

1) Abrir el AVRStudio 4.
2) Seleccionar el menú Project, después seleccionar el submenu Project Wizard.
3) En la ventana de dialogo llamada "Welcome to AVR Studio 4" presionamos el boton "New Project".
4) Seleccionamos en "Project type" AVR GCC
5) En "Location" indicamos la ruta en mi caso es C:\atmel.
6) En "Project name:" indicamos el nombre del projecto que será el mismo que el archivo principal en este caso Blinky.
7) Después presionamos "Next>>"
   Opcional porque podemos utilizar el proteus. Por lo general con ver los registros me basta pero como todavía no conozco mucho el atmel utilizare el proteus.
   8) En "Debug plataform" seleccionamos AVR Simulator.
   9) Y en "Device" ATMEGA32
8) Hacemos clic en Finalizar

*Por cierto ya acabo futurama.

1) Creamos el archivo Blinky.c tal y como lo puse arriba.
2) Seleccionamos el menu "Project" y luego el submenu "Configuration Options".
3) En "General" seleccionamos 1000000 en "Frequency", la optimización de "-Os" y Aceptamos la configuración.
Nota: aparecerá un warning pero para eliminarlo hay que elegir la carpeta donde esta ubicada la librería y con compilar de nuevo se elimina ya que la librería automaticamente incluye la libreria correcta.

Ahora procederemos a programar el microcontrolador.
1) Seleccionamos el menu "Tools" y luego el submenu "Program AVR", despues "connect".
2) aparece un dialogo llamado "Select AVR Programmer" en este caso "AVRISP mkII" y en "Port"  USB. Y presionamos el boton "CONNECT".

1) En la pestaña "Program" presionamos el boton "Erase Device" y despues en el cuadro "Flash" presionamos el boton program.

Después de esto tendremos nuestro programa ejecutandose en el microcontrolador atmel atmega32.

si conocen algun programa para subir fotos a internet, con mucho gusto subo los menus y submenus y como se ven ejecutandose esta practica y las futuras.

Ah y tambien donde subir archivos para colocar los archivos de proteus y los futuros archivos comprimidos listo para probar y simular.


----------



## Beamspot (May 26, 2008)

Hola:

Un par de detalles tontos. Creo que hace falta explicar que son los fuses, y que hay que configurarlos antes de programar el micro.

Mas que nada, para asegurarnos que el micro está corriendo con el reloj interno por defecto de 1 MHz, (el que hemos configurado), y que todo está correcto, no sea que alguien haya tocado esos valores.

Hay que recordar que no conviene ni habilitar el uso de relojes externos (o si no no podremos volver a configurar el micro hasta tener un reloj externo conectado), ni poner la frecuencia del ISP a un valor demasiado alto. Parece ser que habitualmente el AVRISP MkII viene configurado como frecuenca de programación de 1MHz, lo cual es un problema, ya que debe ser como mucho un cuarto de la frecuencia de reloj de sistema.

He 'inutilizado' varios AVR's por no hacer eso. Suerte que he podido recuperarlos con un reloj externo.


----------



## microtronic (May 27, 2008)

seria bueno una explicacion mas extensa de los fuses....aveces es un poco confusa la configuracion de estos...


----------



## fitocondria (May 27, 2008)

Por lo que he estado viendo depende de la serie del microcontrolador. 

En mi caso expongo los que aparecen para mi microcontrolador atmega32-16PU.

















Que corresponden con los dos bytes de fusibles, los cuales se dividen en registro de fusibles alto y registro de fusibles bajo.

En el registro de fusibles alto se configuran los siguientes:

OCDEN      :Habilita el OCD, habilita algunos osciladores apesar de estar en modo sleep.
JTAGEN      :Habilita el JTAG, interfaz que cumple con el estandard 1149.1 de la IEEE.
SPIEN        esahabilitado con mi programador, ya que habilita o deshabilita el uso del ISP. jejeje 
CKOPT       :su funcionalidad depende de los bit de CKSEL
EESAVE      : Indica si se borra la memoria eeprom o no durante el ciclo de borrado.
BOOTSZ1   :Configura el tamaño del arrancador 
BOOTSZ0   :cargador por lo general no usado en mis practicas
BOOTRST   :Selecciona donde comienza el vector del reset




imagen del mapa de memoria con boot

En el registro de fusibles bajo se configuran los siguientes:

BODLEVEL :Indica el nivel en el que se detecta el nivel de bajo voltaje
BODEN      :habilita el detector de nivel de bajo voltaje
SUT1         :Indica el tiempo que debe de esperar antes iniciar
SUT0         :el programa dentro del microcontrolador
CKSEL3     :Se utiliza para seleccionar los tipos de reloj a utilizar
CKSEL2     :desde el oscilador interno de 1 mhz hasta 8 mhz internos
CKSEL1     ara mi caso, o los osciladores externos que alcanzan hasta
CKSEL0     :los 16mhz

Pero todo esto depende del microcontrolador y por lo general las opciones por default son buenas. Hasta arriba estan las opciones con las que programo el atmega32.

No he subido enviado más practicas porque estoy peleandome con el display LCD para utilizarlo con mi titulación. Espero subir más, pero me ha quitado mucho tiempo el mugre LCD. Pero espero subir más, ya que las que tengo en C las estoy pasando tambien a ensamblador, muy divertido por cierto el ensamblador de los atmel.


----------



## Beamspot (May 28, 2008)

Confirmo que los fuses dependen del micro, pero hay unos pocos que son comunes en significado, que no en posición.

El del reloj, que por defecto viene programado como interno a 1MHz es fundamental. Es el primero que hay que mirar, y es muy importante estar seguro de lo que se pone, no sea que se programe para funcionar con uno externo, y no haya ningún cristal puesto. Este suele ser la principal causa de los micros que se 'mueren' al programarlos. Por suerte, con un reloj externo se pueden 'resucitar'.

El de SPI enable es importande dejarlo habilitado (por defecto), y es que si uno lo deshabilita, adiós volver a programarlo. Por suerte, hoy en día el AVRStudio pide confirmación de esto.

El del JTAG y OCD dependen de si el micro tiene esta interfaz. Permite programar por el JTAG por defecto, pero eso ocupa algunos pines que quedan inutilizados para ser usados en el programa. Eso sí, el OCD es muy bueno a la hora de depurar los programas (y barato), hasta el punto en que nunca uso el ISP excepto para productos 'acabados'.

Así que estos fuses son los primeros que hay que comprobar y mirar cuando uno programa el micro.


----------



## fitocondria (May 28, 2008)

Ya solucione el problema del display LCD, un error de alambrado   jojojojojo. Pero ya funciona.

En el caso de la opción para habilitar el ISP en la imagen se ve que el propio menú bloquea esa opción, para evitar cometer ese error.

Sería bueno que mencionaran los nombres de los programas que utilizan para programar los micros, eso permitiría facilitar que errores se pueden presentar al momento de programar. Por ejemplo: cuando selecciono la pestaña de los "fuses" coloca los valores ideales o por default para el microcontrolador que se va a programar, cuando se programa por primera vez, pero cuando abro el proyecto de nuevo y voy a volver a programar, me pone los valores que contiene el microcontrolador.


----------



## fitocondria (May 29, 2008)

A continuación pongo la practica número 1 - blinky- pero en ensamblador. Utilizando el atmega32.


```
#pragma AVRPART ADMIN PART_NAME ATmega32        ; Use el ATmega32

#pragma AVRPART MEMORY PROG_FLASH 32768         ; 32KB de memoria ram

#pragma AVRPART MEMORY EEPROM 1024              ; 1024 bytes de EEPROM

#pragma AVRPART MEMORY INT_SRAM SIZE 2048       ; 2048 bytes de SRAM

#pragma AVRPART MEMORY INT_SRAM START_ADDR 0x60 ; Inicio de la memoria sram

.include "m32def.inc"

.CSEG

        rjmp    RESET

RESET:  ldi	r16,HIGH(RAMEND) ;Configura la pila 
	out	SPH,r16	         ;para utilizar subrutinas
	ldi	r16,LOW(RAMEND)	 
	out	SPL,r16

        ldi     r16,0xFF         ;Configura el PUERTO A como
        out     DDRA,r16         ;salidas

WHILE:  nop

        ldi     r16,0x01         ;Prende un led en el bit 0
        out     PORTA,r16        ;del puerto A 
INCREMENTA:                
        call    retardo4         ;Retardo para apreciar la posición
                                 ;del led encendido      
        in      r16,PORTA        ;Envia la salida del PUERTOA al registro 16
        sbrc    r16,7            ;Es 128 el valor del PUERTOA
        rjmp    DECREMENTA       ;SI->TERMINA RUTINA INCREMENTA
        rol     r16              ;NO->RECORRE UN BIT A LA IZQUIERDA
        out     PORTA,r16        ;Visualiza el nuevo dato en el PUERTOA
        rjmp    INCREMENTA       ;REPETIMOS OPERACION HASTA QUE SEA IGUAL A 128

DECREMENTA:    
        call    retardo4         ;Retardo para apreciar la posición
                                 ;del led encendido
        in      r16,PORTA        ;Envia la salida del PUERTOA al regitro 16
        sbrc    r16,0            ;Es 1 el valor del PUERTOA
        rjmp    INCREMENTA       ;SI->TERMINA RUTINA DECREMENTA
        ror     r16              ;NO->RECORRE UN BIT A LA DERECHA
        out     PORTA,r16        ;Visualiza el nuevo dato en el PUERTOA
        rjmp    DECREMENTA       ;REPETIMOS OPERACION HASTA QUE SEA IGUAL A 1

;*************************************************************************
;* INICIA SUBRUTINA retardo4
;*************************************************************************
retardo4:
        ldi     r20,8
ret2000:
        ldi     r21,150
ret1000:
        ldi     r22,150
ret0000:
        dec     r22
        brne    ret0000
        dec     r21
        brne    ret1000
        dec     r20
        brne    ret2000
        ret
;*************************************************************************
;* INICIA SUBRUTINA retardo4
;*************************************************************************
```

Utilizo la directiva #pragma, ya que utilizo el AVR Assembler 2, esta directiva se utiliza en lugar de su predecesora .device del AVR Assembler 1. Esta y demás opciones se muestran haciendo clic en el menú "Project", luego haciendo clic en el subMenú "Assembler option". Con lo cúal aparecerá el dialogo "Assembler option".




Dialogo "Assembler Option"

En el dialogo aparece un "combo box" llamado "Hex Output Format", en el podemos seleccionar 3 formatos:

1) Intel
2) mototola ("jejejeje")
3) generic

Yo utilice las opciones que vienen por default y son las que se muestran en la imagen.

Abajo del combo box Hex Output Format, hay 3 "check box".

1) Create Map File
2) Create File List
3) Wrap Relative Jumps

Al centro arriba hay un "group box" llamado "Output File"  que contiene 3 "radio buttons" y un "line edit", que nos permite indicar como se llamará el archivo de salida. Si queremos que tenga el nombre del projecto ó si queremos que se llame como el archivo principal que contiene las directivas pragma ó device, por ultimo podemos nombrarlo como deseemos introduciendo el nombre en el "line edit"

1) Project name :
2) Entry file
3) User
I) "_____".obj

Abajo del "group box" llamado "Output File" esta otro "group box" llamado "Unsupported Instructions" que contiene dos "radio buttons".

1) Warning
2) Error

Aquí indicamos como queremos que sean tratadas las instrucciones que no son reconocidas por   el microcontrolador a utilizar, es decir el atmega32 tiene 131 instrucciones y el at90s8515 tiene 118 instrucciones, con pragma podemos indicar que instrucciones no son reconocidas. Cuando escribamos alguna instrucción que no esté soportada por nuestro microcontrolador se nos informaciónrmará. Y no estaremos buscando porque no funciona el programa cuando utilizemos instrucciones que no tiene nuestro microcontrolador empleado. ("Para volverse loco cuando sucede esto, juar juar juar").

Más información viene en el menú "Help" del AVRStudio 4 seleccionando el submenú "Avr Studio User Guide", después en la nueva ventana que aparece seleccionamos "Project" y despues "Assembler project" y por último seleccionamos "Assembler Options".

Con este programa obtenemos los mismos resultados pero en ensamblador en lugar de C.

Comentaré las partes más interesantes a continuación:


```
#pragma AVRPART ADMIN PART_NAME ATmega32        ; Use el ATmega32

#pragma AVRPART MEMORY PROG_FLASH 32768         ; 32KB de memoria ram

#pragma AVRPART MEMORY EEPROM 1024              ; 1024 bytes de EEPROM

#pragma AVRPART MEMORY INT_SRAM SIZE 2048       ; 2048 bytes de SRAM

#pragma AVRPART MEMORY INT_SRAM START_ADDR 0x60 ; Inicio de la memoria sram
```

Esta es la directiva "#pragma" que sustituye a ".device", la directiva "#pragma" se utiliza a partir de la version 2 del AVR Assembler, lo importante de esta directiva es que nos permite indicar que tipo de procesador estamos utilizando, la cantidad de memoria de programa tiene, la cantidad de memoria eeprom y la cantidad de memoria ram, así como el inicio de la memoria ram. También nos permite indicar las instrucciones soportadas como las no soportadas, entre otras cosas. En lugar de seleccionar el dispositivo en un combo box como se hace con los projectos en C, en los projectos en ensamblador se utiliza la directiva "#pragma" para el mismo proposito que en C.


```
.include "m32def.inc"
```

esta es la forma de incluir las definiciones del atmega32, es decir gracias a esto podemos escribir PORTA, etc.


```
rjmp    RESET

RESET:  ldi	r16,HIGH(RAMEND) ;Configura la pila 
       	out	SPH,r16	         ;para utilizar subrutinas
	ldi	r16,LOW(RAMEND)	 
	out	SPL,r16
```

Cuando ocurre un reset o inicia por primera vez el programa va a la posición indicada por la etiqueta reset, esto es para saltarse los vectores de interrupcion. En este programa sencillo pude haber quitado esta instrucción de salto, pero por costumbre y por posibles ampliaciónes la utilizo.

Las instrucciones siguientes nos permiten definir la pila para utilizar llamadas a subrutinas y pasar parametros a funciones, etc.

Otra apecto importante son los saltos, pero por ser un programa muy pequeño,  utilize rjmp, ya que jmp permite saltar a cualquier parte de la memoria y la instrucción rjmp solo 2000 instrucciones arriba y abajo de donde se localiza.

El programa ensamblador utiliza 0.2% de memoria de programa y el programa en c ocupa 0.2% de memoria de programa .




asmblinky.asm




blinky.c

La próxima práctica será un convertidor binario a bcd en c y luego en ensamblador.


----------



## fitocondria (May 29, 2008)

1) No puse como configurar el AVR Studio 4 para los programas en ensamblador.

En project wizard se elije Atmel AVR Assembler en lugar de AVR GCC. De ahí en fuera es igual todo lo demás. Hasta en la forma de programar el microcontrolador.

2) Puse un while por ahí.  Lo pueden eliminar sin problemas, iba a poner los nombres similares al programa en C de blinky.c, pero me distraje con unos compañeros y se me olvido continuar con la nomenclatura tipo c, indicando donde se inicia el for, como se inicializa la variable, donde se compara  y donde se incrementa, todo en ensamblador. Perdonen.


----------



## fitocondria (May 30, 2008)

Ya funciona bien la pantalla de cristal líquido con el atmega32, me costo trabajo y errores de descuido.

Pronto pondre una practica con la pantalla, pero primero sería en ensamblador y luego en C.

Saludos a todos.

Por cierto los modelos de las pantallas de cristal líquido son:

1) JHD162A
2) TM162AD

Los dos tienen el chip de control KS0066U y funcionan bien.


----------



## fitocondria (May 30, 2008)

A continuación el codigo fuente, solo necesitamos incluir <avr/io.h> ya que solo vamos a manipular los puertos del microcontrolador.


```
/*
BINBCD.C : LEE UN NÚMERO BINARIO DE UN PUERTO Y LO
	   CONVIERTE A BCD, EL NUEVO NUMERO BCD SE
	   EXHIBE POR OTRO PUERTO.
*/

#include <avr/io.h>

int main(void)
{
 unsigned char binario;
 unsigned char bcdUnidades;
 unsigned char bcdDecimas;
 unsigned char bcdCentecimas;
 
 //CONFIGURA EL PUERTO DE ENTRADA PARA DATOS BINARIOS
 //SIN RESISTENCIAS PULLUP
 DDRD = 0x00;
 PORTD = 0xFF;

 //CONFIGURA PUERTOS PARA SALIDA DE DATOS BCD
 DDRA = 0xFF;
 DDRC = 0xFF;

 //INICIA PROGRAMA DE LECTURA DE DATOS Y CONVERSIÓN DE
 //BINARIO A BCD
 while(1)
 {
 binario = PIND;           //DIP SWITCH
 bcdUnidades = 0x00;       //REGISTRO UNIDADES
 bcdDecimas = 0x00;        //REGISTRO DECIMAS
 bcdCentecimas = 0x00;     //REGISTRO CENTESIMAS
 while (binario > 9)            //Si es mayor de nueve restamos 10
 {
	binario -= 10;
	bcdDecimas++;         
	if (bcdDecimas > 9)   
	{                                
	 bcdDecimas = 0x00;
	 bcdCentecimas++;
	}
 }                                      
 if (binario <= 9)               
 {
  //Las unidades están en el registro unidades
  //Las decenas están en decenas
  //las centenas están en centenas
	bcdUnidades = binario;
 }

 bcdDecimas <<= 4;      //Corremos bcdDecimas para 
                        //dejar espacio a las unidades
 PORTC = bcdCentecimas;
 PORTA = bcdDecimas | bcdUnidades;
 }
 return 0;
}
```


----------



## fitocondria (Jun 4, 2008)

un virus entro en mi computadora gracias a un compañero, y me modifico todo lo que tenía de las practicas y lo de mi titulación así que voy a estar un rato fuera de línea, por cierto mi librería de la pantalla de cristal líquido de 16x2 que tanto me costo también se la paso a mejor vida. En este momento estoy tratando de instalar las toolschain, kontrollerlab, y avr32 en linux, les contaré como me fué.


----------



## robifaria (Jun 13, 2008)

hola fitocondria, he comprado un modulo con un atmega128 y creo que me he equivocado en la configuracón de los fuses porque puedo programar el micro pero no hace nada.
¿como es el esquematico del oscilador externo y como se hace para revivir el micro?
Te escribo pq eres el único que ha explicado otros conceptos de forma muy transparente.
gracias.


----------



## Beamspot (Jun 16, 2008)

Hola:

Si puedes programar el micro, dudo que tengas problemas con el tema de los fuses del reloj. Sin embargo, si no el AVRStudio no te identifica la 'signature', o el micro no contesta, lo más probable es que hayas seleccionado el fuse de 'Oscilador externo'.

Para eso, el ATmega128 tiene dos pines (XTAL1 y XTAL2, 23 y 24) donde poner un cristal de cuarzo para que funcione a la frecuencia del cristal. Si es temporal, no hace falta que añadas ningún condensador. Te recomiendo un cristal de 8 MHz o similar frecuencia. Si aún así no te comunica, entonces seguramente tendrás que 'inyectarle' una senñal cuadrada de la frecuencia que puedas (aquí es donde le generador de funciones va estupendo) con las tensiones adecuadas, pero no se por qué pin (habrá que mirar el Datasheet).

Según como lo programes, debes asegurarte que la velocidad de programación esté por debajo de 1/4 de la velocidad del micro. Es decir, si está con el reloj interno de 1MHz (valor por defecto), debes programarlo como mucho a 250KHz. De lo contrario, puedes tener problemas.


----------



## fitocondria (Jun 17, 2008)

Me gustaría saber algunas cosas antes. Como cual es el estado de los fuses que se leen con tu programador. Que programa utilizas para grabar el micro para conocer su interfaz. Yo no he tenido ningun problemas de ese tipo con los osciladores de cristal, pero si de equivocarme al momento de seleccionar 1mhz como frecuencia de trabajo del microcontrolador y lo tengo programado como 4mhz. Lo primero es que leas el estado de los fuses para saber como estan configurados y compararlos con lo que tu esperas recibir y apartir de ahí ya puedes solucionar tu situación. 

Por cierto voy a regresar con unos programas para manipular el RTC del atmega 32 y el convertidor analógico a digital. Tanto en ensamblador como en C. Que por cierto utilizando librerias de terceros el programa de mi titulación ocupo 16 k de memoria y con librerias personalizadas llego a 6k.

Espero vernos pronto por aquí. Ya le pondre como llenar un canal de agua con un atmel 32, aunque me gustaría conseguir un atiny pero lo tengo que pedir a México. Nos vemos


----------



## robifaria (Jun 18, 2008)

Hola Beamspot, efectivamente, el problema que he tenido ha sido que no configuré bien los fuses, cambiando las características del cristal me ha funcionado.
Hace poco que programo los micros de Atmel por eso me hago mucho lío con los fuses.
Por lo que me has explicado la configuración del oscilador con los capacitores es la que utilizo siempre.
Entiendo que cuando pregunte me he explicado mal y la solución en caso de que me equivocara en la configuración de los fuses es la que comentaste de inyectar una onda cuadrada en el sitio adecuado. Muy buen consejo el de utilizar el generador de funciones.


----------



## robifaria (Jun 18, 2008)

Hola fitocondria, en verdad los osciladores externos no dan problemas, el programa que usaba para programar los micros es el Avr Studio 4.14 y un programador Jtag Ice, que me he cargado hace dos días atrás, ahora uso el ponyprog que me va lentísimo. Hasta que pueda hacerme otro Jtag saldré de apuros con el programador de puerto paralelo de la Simmstick DT006 que usa solamente tres resistencia en serie el cual  es muy veloz.
No se decirte en estos momentos el estados de los fuses ya que el AVR Studio tiene muchas más opciones de configuración que el ponyprog, de todos modos mi configuración actual es la siguiente:
Oceden, Jtagen,Spien,Ckopt,Bodlevel,Sut1.
Estoy usando un cristal de 14.7456Mhz con capacitores de 22pf.
En estos momentos está funcionando a pesar de todo lo que le hago al  micro.  
Es una muy buena noticia el anuncio del tuorial de C y ensamblador, esperamos contar con ellos en breve. Te agradezco el tiempo y el esfuerzo que dedicas en compartir tus conocimientos.


----------



## Beamspot (Jun 19, 2008)

Dos cosas: primero, enhorabuena por usar un JTAG. Cuando empiezes a depurar programas con el verás las ventajas que ofrece. Cúidalo.
Segundo: intento explicar los fuses que has puesto:
OCDEnable: habilita el debug en el chip con el JTAG.
JTAGEnable: habilita el JTAG, para programar, y para depurar si el fuse anterior está habilitado (los dos están habilitados por defecto de fábrica).
SPIEn: habilita la programación por el ISP/SPI. Habilitado de fábrica, para poder programar el micro.
CKOpt: es un fusible que permite tener una salida 'amplificada' del oscilador del reloj, para poder suministrar el mismo a otros micros o sistemas.
BODLevel: el BOD es un detector de caidas de tensión que resetea el micro. En algunos AVR se puede ajustar a diferentes tensiones (para trabajar a 5V o a 3V3).
SUT: tiempo de arranque después de un HW reset. Hay diferentes opciones, para dar tiempo a estabilizarse tanto la tensión como el oscilador/reloj.
Y quedan los fusibles de selección de reloj interno/externo y velocidad del interno (si se usa). Estos últimos son bastante 'delicados', y generalmente la causa de la 'muerte' de la mayoría de AVR's por novatos (aunque yo mismo, sin ser novato, también tuve este problema). Por suerte, 'resucitar' a estos micros es sencillo.

Y para acabar, quiero felicitar a Fitocondria por tu magnífico trabajo con este tutorial. Me parece muy bueno, y me gustaría poner un Link en www.webdearde.com, pero antes quisiera contar con tu permiso, porsupuesto.


----------



## fitocondria (Jun 20, 2008)

Ya tengo tiempo que no aporto nada, así que comparto este convertidor analógico a digital, el cual es la base para medir el nivel de agua en mi tanque de agua. Lo que pongo no es el que utilizo para mi tesis pero es el que hice para verificar que el microcontrolador hiciera su trabajo.

Expongo el código a continuación.


```
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <compat/ina90.h>
#include <inttypes.h>
#include <lcd.h>

unsigned int datoadc = 0;

void LCDyear(unsigned int binario);

void readADC(uint16_t *radc);

ISR(ADC_vect)
{
   readADC(&datoadc);
}

int main(void)
{
	// turn on and initialize A/D converter
   LCDinit();
   LCDclr();
   LCDhome();
	
	// configure a2d port (PORTA) as input
	// so we can receive analog signals
	DDRA &= ~(1<<DDA0);
	// make sure pull-up resistors are turned off
	PORTA = 0x00;

   //ADMUX = REFS1,REFS0,ADLAR,MUX4,MUX3,MUX2,MUX1,MUX0
   //ADMUX =   0  ,  1  ,  0  ,  0 ,  0 ,  0 ,  0 ,  0
   ADMUX = 0x40;

   //ADCSR = ADEN,ADSC,ADATE,ADIF,ADIE,ADPS2,ADPS1,ADPS0
   //ACDSR =   1 , 0  ,  0  ,  0 ,  1 ,  1  ,  1  ,  1  
   ADCSRA =   0x8F;

   //ADCL = REGISTRO BAJO DEL RESULTADO DEL CONVERTIDOR
   //ADCH = REGISTRO ALTO DEL RESULTADO DEL CONVERTIDOR

   //SFIOR = ADTS2, ADTS1, ADTS0
   //SFIOR = NO UTILIZADO

   sei();
   while(1)
   {
      LCDhome();
      LCDGotoXY(0, 0);
      uint8_t mensaje0[] = {'E','l',' ','r','e','s','u','l','t','a','d','o',' ','e','s',':'};
      LCDstring(mensaje0, 16);

      ADCSRA |= (1<<ADSC);

      while (ADIF == 1)
      {
         _NOP();
      }
      
      LCDGotoXY(6, 1);
      LCDyear(datoadc);
           
      _delay_ms(250);
      _delay_ms(250);
      _delay_ms(250);
      _delay_ms(250);
   }
	return 0;
}

void LCDyear(unsigned int binario)
{
   uint8_t dato[4];
   uint8_t bcdDecenas = 0x00;
   uint8_t bcdCentenas = 0x00;
   uint8_t bcdMillar = 0x00;

 while (binario > 9) //INICIA PROGRAMA DE LECTURA DE DATOS Y CONVERSIÓN DE BINARIO A BCD
 {
	binario -= 10;
	bcdDecenas++;
	if (bcdDecenas > 9)
	{
	   bcdDecenas = 0x00;
	   bcdCentenas++;
      if (bcdCentenas > 9)
      {
         bcdCentenas = 0x00;
         bcdMillar++;
      }
	}
 } //Guarda la conversión en el arreglo
 	dato[0] = bcdMillar + 0x30;
   dato[1] = bcdCentenas + 0x30;
   dato[2] = bcdDecenas + 0x30;
   dato[3] = binario + 0x30;
   
   LCDstring(dato, 4);
}

void readADC(uint16_t *radc)
{
   *radc = ADCW;   
}
```

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <compat/ina90.h>
#include <inttypes.h>
#include <lcd.h>

Explico a continuación el uso de cada librería.

io.h : Empleada para la definición de los registros de mi microcontrolador, en realidad este archivo incluye el archivo correcto para el microcontrolador seleccionado en la ventana de depuracion.




interrupt.h : Empleada para utilizar las interrupciones del microcontrolador.

delay.h : Famosa en Insituto Tecnológico de Veracruz, por aparecer mensajes de advertencia, porque no poniamos la dirección correcta de la libraría que es la que puse en este documento. Y utilizada para generar retardos por registro. si se utiliza _delay_ms(), el máximo valor es 255 por supuesto milisegundos. Si se utiliza _delay_us(), el máximo valor es 768 me parece. Para que funcione bien y no nos marque errores o advertencia de f_cpu no definido, hay que definirlo en la siguiente ventana: 





Este ventana sale del menu Project y luego seleccionamos el submenu Configuration Options y de la nueva ventana que aparece seleccionamos el menu general como se aprecia en la imagen tengo configurado el reloj a 4MHz y la optimización a -0s ya que lo pide la libreria <util/delay.h>

ina90.h : Utilizada para habilitar y deshabilitar las interrupciones mediante las llamadas _CLI() y _SEI().

inttypes.h : Empleada para la definición de los tipos empleadas en las librerias de winavr tales como uint8_t y uint16_t.

lcd.h : en realidad es una modificación, bueno en realidad solo pegue las definiciones dentro de los encabezado. el cual expongo hasta el final.

A continuación imagenes de como se ve el circuito.









unsigned int datoadc = 0;
Es la variable donde guardo la señal convertida a digital de la conversión analógica a digital.

void LCDyear(unsigned int binario);
Es una función que cree para mi proyecto de titulacion, la cual visualiza el año y como el año y el valor de la conversión analógica a digital tienen el mismo tamaño es decir 4 digitos la utilice para mostrar el valor de la conversión analógica a digital en la pantalla de cristal liquido.

void readADC(uint16_t *radc);
Es la función que se encarga de guardar el dato de la conversión analógica a digital en la variable que mencione arriba.

ISR(ADC_vect)
{
   readADC(&datoadc);
}
Es la forma en que el c de gnu llama a las subrutinas se pone esta función y como parametro se
pone el vector de interrupción el cual viene en el archivo de definiciones de cada microcontrolador en mi caso en el archivo de encabezado iom32.h, y ya solo llaman a la función que realizara el grueso del trabajo. La explico a profundidad mañana porque ya me voy al rancho. saludos a todos.



```
//*****************************************************************************
//
// File Name	: 'lcd_lib.h'
// Title		: 8 and 4 bit LCd interface
// Author		: Scienceprog.com - Copyright (C) 2007
// Created		: 2007-03-29
// Revised		: 2007-08-08
// Version		: 1.0
// Target MCU	: Atmel AVR series
//
// This code is distributed under the GNU Public License
//		which can be found at [url]http://www.gnu.org/licenses/gpl.txt[/url]
//
//*****************************************************************************
#ifndef LCD_LIB
#define LCD_LIB

#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

//Uncomment this if LCD 4 bit interface is used
//******************************************
#define LCD_4bit
//***********************************************

#define LCD_RS	0 	//define MCU pin connected to LCD RS
#define LCD_RW	1 	//define MCU pin connected to LCD R/W
#define LCD_E	2	//define MCU pin connected to LCD E
#define LCD_D0	0	//define MCU pin connected to LCD D0
#define LCD_D1	1	//define MCU pin connected to LCD D1
#define LCD_D2	2	//define MCU pin connected to LCD D1
#define LCD_D3	3	//define MCU pin connected to LCD D2
#define LCD_D4	4	//define MCU pin connected to LCD D3
#define LCD_D5	5	//define MCU pin connected to LCD D4
#define LCD_D6	6	//define MCU pin connected to LCD D5
#define LCD_D7	7	//define MCU pin connected to LCD D6
#define LDP PORTD	//define MCU port connected to LCD data pins
#define LCP PORTD	//define MCU port connected to LCD control pins
#define LDDR DDRD	//define MCU direction register for port connected to LCD data pins
#define LCDR DDRD	//define MCU direction register for port connected to LCD control pins

#define LCD_CLR             0	//DB0: clear display
#define LCD_HOME            1	//DB1: return to home position
#define LCD_ENTRY_MODE      2	//DB2: set entry mode
#define LCD_ENTRY_INC       1	//DB1: increment
#define LCD_ENTRY_SHIFT     0	//DB2: shift
#define LCD_ON_CTRL         3	//DB3: turn lcd/cursor on
#define LCD_ON_DISPLAY      2	//DB2: turn display on
#define LCD_ON_CURSOR       1	//DB1: turn cursor on
#define LCD_ON_BLINK        0	//DB0: blinking cursor
#define LCD_MOVE            4	//DB4: move cursor/display
#define LCD_MOVE_DISP       3	//DB3: move display (0-> move cursor)
#define LCD_MOVE_RIGHT      2	//DB2: move right (0-> left)
#define LCD_FUNCTION        5	//DB5: function set
#define LCD_FUNCTION_8BIT   4	//DB4: set 8BIT mode (0->4BIT mode)
#define LCD_FUNCTION_2LINES 3	//DB3: two lines (0->one line)
#define LCD_FUNCTION_10DOTS 2	//DB2: 5x10 font (0->5x7 font)
#define LCD_CGRAM           6	//DB6: set CG RAM address
#define LCD_DDRAM           7	//DB7: set DD RAM address
// reading:
#define LCD_BUSY            7	//DB7: LCD is busy
#define LCD_LINES			2	//visible lines
#define LCD_LINE_LENGTH		16	//line length (in characters)
// cursor position to DDRAM mapping
#define LCD_LINE0_DDRAMADDR		0x00
#define LCD_LINE1_DDRAMADDR		0x40
#define LCD_LINE2_DDRAMADDR		0x14
#define LCD_LINE3_DDRAMADDR		0x54
// progress bar defines
#define PROGRESSPIXELS_PER_CHAR	6


void LCDsendChar(uint8_t);		//forms data ready to send to 74HC164
void LCDsendCommand(uint8_t);	//forms data ready to send to 74HC164
void LCDinit(void);			//Initializes LCD
void LCDclr(void);				//Clears LCD
void LCDhome(void);			//LCD cursor home
void LCDstring(uint8_t*, uint8_t);	//Outputs string to LCD
void LCDGotoXY(uint8_t, uint8_t);	//Cursor to X Y position
void CopyStringtoLCD(const uint8_t*, uint8_t, uint8_t);//copies flash string to LCD at x,y
void LCDdefinechar(const uint8_t *,uint8_t);//write char to LCD CGRAM 
void LCDshiftRight(uint8_t);	//shift by n characters Right
void LCDshiftLeft(uint8_t);	//shift by n characters Left
void LCDcursorOn(void);		//Underline cursor ON
void LCDcursorOnBlink(void);	//Underline blinking cursor ON
void LCDcursorOFF(void);		//Cursor OFF
void LCDblank(void);			//LCD blank but not cleared
void LCDvisible(void);			//LCD visible
void LCDcursorLeft(uint8_t);	//Shift cursor left by n
void LCDcursorRight(uint8_t);	//shif cursor right by n
// displays a horizontal progress bar at the current cursor location
// <progress> is the value the bargraph should indicate
// <maxprogress> is the value at the end of the bargraph
// <length> is the number of LCD characters that the bargraph should cover
//adapted from AVRLIB - displays progress only for 8 bit variables
void LCDprogressBar(uint8_t progress, uint8_t maxprogress, uint8_t length);

const uint8_t LcdCustomChar[] PROGMEM=//define 8 custom LCD chars
{
	0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, // 0. 0/5 full progress block
	0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, // 1. 1/5 full progress block
	0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, // 2. 2/5 full progress block
	0x00, 0x1F, 0x1C, 0x1C, 0x1C, 0x1C, 0x1F, 0x00, // 3. 3/5 full progress block
	0x00, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x00, // 4. 4/5 full progress block
	0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // 5. 5/5 full progress block
	0x03, 0x07, 0x0F, 0x1F, 0x0F, 0x07, 0x03, 0x00, // 6. rewind arrow
	0x18, 0x1C, 0x1E, 0x1F, 0x1E, 0x1C, 0x18, 0x00  // 7. fast-forward arrow
};


void LCDsendChar(uint8_t ch)		//Sends Char to LCD
{

#ifdef LCD_4bit
	//4 bit part
	LDP=(ch&0b11110000);
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
	LDP=((ch&0b00001111)<<4);
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
#else
	//8 bit part
	LDP=ch;
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
#endif
}
void LCDsendCommand(uint8_t cmd)	//Sends Command to LCD
{
#ifdef LCD_4bit	
	//4 bit part
	LDP=(cmd&0b11110000);
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	LDP=((cmd&0b00001111)<<4);	
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
#else
	//8 bit part
	LDP=cmd;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);	
#endif
}
void LCDinit(void)//Initializes LCD
{
#ifdef LCD_4bit	
	//4 bit part
	_delay_ms(15);
	LDP=0x00;
	LCP=0x00;
	LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //Registro de datos
	LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;            //Registro de control
   //---------one------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(5);
	//-----------two-----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-------three-------------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|0<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//--------4 bit--dual line---------------
	LCDsendCommand(0b00101000);
   //-----increment address, invisible cursor shift------
	LCDsendCommand(0b00001100);
		//init 8 custom chars
	uint8_t ch=0, chn=0;
	while(ch<64)
	{
		LCDdefinechar((LcdCustomChar+ch),chn++);
		ch=ch+8;
	}


#else
	//8 bit part
	_delay_ms(15);
	LDP=0x00;
	LCP=0x00;
	LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<LCD_D3
			|1<<LCD_D2|1<<LCD_D1|1<<LCD_D0;
	LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;
   //---------one------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-----------two-----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-------three-------------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//--------8 bit dual line----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
   //-----increment address, invisible cursor shift------
	LDP=0<<LCD_D7|0<<LCD_D6|0<<LCD_D5|0<<LCD_D4|1<<LCD_D3
			|1<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(5);
		//init custom chars
	uint8_t ch=0, chn=0;
	while(ch<64)
	{
		LCDdefinechar((LcdCustomChar+ch),chn++);
		ch=ch+8;
	}

#endif
}			
void LCDclr(void)				//Clears LCD
{
	LCDsendCommand(1<<LCD_CLR);
}
void LCDhome(void)			//LCD cursor home
{
	LCDsendCommand(1<<LCD_HOME);
}
void LCDstring(uint8_t* data, uint8_t nBytes)	//Outputs string to LCD
{
register uint8_t i;

	// check to make sure we have a good pointer
	if (!data) return;

	// print data
	for(i=0; i<nBytes; i++)
	{
		LCDsendChar(data[i]);
	}
}
void LCDGotoXY(uint8_t x, uint8_t y)	//Cursor to X Y position
{
	register uint8_t DDRAMAddr;
	// remap lines into proper order
	switch(y)
	{
	case 0: DDRAMAddr = LCD_LINE0_DDRAMADDR+x; break;
	case 1: DDRAMAddr = LCD_LINE1_DDRAMADDR+x; break;
	case 2: DDRAMAddr = LCD_LINE2_DDRAMADDR+x; break;
	case 3: DDRAMAddr = LCD_LINE3_DDRAMADDR+x; break;
	default: DDRAMAddr = LCD_LINE0_DDRAMADDR+x;
	}
	// set data address
	LCDsendCommand(1<<LCD_DDRAM | DDRAMAddr);
	
}
//Copies string from flash memory to LCD at x y position
//const uint8_t welcomeln1[] PROGMEM="AVR LCD DEMO\0";
//CopyStringtoLCD(welcomeln1, 3, 1);	
void CopyStringtoLCD(const uint8_t *FlashLoc, uint8_t x, uint8_t y)
{
	uint8_t i;
	LCDGotoXY(x,y);
	for(i=0;(uint8_t)pgm_read_byte(&FlashLoc[i]);i++)
	{
		LCDsendChar((uint8_t)pgm_read_byte(&FlashLoc[i]));
	}
}
//defines char symbol in CGRAM
/*
const uint8_t backslash[] PROGMEM= 
{
0b00000000,//back slash
0b00010000,
0b00001000,
0b00000100,
0b00000010,
0b00000001,
0b00000000,
0b00000000
};
LCDdefinechar(backslash,0);
*/
void LCDdefinechar(const uint8_t *pc,uint8_t char_code){
	uint8_t a, pcc;
	uint16_t i;
	a=(char_code<<3)|0x40;
	for (i=0; i<8; i++){
		pcc=pgm_read_byte(&pc[i]);
		LCDsendCommand(a++);
		LCDsendChar(pcc);
		}
}

void LCDshiftLeft(uint8_t n)	//Scrol n of characters Right
{
	uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x1E);
	}
}
void LCDshiftRight(uint8_t n)	//Scrol n of characters Left
{
	uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x18);
	}
}
void LCDcursorOn(void) //displays LCD cursor
{
	LCDsendCommand(0x0E);
}
void LCDcursorOnBlink(void)	//displays LCD blinking cursor
{
	LCDsendCommand(0x0F);
}
void LCDcursorOFF(void)	//turns OFF cursor
{
	LCDsendCommand(0x0C);
}
void LCDblank(void)		//blanks LCD
{
	LCDsendCommand(0x08);
}
void LCDvisible(void)		//Shows LCD
{
	LCDsendCommand(0x0C);
}
void LCDcursorLeft(uint8_t n)	//Moves cursor by n poisitions left
{
	uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x10);
	}
}
void LCDcursorRight(uint8_t n)	//Moves cursor by n poisitions left
{
	uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x14);
	}
}
//adapted fro mAVRLIB
void LCDprogressBar(uint8_t progress, uint8_t maxprogress, uint8_t length)
{
	uint8_t i;
	uint16_t pixelprogress;
	uint8_t c;

	// draw a progress bar displaying (progress / maxprogress)
	// starting from the current cursor position
	// with a total length of "length" characters
	// ***note, LCD chars 0-5 must be programmed as the bar characters
	// char 0 = empty ... char 5 = full

	// total pixel length of bargraph equals length*PROGRESSPIXELS_PER_CHAR;
	// pixel length of bar itself is
	pixelprogress = ((progress*(length*PROGRESSPIXELS_PER_CHAR))/maxprogress);
	
	// print exactly "length" characters
	for(i=0; i<length; i++)
	{
		// check if this is a full block, or partial or empty
		// (u16) cast is needed to avoid sign comparison warning
		if( ((i*(uint16_t)PROGRESSPIXELS_PER_CHAR)+5) > pixelprogress )
		{
			// this is a partial or empty block
			if( ((i*(uint16_t)PROGRESSPIXELS_PER_CHAR)) > pixelprogress )
			{
				// this is an empty block
				// use space character?
				c = 0;
			}
			else
			{
				// this is a partial block
				c = pixelprogress % PROGRESSPIXELS_PER_CHAR;
			}
		}
		else
		{
			// this is a full block
			c = 5;
		}
		
		// write character to display
		LCDsendChar(c);
	}

}
#endif
```


----------



## torresdelamora (Jun 20, 2008)

saludos, yo agrego un programa que ando haciendo para el atmega32 que es una terminal serial donde monitoreare el llenado de unos contenedores.

todavia me Falta hacer mucho en el, pero ya puedo ejecutar comandos en el desde la hyperterminal

```
/*programa de monitoreo de totes via serial*/
/*todavia esta en fabricacion*/

#include <iom32v.h>
#include <stdio.h>

#define MAXCONT 20
#define RAMEND 0X085F


typedef struct
			{
			unsigned int 	contador;
			unsigned char	dia;
			unsigned char	minuto;
			unsigned char	meshr;
			
			
			}campo_datos;

campo_datos memoria[MAXCONT];



//////////////////////////////////////////////////////////////

void delay2(unsigned char n)
{
	unsigned char a, c;

	for (a = 1; a; a++)
		for (c = 1; c<n; c++);
}


int iniciacampos(void) // simulo un guardado de datos
{

int cont;



for (cont=0;cont<MAXCONT;cont++)
	{
	memoria[cont].contador=4000+cont;
	memoria[cont].dia=7;
	memoria[cont].minuto=3;
	}

return 0;
}


void saca_serial(char *cadena)
{
//char dato;
unsigned char i;

for (i=0;cadena[i]!='\0';i++)
	 	{
		saca_caracter_USART(cadena[i]);
		}
saca_caracter_USART(10);
saca_caracter_USART(13);
}


///////////////////////////////////////////////////////////////
void entrega_reporte(void)
{
char cadena [55];
unsigned char dia=7,mes=5,hora=12,minuto=00;
unsigned int piezas=0;
int cont;


PORTB=0x00;
sprintf(cadena,"Reporte de datos dia %d, Mes %d ",dia,mes);
saca_serial(cadena);
for (cont=0;cont<MAXCONT;cont ++)
	{
	piezas	= memoria[cont].contador;
	dia		= memoria[cont].dia;
	minuto	= memoria[cont].minuto;
	hora	= (memoria[cont].meshr) & 0x0F;
	mes		= (memoria[cont].meshr >>4 ) &0X0F;

	sprintf(cadena,"%d->\t%d/%d/08\t%d:%d\t Tote con %d \tPzas  ",cont,dia,mes,hora,minuto,piezas);
	saca_serial(cadena);
    
	}
sprintf(cadena,"Reporte terminado....");
saca_serial(cadena);

}



void USART_Init( unsigned int baud )
{
/* Set baud rate */
UBRRH = (unsigned char)(baud>>8);
UBRRL = (unsigned char)baud;
/* Habilitacion de transmisor */
UCSRB = (1<<RXEN)|(1<<TXEN);
/* Set frame format: 8data, 2stop bit */
UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}


void saca_caracter_USART( unsigned char dato )
{

while ( !( UCSRA & (1<<UDRE)) ); //espera por si hay una transmision
UDR = dato; //envia el dato
return;
}

unsigned char recibe_caracter_USART( void )
{
while ( !(UCSRA & (1<<RXC)) ); // espera por un dato recibido
return UDR;   // regresa el valor recibido
}

///////////////////////////////////////////////////////////////
int main()
{
int i=0;
unsigned char car;
char cad[45];

DDRD = 0x02;  // solo la salida 1 del puerto d es salida
DDRB = 0XFF;  //el puerto b es salida
DDRA = 0X00;  /*//Puerto A es entrada*/


SPH	= (unsigned char) (RAMEND>>8);
SPL = (unsigned char) (RAMEND);


USART_Init(47);  /* ubrr = 47 para 9600 bauds con cristal de  7.3728 Mhz */


PORTB=0xF0;
iniciacampos();
saca_caracter_USART(10);
saca_caracter_USART(13);
sprintf(cad,"- Prueba de terminal -");
saca_serial(cad);
saca_caracter_USART(10);
saca_caracter_USART(13);
saca_caracter_USART('a');
saca_caracter_USART('v');
saca_caracter_USART('r');
saca_caracter_USART('^');
saca_caracter_USART('\\');

while (1)
	{
	car = recibe_caracter_USART();
	
	if (car!=13 )  // si el caracter es diferente de enter
		{
		cad[i] = car;   // se agrega el caracter recibido
		i++;                                              
		saca_caracter_USART(car);	// se muestra de regreso
		}
	
	else   /// en caso de enter....
		{
		cad[i]='\0';

		saca_caracter_USART(10);
		saca_caracter_USART(13);

		if (!strcmp(cad,"reporta"))
			{
			entrega_reporte();
			}
		else if (!strcmp(cad,"borra"))
			{
			sprintf(cad,"borrando...");
			saca_serial(cad);
			delay2(100);

			sprintf(cad,"terminado");
			saca_serial(cad);
			}
		else if (!strcmp(cad,"?"))
			{
			sprintf(cad,"Comandos:");
			saca_serial(cad);
			sprintf(cad,"reporta\t\tborra");
			saca_serial(cad);
			}
		
		else
			{
			saca_caracter_USART('-');
			saca_serial(cad);
			saca_caracter_USART(' ');
			
			sprintf(cad,"comando no reconocido...");
			saca_serial(cad);
			}
		
		saca_caracter_USART(10);
		saca_caracter_USART(13);
		saca_caracter_USART('a');
		saca_caracter_USART('v');
		saca_caracter_USART('r');
		saca_caracter_USART('^');
		saca_caracter_USART('\\');
		i=0;
		car=' ';
		}
	
		
	
	delay2(250);

	delay2(250);

    }
return 0;
}
```


----------



## robifaria (Jun 22, 2008)

Se agradece la felicitación por el Jtag y muy interesante la descripción de los fuses.
Cuando mencionas que es fácil resucitar el micro lo haces con el procedimiento que explicaste de inyectar una señal con el generador de frecuencia por el pin X...
Buen fin de semana a todos.


----------



## robifaria (Jun 22, 2008)

Encontré en mi disco una hoja de calculo que calcula los fuses, no recuerdo de donde la descargué, pero creo que puede servir.
Sería importante que las personas que han trabajado configurando los fuses le echen una mirada para saber si es confiable o le encuentran alguna pega.
Excel por defecto tiene las macros desabilitadas, para ejecutar las macros hay que bajar la seguridad en Excel.
Cuando presionamos en el boton RUN, aparece un cuadro de diálogo para seleccionar los parámetros.


----------



## fitocondria (Jun 25, 2008)

Perdón por la tardanza, pero por el rancho no he tenido mucho tiempo ni siquiera para mi proyecto de titulación, se supone que ahorita debo estar con el proyecto de titulación.

El metodo que utiliza el C de GNU y c++, es por medio de la llamada ISR, todo lo que expongo viene en el archivo de encabezado del programa winavr llamado interrupt.h. El metodo anterior es signal.h

Se utiliza, bueno yo utilizo el formato(porque es el que recomindan, ya que signal pronto será eliminado a favor de ISR y luego no tengamos sorpresa de ¿porque no se compilan nuestros codigos?):


```
ISR()
{
}
```

entre parentesis va el nombre del vector de interrupción, es decir en el archivo de definiciones de nuestros micros en particular vienen los nombres de los vectores. 

a continuación solo expongo la parte correspondiente a interrupciones para el atmega32 que viene en el archivo iom32.h


```
/* 0x3F SREG */

/* Interrupt vectors */

/* External Interrupt Request 0 */
#define INT0_vect			_VECTOR(1)
#define SIG_INTERRUPT0			_VECTOR(1)

/* External Interrupt Request 1 */
#define INT1_vect			_VECTOR(2)
#define SIG_INTERRUPT1			_VECTOR(2)

/* External Interrupt Request 2 */
#define INT2_vect			_VECTOR(3)
#define SIG_INTERRUPT2			_VECTOR(3)

/* Timer/Counter2 Compare Match */
#define TIMER2_COMP_vect		_VECTOR(4)
#define SIG_OUTPUT_COMPARE2		_VECTOR(4)

/* Timer/Counter2 Overflow */
#define TIMER2_OVF_vect			_VECTOR(5)
#define SIG_OVERFLOW2			_VECTOR(5)

/* Timer/Counter1 Capture Event */
#define TIMER1_CAPT_vect		_VECTOR(6)
#define SIG_INPUT_CAPTURE1		_VECTOR(6)

/* Timer/Counter1 Compare Match A */
#define TIMER1_COMPA_vect		_VECTOR(7)
#define SIG_OUTPUT_COMPARE1A		_VECTOR(7)

/* Timer/Counter1 Compare Match B */
#define TIMER1_COMPB_vect		_VECTOR(8)
#define SIG_OUTPUT_COMPARE1B		_VECTOR(8)

/* Timer/Counter1 Overflow */
#define TIMER1_OVF_vect			_VECTOR(9)
#define SIG_OVERFLOW1			_VECTOR(9)

/* Timer/Counter0 Compare Match */
#define TIMER0_COMP_vect		_VECTOR(10)
#define SIG_OUTPUT_COMPARE0		_VECTOR(10)

/* Timer/Counter0 Overflow */
#define TIMER0_OVF_vect			_VECTOR(11)
#define SIG_OVERFLOW0			_VECTOR(11)

/* Serial Transfer Complete */
#define SPI_STC_vect			_VECTOR(12)
#define SIG_SPI				_VECTOR(12)

/* USART, Rx Complete */
#define USART_RXC_vect			_VECTOR(13)
#define SIG_USART_RECV			_VECTOR(13)
#define SIG_UART_RECV			_VECTOR(13)

/* USART Data Register Empty */
#define USART_UDRE_vect			_VECTOR(14)
#define SIG_USART_DATA			_VECTOR(14)
#define SIG_UART_DATA			_VECTOR(14)

/* USART, Tx Complete */
#define USART_TXC_vect			_VECTOR(15)
#define SIG_USART_TRANS			_VECTOR(15)
#define SIG_UART_TRANS			_VECTOR(15)

/* ADC Conversion Complete */
#define ADC_vect			_VECTOR(16)
#define SIG_ADC				_VECTOR(16)

/* EEPROM Ready */
#define EE_RDY_vect			_VECTOR(17)
#define SIG_EEPROM_READY		_VECTOR(17)

/* Analog Comparator */
#define ANA_COMP_vect			_VECTOR(18)
#define SIG_COMPARATOR			_VECTOR(18)

/* 2-wire Serial Interface */
#define TWI_vect			_VECTOR(19)
#define SIG_2WIRE_SERIAL		_VECTOR(19)

/* Store Program Memory Ready */
#define SPM_RDY_vect			_VECTOR(20)
#define SIG_SPM_READY			_VECTOR(20)

#define _VECTORS_SIZE 84
```

Por cada interrupción viene dos #define:
el  primero que termina con _vect
y el segundo que comienza con SIG_

El primer es el que viene sustituyendo al antigüo método que es por medio de señales. "paradigmas en todo caso" aunque todo tiene una forma y ser.

Por ejemplo para que en el micro se programe que en el vector de interrupción que corresponde al convertidor analógico a digital se realize algo en específico se escribe lo siguiente:


```
ISR(ADC_vect)
{
}
```

Nota:
se puede utilizar SIG_ADC pero ya no es lo recomendable por los propios autores de winavr.

El archivo include io.h se encarga de seleccionar el archivo de encabezado correcto, en mi caso yo utilizo el atmega32, para lo cual se apoya del menu de selección del micro.





con esto el preprocesador sabe que archivo incluir. Esto es así para que resulte transparente a los usuarios el que no tengan que buscar el archivo de encabezado para cada micro. Trampa para los nuevos como yo, al fin y al cabo tengo que buscar el archivo para verificar las definiciones para usarlas jajaja. O se pueden crear sus propios archivos como más gusteis.

En el bloque de código (lo que esta entre llaves{}) ahí podemos poner nuestro código, yo lo que hago es colocar una función que se encarga de guardar el dato del convertidor analógico a digital en un apuntador para su posterior uso. Ustedes pueden hacer lo que gusten.

ISR(ADC_vect)
{
     readADC(&datoadc);
}

Y esto es lo que hace la función 

void readADC(uint16_t *radc);

void readADC(uint16_t *radc)
{
   *radc = ADCW;   
}
[/code]

Así cualquier operación que realize con el dato obtenido de la conversión analógica a digital no afecta el resultado original, ya que luego lo utilizo para visualizar el dato en la pantalla de cristal liquido al convertir este dato binario a bcd y solo sumarle 30 para que represente el número adecuado, pero eso es aparte. 

Me falta poner los parametros utilizados con ISR que son BLOCK y etc. Pero me despido para avanzar con mi proyecto de titulación.


----------



## fitocondria (Jul 16, 2008)

Me decanto por utilizar ensamblador con C. 

Pasas un apuntador a una función y luego ese apuntador a una instrucción condicional y valio el apuntador. A menos que utilizen volatile en la declaración de su apuntador.

Por lo anterior no escribí nada durante este tiempo. Y me preguntaba, ¿Porque no funciona esta .....?. Señores aprendan de todo.  Ese es el mejor aporte que les puedo dar.


----------



## Beamspot (Jul 17, 2008)

Por término general, todas las variables que se modifican en una rutina de servicio a la interrupción (ISR), debe ser declaradas volatile. Eso evita que el compilador las optimice y las haga desaparecer.

Según muchos, esta es la práctica estándar, y la 'filosofía' detrás de la palabra volatile.

De esta manera con:

volatile unsigned int radc;

ISR(ADC_vect)
{
radc=ADCW;
}

debería funcionar.


----------



## fitocondria (Jul 20, 2008)

El apuntador al que hago referencia es del código de mi titulación y no lo he escrito aqui en el foro todavía hasta que este completo.

El código de arriba sino me equivoco es de un ejemplo que puse sobre el uso del convertidor analógico a digital y ese funciona, por eso me desconcerto mi apuntador de mi programa, puesto que el apuntador funciona bien, en el caso del apuntador que me causo problemas es el que paso  a una función y dentro de esa función lo utilizo en una función while para verificar cuando se lleno el tanque de agua. Pero ya quedo resuelto el problema.

Ahora estoy realizando otra parte del proyecto. Pero como estoy mucho tiempo en el rancho no he tenido tiempo de poner los programas que les he mencionado antes, el del temporizador en tiempo real, para generar un calendario con reloj, etc.

Estaba pensando subir solo el codigo, pero creo que sería mejor explicar lo que hice para referenci a y aclaraciones y sirva a todos.

De hecho estaba pensando pedir que pidan programas sencillos para ir conociendo poco a poco las caracteristicas de los micros avr, al menos utilizando el atmega8 por que es el unico que tengo jejeje, pero que se pueden utilizar como ejemplo para los demás micros, y hacerlo tanto en ensamblador como en c. Así yo tambien practico. E incluso estaba pensando utilizar los ejemplos del libro que tiene meta sobre pic y pasarlos a los avr, tanto en ensamblador como a lenjuage C, así podría servir de referencia para los que pueden comprar el libro, y comparar los micros de atmel y de microchip.

¿Que les parece la idea? En el proteus no me gusta mucho simular, porque luego me ha engañado jajaja, sobre todo con el lcd. jajajaj pero nada grave. Así que si pueden conseguir los programadores mucho mejor.


----------



## fitocondria (Jul 24, 2008)

jajaja, se me perdió el libro de pic16f84, así que queda descartada esa opción. Voy a subir nuevas practicas, yo creo que será para la proxima semana. Y comenzaré desde cero con explicaciones de cada paso dado, principalmente una hojeada a la arquitectura, para entender mejor porque se usan más los registros  en lugar de la ram y cosas así.

Nos vemos las próxima semana.


----------



## fitocondria (Ago 8, 2008)

Al instalar las herramientas para trabajar los microcontroladores avr en Debian GNU/Linux 4.1.1-21 encontre algunos ejemplos. Me siento más comodo trabajando en Debian que en Vista, en fin. 

Ahí encontre 2 cosas necesarias para mi proyecto, especificamente para la programación en C para los microcontroladores atmel. Las cuales fueron las siguiente palabras reservadas.

*volatile : *
Todas las variables que son usadas para comunicar valores entre una rutina de servicio de interrupción y la aplicación principal (main function), son declaradas volatile.

*static :*
El especificador de clase de almacenamiento static, cuando se aplica a una variable global o a una función, evita que la utilice alguna función que no está definida en el mismo archivo. A esto se le conoce como vinculación interna. Las variables y las funciones globales que no son precedidas por static en sus definiciones tienen una vinculación externa; se puede acceder a ellas desde otros archivos, si dichos archivos contienen las declaraciones apropiadas y/o los prototipos de las funciones.
Por lo general, el especificador static se utiliza con las funciones de utilidad que son llamadas por las funciones de un archivo en particular. Si no se requiere una función fuera de un archivo en particular, debe reforzarse el principio del menor privilegio por medio de static. Si una función se define antes de que se utilice en un archivo, static debe aplicarse en la definición de la función; de lo contrario, debe aplicarse al prototipo de la función.
Las variables locales que se declaran con la palabra reservada static sólo se reconocen en la función en la que se definen, pero a diferencia de las variables automáticas, las variables locales static retienen su valor, incluso cuando se sale de la función. La siguiente vez que se invoca a la función, la variable local static contiene el valor que tenía cuando la función terminó por última vez. 


¿Qué es lo importate de esto? Si no se utilizan estas palabras reservadas y dependiendo de como se empleen las variables, tendremos problemas en tiempo de ejecución. Es decir nuestro programa se compilara sin ningún problema, el compilador ni el preprocesador nos diran nada. Pero no funcionará de la forma correcta el programa. Por ejemplo no se actualizaban los valores del reloj cuando entraba a una función. En la función main todo funcionaba perfectamente, pero dentro de funciones que necesitan manipular esas variables sus valores no son actualizados. Es algo que ya había expuesto anteriormente, pero ahora con pruebas y recomendaciones de la propria avr-gcc avr-libc. Es decir esto es válido para los que usamos *winavr*, para otro compilador de alguna otra empresa no se si esto es válido.

La información viene en el manual del avr-libc. Específicamente en el ejemplo largedemo.c. De hecho les recomiendo que vean los ejemplos presentados en la documentación.


----------



## microtronic (Ago 10, 2008)

hola amigos tengo un jtagice mkii me lo gane de una encuesta de atmel noruega ;-)
...estoy aprendiendo la arquitectura atmel... y bueno me gustaria saber para conectar el jtag a un atmega 16 y depurar el codigo necesito conectar reisstencia pull-up a los pines...
PC5 (TDI)
PC4 (TDO)
PC3 (TMS)
PC2 (TCK)...
ah otra pregunta cuando programe el micro via  ISP tengo que alimentar el avr o con el vcc y gnd que me proporciona el isp es suficiente..


----------



## fitocondria (Ago 12, 2008)

Yo tengo el mkIIisp y programo el micro cuando tengo alimentado el micro. El propio programador pone en modo programación el micro y cuando termina de realizar su tarea, regresa al microcontrolador al modo ejecución de su programa grabado.





Si puedes, lee la nota de aplicación avr060 para el jtag y para el isp avr069 y el AVR067: JTAGICE mkII Communication Protocol.

Yo no tengo el JTAG pero quiero uno.


----------



## pispud (Nov 16, 2008)

Hola amigos,soy nuevo en este foro y quiero que alguin me ayude para usar un lcd 16X2. Quiero usar el lcd con un avr,uso winavr, e bajado las librerias del lcd, pero nose que debo de hacer con ellas, tengo que pegarlas en una carpeta especial o que? porque en algunos ejemplos que e visto solo ponen #include "lcd_lib.h" y nada mas,por favor que alguin me instruya.Gracias.


----------



## fitocondria (Ene 14, 2009)

Si todavìa necesitas una mano avisa. Tenía tiempo que no revisaba el foro. Pero me parece que al principio puse la libreria completa para emplear un display  lcd de 16x2 del fabricante JHD. Lee los mensajes anteriores cualquier duda, espero aclarartela.


----------



## Y Sánchez (Ene 15, 2009)

hola Fitocondria:

estoy haciendo una aplicación en la que se requiere usar un display de 2*16 y estoy retomando el AVR, un tiempo lo usé progrmándolo con el AVR Studio y en ensamblador,  no se si puedas compartir tu diagrama de conexión del display, de cualquier forma buscaré haber si logro dar con él.

gracias por compartir tu conocimiento con nosotros...


----------



## fitocondria (Ene 30, 2009)

Disculpa la demora. Te debo el diagrama de conexión de mi display lcd de 2 líneas y 16 caracteres. No estoy seguro de la conexión porque cambie varias veces de puerto debido a que conforme iba creciendo mi proyecto lo fuí cambiando de lugar, te paso la librería solo ve que puertos son y ahí conectas tu display. 

Mi problema con librerias de 3eras personas fué el tiempo que ellos asignaban a la inicialización del display.


```
void LCDinit(void)//Initializes LCD
{
#ifdef LCD_4bit	
	//4 bit part
	_delay_ms(50); <-- Cambia el tiempo por lo que tu necesites.
	LDP=0x00;
```

mi librería en ensamblador no me acuerdo bien cuál es. Pero teniendo la librería de C la puedes transladar a ensamblador. Que fué lo que yo hice. Hasta que encontre la hoja de datos del C.I. que controla mi LCD.

a continuación te muestro el código en C de la libreria del LCD, de hecho todas funcionan solo ajusta los puertos de control y de datos de acuerdo a tus necesidades y tambien los tiempos de inicialización del Display LCD.
Por cierto el siguiente código es la librería:

```
//*****************************************************************************
//
// File Name	: 'lcd_lib.h'
// Title		: 8 and 4 bit LCd interface
// Author		: Scienceprog.com - Copyright (C) 2007
// Created		: 2007-03-29
// Revised		: 2007-08-08
// Version		: 1.0
// Target MCU	: Atmel AVR series
//
// This code is distributed under the GNU Public License
//		which can be found at [url]http://www.gnu.org/licenses/gpl.txt[/url]
//
//*****************************************************************************
#ifndef _LCDLIB_H_
#define _LCDLIB_H_

#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>


//Uncomment this if LCD 4 bit interface is used
//******************************************
#define LCD_4bit
//***********************************************

#define LCD_RS	0 	//define MCU pin connected to LCD RS
#define LCD_RW	1 	//define MCU pin connected to LCD R/W
#define LCD_E	2	//define MCU pin connected to LCD E
#define LCD_D0	0	//define MCU pin connected to LCD D0
#define LCD_D1	1	//define MCU pin connected to LCD D1
#define LCD_D2	2	//define MCU pin connected to LCD D1
#define LCD_D3	3	//define MCU pin connected to LCD D2
#define LCD_D4	4	//define MCU pin connected to LCD D3
#define LCD_D5	5	//define MCU pin connected to LCD D4
#define LCD_D6	6	//define MCU pin connected to LCD D5
#define LCD_D7	7	//define MCU pin connected to LCD D6
#define LDP PORTD	//define MCU port connected to LCD data pins
#define LCP PORTD	//define MCU port connected to LCD control pins
#define LDDR DDRD	//define MCU direction register for port connected to LCD data pins
#define LCDR DDRD	//define MCU direction register for port connected to LCD control pins

#define LCD_CLR             0	//DB0: clear display
#define LCD_HOME            1	//DB1: return to home position
#define LCD_ENTRY_MODE      2	//DB2: set entry mode
#define LCD_ENTRY_INC       1	//DB1: increment
#define LCD_ENTRY_SHIFT     0	//DB2: shift
#define LCD_ON_CTRL         3	//DB3: turn lcd/cursor on
#define LCD_ON_DISPLAY      2	//DB2: turn display on
#define LCD_ON_CURSOR       1	//DB1: turn cursor on
#define LCD_ON_BLINK        0	//DB0: blinking cursor
#define LCD_MOVE            4	//DB4: move cursor/display
#define LCD_MOVE_DISP       3	//DB3: move display (0-> move cursor)
#define LCD_MOVE_RIGHT      2	//DB2: move right (0-> left)
#define LCD_FUNCTION        5	//DB5: function set
#define LCD_FUNCTION_8BIT   4	//DB4: set 8BIT mode (0->4BIT mode)
#define LCD_FUNCTION_2LINES 3	//DB3: two lines (0->one line)
#define LCD_FUNCTION_10DOTS 2	//DB2: 5x10 font (0->5x7 font)
#define LCD_CGRAM           6	//DB6: set CG RAM address
#define LCD_DDRAM           7	//DB7: set DD RAM address
// reading:
#define LCD_BUSY            7	//DB7: LCD is busy
#define LCD_LINES			2	//visible lines
#define LCD_LINE_LENGTH		16	//line length (in characters)
// cursor position to DDRAM mapping
#define LCD_LINE0_DDRAMADDR		0x00
#define LCD_LINE1_DDRAMADDR		0x40
#define LCD_LINE2_DDRAMADDR		0x14
#define LCD_LINE3_DDRAMADDR		0x54
// progress bar defines
#define PROGRESSPIXELS_PER_CHAR	6


void LCDsendChar(uint8_t);		//forms data ready to send to 74HC164
void LCDsendCommand(uint8_t);	//forms data ready to send to 74HC164
void LCDinit(void);			//Initializes LCD
void LCDclr(void);				//Clears LCD
void LCDhome(void);			//LCD cursor home
void LCDstring(uint8_t*, uint8_t);	//Outputs string to LCD
void LCDGotoXY(uint8_t, uint8_t);	//Cursor to X Y position
void CopyStringtoLCD(const uint8_t*, uint8_t, uint8_t);//copies flash string to LCD at x,y
void LCDdefinechar(const uint8_t *,uint8_t);//write char to LCD CGRAM 
void LCDshiftRight(uint8_t);	//shift by n characters Right
void LCDshiftLeft(uint8_t);	//shift by n characters Left
void LCDcursorOn(void);		//Underline cursor ON
void LCDcursorOnBlink(void);	//Underline blinking cursor ON
void LCDcursorOFF(void);		//Cursor OFF
void LCDblank(void);			//LCD blank but not cleared
void LCDvisible(void);			//LCD visible
void LCDcursorLeft(uint8_t);	//Shift cursor left by n
void LCDcursorRight(uint8_t);	//shif cursor right by n
// displays a horizontal progress bar at the current cursor location
// <progress> is the value the bargraph should indicate
// <maxprogress> is the value at the end of the bargraph
// <length> is the number of LCD characters that the bargraph should cover
//adapted from AVRLIB - displays progress only for 8 bit variables
void LCDprogressBar(uint8_t progress, uint8_t maxprogress, uint8_t length);


const uint8_t LcdCustomChar[] PROGMEM=//define 8 custom LCD chars
{
	0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, // 0. 0/5 full progress block
	0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, // 1. 1/5 full progress block
	0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, // 2. 2/5 full progress block
	0x00, 0x1F, 0x1C, 0x1C, 0x1C, 0x1C, 0x1F, 0x00, // 3. 3/5 full progress block
	0x00, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x00, // 4. 4/5 full progress block
	0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // 5. 5/5 full progress block
	0x03, 0x07, 0x0F, 0x1F, 0x0F, 0x07, 0x03, 0x00, // 6. rewind arrow
	0x18, 0x1C, 0x1E, 0x1F, 0x1E, 0x1C, 0x18, 0x00  // 7. fast-forward arrow
};


void LCDsendChar(uint8_t ch)		//Sends Char to LCD
{

#ifdef LCD_4bit
	//4 bit part
	LDP=(ch&0b11110000);
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
	LDP=((ch&0b00001111)<<4);
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
#else
	//8 bit part
	LDP=ch;
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
#endif
}
void LCDsendCommand(uint8_t cmd)	//Sends Command to LCD
{
#ifdef LCD_4bit	
	//4 bit part
	LDP=(cmd&0b11110000);
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	LDP=((cmd&0b00001111)<<4);	
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
#else
	//8 bit part
	LDP=cmd;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);	
#endif
}
void LCDinit(void)//Initializes LCD
{
#ifdef LCD_4bit	
	//4 bit part
	_delay_ms(50);
	LDP=0x00;
	LCP=0x00;
	LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //Registro de datos
	LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;            //Registro de control
   //---------one------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(5);
	//-----------two-----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-------three-------------
   LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-------four-------------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|0<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//--------4 bit--dual line---------------
	LCDsendCommand(0b00101000);
   //-----increment address, invisible cursor shift------
	LCDsendCommand(0b00001100);
		//init 8 custom chars
	uint8_t ch=0, chn=0;
	while(ch<64)
	{
		LCDdefinechar((LcdCustomChar+ch),chn++);
		ch=ch+8;
	}


#else
	//8 bit part
	_delay_ms(15);
	LDP=0x00;
	LCP=0x00;
	LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<LCD_D3
			|1<<LCD_D2|1<<LCD_D1|1<<LCD_D0;
	LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;
   //---------one------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-----------two-----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-------three-------------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//--------8 bit dual line----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
   //-----increment address, invisible cursor shift------
	LDP=0<<LCD_D7|0<<LCD_D6|0<<LCD_D5|0<<LCD_D4|1<<LCD_D3
			|1<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(5);
		//init custom chars
	uint8_t ch=0, chn=0;
	while(ch<64)
	{
		LCDdefinechar((LcdCustomChar+ch),chn++);
		ch=ch+8;
	}

#endif
}			
void LCDclr(void)				//Clears LCD
{
	LCDsendCommand(1<<LCD_CLR);
}
void LCDhome(void)			//LCD cursor home
{
	LCDsendCommand(1<<LCD_HOME);
}
void LCDstring(uint8_t* data, uint8_t nBytes)	//Outputs string to LCD
{
register uint8_t i;

	// check to make sure we have a good pointer
	if (!data) return;

	// print data
	for(i=0; i<nBytes; i++)
	{
		LCDsendChar(data[i]);
	}
   LCDcursorOFF();
}
void LCDGotoXY(uint8_t x, uint8_t y)	//Cursor to X Y position
{
	register uint8_t DDRAMAddr;
	// remap lines into proper order
	switch(y)
	{
	case 0: DDRAMAddr = LCD_LINE0_DDRAMADDR+x; break;
	case 1: DDRAMAddr = LCD_LINE1_DDRAMADDR+x; break;
	case 2: DDRAMAddr = LCD_LINE2_DDRAMADDR+x; break;
	case 3: DDRAMAddr = LCD_LINE3_DDRAMADDR+x; break;
	default: DDRAMAddr = LCD_LINE0_DDRAMADDR+x;
	}
	// set data address
	LCDsendCommand(1<<LCD_DDRAM | DDRAMAddr);
	
}
//Copies string from flash memory to LCD at x y position
//const uint8_t welcomeln1[] PROGMEM="AVR LCD DEMO\0";
//CopyStringtoLCD(welcomeln1, 3, 1);	
void CopyStringtoLCD(const uint8_t *FlashLoc, uint8_t x, uint8_t y)
{
	uint8_t i;
	LCDGotoXY(x,y);
	for(i=0;(uint8_t)pgm_read_byte(&FlashLoc[i]);i++)
	{
		LCDsendChar((uint8_t)pgm_read_byte(&FlashLoc[i]));
	}
}
//defines char symbol in CGRAM
/*
const uint8_t backslash[] PROGMEM= 
{
0b00000000,//back slash
0b00010000,
0b00001000,
0b00000100,
0b00000010,
0b00000001,
0b00000000,
0b00000000
};
LCDdefinechar(backslash,0);
*/
void LCDdefinechar(const uint8_t *pc,uint8_t char_code){
	uint8_t a, pcc;
	uint16_t i;
	a=(char_code<<3)|0x40;
	for (i=0; i<8; i++){
		pcc=pgm_read_byte(&pc[i]);
		LCDsendCommand(a++);
		LCDsendChar(pcc);
		}
}

void LCDshiftLeft(uint8_t n)	//Scrol n of characters Right
{
   uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x1E);
	}
}
void LCDshiftRight(uint8_t n)	//Scrol n of characters Left
{
   uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x18);
	}
}
void LCDcursorOn(void) //displays LCD cursor
{
	LCDsendCommand(0x0E);
}
void LCDcursorOnBlink(void)	//displays LCD blinking cursor
{
	LCDsendCommand(0x0F);
}
void LCDcursorOFF(void)	//turns OFF cursor
{
	LCDsendCommand(0x0C);
}
void LCDblank(void)		//blanks LCD
{
	LCDsendCommand(0x08);
}
void LCDvisible(void)		//Shows LCD
{
	LCDsendCommand(0x0C);
}
void LCDcursorLeft(uint8_t n)	//Moves cursor by n poisitions left
{
   uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x10);
	}
}
void LCDcursorRight(uint8_t n)	//Moves cursor by n poisitions left
{
   uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x14);
	}
}
//adapted fro mAVRLIB
void LCDprogressBar(uint8_t progress, uint8_t maxprogress, uint8_t length)
{
	uint8_t i;
	uint16_t pixelprogress;
	uint8_t c;

	// draw a progress bar displaying (progress / maxprogress)
	// starting from the current cursor position
	// with a total length of "length" characters
	// ***note, LCD chars 0-5 must be programmed as the bar characters
	// char 0 = empty ... char 5 = full

	// total pixel length of bargraph equals length*PROGRESSPIXELS_PER_CHAR;
	// pixel length of bar itself is
	pixelprogress = ((progress*(length*PROGRESSPIXELS_PER_CHAR))/maxprogress);
	
	// print exactly "length" characters
	for(i=0; i<length; i++)
	{
		// check if this is a full block, or partial or empty
		// (u16) cast is needed to avoid sign comparison warning
		if( ((i*(uint16_t)PROGRESSPIXELS_PER_CHAR)+5) > pixelprogress )
		{
			// this is a partial or empty block
			if( ((i*(uint16_t)PROGRESSPIXELS_PER_CHAR)) > pixelprogress )
			{
				// this is an empty block
				// use space character?
				c = 0;
			}
			else
			{
				// this is a partial block
				c = pixelprogress % PROGRESSPIXELS_PER_CHAR;
			}
		}
		else
		{
			// this is a full block
			c = 5;
		}
		
		// write character to display
		LCDsendChar(c);
	}

}



#endif
```

En la librería del display LCD viene la configuración para 4 u 8 lineas de datos, las 3 de control se mantienen, te lo menciono porque algunas librerias solo manejan 2 lineas de control.


```
#ifdef LCD_4bit	
	//4 bit part
	_delay_ms(50);
	LDP=0x00;
	LCP=0x00;
	LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //Registro de datos
	LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;            //Registro de control

#else
	//8 bit part
	_delay_ms(15);
	LDP=0x00;
	LCP=0x00;
	LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<LCD_D3
			|1<<LCD_D2|1<<LCD_D1|1<<LCD_D0;
	LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;
```

Como te muestro a continuación al principio de la libreria se definen donde van a conectarse las lineas de datos y de control del display LCD.


```
#define LCD_RS	0 	//define MCU pin connected to LCD RS
#define LCD_RW	1 	//define MCU pin connected to LCD R/W
#define LCD_E	2	//define MCU pin connected to LCD E
#define LCD_D0	0	//define MCU pin connected to LCD D0
#define LCD_D1	1	//define MCU pin connected to LCD D1
#define LCD_D2	2	//define MCU pin connected to LCD D1
#define LCD_D3	3	//define MCU pin connected to LCD D2
#define LCD_D4	4	//define MCU pin connected to LCD D3
#define LCD_D5	5	//define MCU pin connected to LCD D4
#define LCD_D6	6	//define MCU pin connected to LCD D5
#define LCD_D7	7	//define MCU pin connected to LCD D6
#define LDP PORTD	//define MCU port connected to LCD data pins
#define LCP PORTD	//define MCU port connected to LCD control pins
#define LDDR DDRD	//define MCU direction register for port connected to LCD data pins
#define LCDR DDRD	//define MCU direction register for port connected to LCD control pins
```

con los siguientes comandos envias los datos al display y el control sobre esos datos:


```
datos enviados:
LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<LCD_D3
			|1<<LCD_D2|1<<LCD_D1|1<<LCD_D0;
control aplicado a los datos:
LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;
```
Por lo anterior solo queda decir que tú decides en que puerto o puertos colocas tu Display LCD de acuerdo a tus necesidades.

Y un programa que hice en ensamblador para manejar el display, similar a uno que encontre pero lo ordene y no me acuerdo bien que le agregue, espero te sirva de guía.


```
#pragma AVRPART ADMIN PART_NAME ATmega32

#pragma AVRPART MEMORY PROG_FLASH 32768

#pragma AVRPART MEMORY EEPROM 1024

#pragma AVRPART MEMORY INT_SRAM SIZE 2048

#pragma AVRPART MEMORY INT_SRAM START_ADDR 0x60

.include "m32def.inc"

.CSEG

        rjmp    RESET

RESET:
   ldi   r16,HIGH(RAMEND) ;Configura la pila
   out   SPH,r16            ;para utilizar subrutinas
   ldi   r16,LOW(RAMEND)   
   out   SPL,r16 

   call  UNSEG
   call  INI_LCD
NOMBRE:      
   ldi   r16,0x41
   call  caracterLCD
   ldi   r16,0x44
   call  caracterLCD
   ldi   r16,0x4F
   call  caracterLCD
   ldi   r16,0x4C
   call  caracterLCD
   ldi   r16,0x46
   call  caracterLCD
   ldi   r16,0x4F
   call  caracterLCD
   ldi   r16,0x02
   call  comandoLCD
   call  UNSEG
   rjmp  NOMBRE

/*************************************************************************
* Subrutina
* Nombre    : INI_LCD
* 
* Proposito : Inicializa el LCD por instrucción. 
*             PORTD = DATOS; PORTC,0 = RS; PORTC,1 = E.
*             Basado en la pagina 46 de la hoja de datos del HD44780U.PDF
*************************************************************************/
INI_LCD:
   ser   r16
   out   DDRD,r16       ;Configura puerto de datos como salida
   ldi   r16,0b00000011
   out   DDRC,r16       ;Configura puerto de control como salida
   nop                  ;Actualiza registros
   cbi   PORTC,0        ;0->RS
   cbi   PORTC,1        ;0->E
   call  TREINTAMS
   ldi   r16,0x38       ;Inicializa LCD
   call  comandoLCD
   call  CINCOMS
   ldi   r16,0x38       ;Inicializa LCD
   call  comandoLCD
   call  UNMS
   ldi   r16,0x38       ;Function Set
   call  comandoLCD
   call  UNMS
   ldi   r16,0x0C       ;Display on
   call  comandoLCD
   call  UNMS
   ldi   r16,0x01       ;Display clear
   call  comandoLCD
   call  UNMS
   ldi   r16,0x06       ;Entry Mode Set
   call  comandoLCD
   call  UNMS
   ldi   r16,0x02       ;Return Home
   call  comandoLCD
   call  UNMS
   call  UNMS
   ret

/*************************************************************************
* Subrutina
* Nombre    : comandoLCD
* 
* Proposito : Envía un dato al bus de datos del LCD para ser procesado
*             como un comando que modifica el comportamiento del LCD
*************************************************************************/
comandoLCD:
   cbi   PORTC,0        ;0->RS
   cbi   PORTC,1        ;0->E
   out   PORTD,r16      ;Envía el dato al bus de datos
   call  habilitaLCD
   ret

/*************************************************************************
* Subrutina
*Nombre     : caracterLCD
*
*Proposito  : Envía un dato al bus de datos del LCD para ser procesado  
*             como un caracter alfanumérico a visualizarse en el LCD
*************************************************************************/
caracterLCD:
   sbi   PORTC,0        ;1->RS
   cbi   PORTC,1        ;0->E
   out   PORTD,r16      ;Envía el dato al bus de datos
   call  habilitaLCD
   ret

/*************************************************************************
* Subrutina
* Nombre    : habilitaLCD
* 
* Proposito : Activa el LCD para procesar las instrucciones ya sean estas
*             Instrucciones de comando ó Instrucciones de datos
*************************************************************************/
habilitaLCD:
   sbi   PORTC,1        ;1->E
   ldi   r16,0xFF
HLCD:
   dec   r16
   brne  HLCD
   cbi   PORTC,1        ;0->E
   ret

/*************************************************************************
*Subrutina
*Nombre     : UNSEG
*
* Propósito : Genera un temporizado de un segundo. realmente 1002897
*************************************************************************/
UNSEG:
   ldi   r16,14
UNSEG2:
   ldi   r17,95
UNSEG1:
   ldi   r18,250
UNSEG0:
   dec   r18
   brne  UNSEG0
   dec   r17
   brne  UNSEG1
   dec   r16
   brne  UNSEG2
   ret

/*************************************************************************
* Subrutina
* Nombre    : TREINTAMS
*
* Propósito : Genera un temporizado de 30 milisegundos. realmente 30.172ms
*************************************************************************/
TREINTAMS:
   ldi   r16,15
TREINTAMS2:
   ldi   r17,59
TREINTAMS1:
   ldi   r18,10
TREINTAMS0:
   dec   r18
   brne  TREINTAMS0
   dec   r17
   brne  TREINTAMS1
   dec   r16
   brne  TREINTAMS2
   ret

/*************************************************************************
* Subrutina
* Nombre    : CINCOMS
*
* Propósito : Genera un temporizado de 5 milisegundos. realmente 5.011ms
*************************************************************************/
CINCOMS:
   ldi   r16,9
CINCOMS2:
   ldi   r17,29
CINCOMS1:
   ldi   r18,5
CINCOMS0:
   dec   r18
   brne  CINCOMS0
   dec   r17
   brne  CINCOMS1
   dec   r16
   brne  CINCOMS2  
   ret
/*************************************************************************
* Subrutina
* Nombre    : UNMS
*
* Propósito : Genera un temporizado de 1 milisegundo. realmente 1ms
*************************************************************************/
UNMS:
   ldi   r16,4
UNMS2:
   ldi   r17,11
UNMS1:
   ldi   r18,6
UNMS0:
   dec   r18
   brne  UNMS0
   dec   r17
   brne  UNMS1
   dec   r16
   brne  UNMS2
   nop
   nop
   nop
   nop
   nop
   ret
```
Al archivo lo nombre ks0066 porque ese es el controlador de mi display LCD. No esta demás que revises cuál es tu controlador, porque mi problema es que todos mis compañeros manejaban el jhd *** y yo manejaba otro y a todos les funcionaba menos a mi hasta que modifique los tiempos de inicialización de ahí en fuera eran iguales en todo.


----------



## Y Sánchez (Ene 30, 2009)

Muchas gracias, lo revisaremos a detalle, y estoy de acuerdo contigo, en que lo delicado son los tiempos y quizá el comportamiento de los puertos del MCU  empleados....


----------



## fitocondria (Ene 30, 2009)

Si no les urge mucho, el lunes les pongo un ejemplo del display lcd, con diagrama y foto funcionando. solo digan si quiere el ejemplo en ensamblador o en c. Digo hasta el lunes porque mañana me voy al rancho y regreso el domingo en la noche. 

Saludos  y a leer. Aunque creo que puse un ejemplo. Pero de todas formas digan que para eso estamos por aquí. Para tratar de apoyarnos con lo que podemos.


----------



## Toño (Feb 9, 2009)

Me gustaria que pusieras el ejemplo del display lcd pero en C...Gracias de antemano


----------



## beto_mmf (Feb 10, 2009)

mi amigo fitocondria tengo una duda    .
al querer simular en el AVR studio el Atmega32
en el menu DEBUG - "AVR SIMUlATOR OPTIONS "
pongo una frecuencia de reloj de 10  Mhz    y al simular
me sale un mensaje , que dice la velocidad sobrepaso el limite del dispositivo

no entiendo por que , tal vez sea que el simulador trabaja con el reloj interno 
que llega a un maximo de 8Mz.  y si es asi como hago para simular 
con relojes  superiores a los 8 Mhz , por ejemplo 10Mhz .

http://imageshack.us


----------



## fitocondria (Feb 18, 2009)

Primero lo del reloj. El ATMega32 tiene una frecuencia de funcionamiento de 8MHz máxima sin cristal oscilador externo, para utilizar una frecuencia mayor necesitas emplear un cristal externo.

Para realizar simulaciones el mismo programa de simulación límita de acuerdo a sus funciones implementadas.

Es decir que si en Simulator Options, en la etiqueta de Device selection, tu seleccionas un dispositivo cualquiera el programa solo te deja seleccionar las velocidades que el puede manejar es decir el propio simulador no el dispositivo. Yo he comprobado que para la versión que tengo de AVRStudio, para el ATMega32 solo me permite seleccionar un reloj de frecuencia máxima de 8MHz y en el propio cuadro de información aparece la velocidad Máxima.

Algo curioso de mencionar es lo siguiente en la versión 4.13 de AVRStudio me permite seleccionar una frecuencia máxima de 12MHz y en la versión 4.14 de AVRStudio me permite seleccionar una frecuencia máxima de 8MHz.









Es decir encontraste un Bug o error pero que en la versión siguiente ya fué corregido. En la imagen de arriba se ve que me aparece la misma advertencia. Pero si vemos las siguientes imagenes. Ya no aparece, porque solo me permite seleccionar la frecuencia marcada por el cuadro de información. 









Conclusión: Solo puedes emplear la velocidad de reloj que te indique el cuadro de información. Al menos eso me indica lo anterior. por lo cual no te puedo decir como hacerle para que simules con una velocidad superior a 8MHz, sino es que modificando el programa de AVRSimulator 2. Lo mejor es actualizar el software si lo necesitas.


----------



## fitocondria (Feb 18, 2009)

Para el display LCD quería probar de nuevo los programas que hice pero no encuentro mi cable para el programador. Voy a poner la librería y un pequeño ejemplo sin probar si es que no está en los ejemplos anteriores lo del display.

Revisando. . .

En la página 2 de este tema hay un ejemplo que puse del convertidor analógico a digital en el que empleo el display LCD. 

La librería del LCD es la siguiente:


```
//*****************************************************************************
//
// File Name	: 'lcd_lib.h'
// Title		: 8 and 4 bit LCd interface
// Author		: Scienceprog.com - Copyright (C) 2007
// Created		: 2007-03-29
// Revised		: 2007-08-08
// Version		: 1.0
// Target MCU	: Atmel AVR series
//
// This code is distributed under the GNU Public License
//		which can be found at [url]http://www.gnu.org/licenses/gpl.txt[/url]
//
//*****************************************************************************
#ifndef _LCDLIB_H_
#define _LCDLIB_H_

#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>


//Uncomment this if LCD 4 bit interface is used
//******************************************
#define LCD_4bit
//***********************************************

#define LCD_RS	0 	//define MCU pin connected to LCD RS
#define LCD_RW	1 	//define MCU pin connected to LCD R/W
#define LCD_E	2	//define MCU pin connected to LCD E
#define LCD_D0	0	//define MCU pin connected to LCD D0
#define LCD_D1	1	//define MCU pin connected to LCD D1
#define LCD_D2	2	//define MCU pin connected to LCD D1
#define LCD_D3	3	//define MCU pin connected to LCD D2
#define LCD_D4	4	//define MCU pin connected to LCD D3
#define LCD_D5	5	//define MCU pin connected to LCD D4
#define LCD_D6	6	//define MCU pin connected to LCD D5
#define LCD_D7	7	//define MCU pin connected to LCD D6
#define LDP PORTD	//define MCU port connected to LCD data pins
#define LCP PORTD	//define MCU port connected to LCD control pins
#define LDDR DDRD	//define MCU direction register for port connected to LCD data pins
#define LCDR DDRD	//define MCU direction register for port connected to LCD control pins

#define LCD_CLR             0	//DB0: clear display
#define LCD_HOME            1	//DB1: return to home position
#define LCD_ENTRY_MODE      2	//DB2: set entry mode
#define LCD_ENTRY_INC       1	//DB1: increment
#define LCD_ENTRY_SHIFT     0	//DB2: shift
#define LCD_ON_CTRL         3	//DB3: turn lcd/cursor on
#define LCD_ON_DISPLAY      2	//DB2: turn display on
#define LCD_ON_CURSOR       1	//DB1: turn cursor on
#define LCD_ON_BLINK        0	//DB0: blinking cursor
#define LCD_MOVE            4	//DB4: move cursor/display
#define LCD_MOVE_DISP       3	//DB3: move display (0-> move cursor)
#define LCD_MOVE_RIGHT      2	//DB2: move right (0-> left)
#define LCD_FUNCTION        5	//DB5: function set
#define LCD_FUNCTION_8BIT   4	//DB4: set 8BIT mode (0->4BIT mode)
#define LCD_FUNCTION_2LINES 3	//DB3: two lines (0->one line)
#define LCD_FUNCTION_10DOTS 2	//DB2: 5x10 font (0->5x7 font)
#define LCD_CGRAM           6	//DB6: set CG RAM address
#define LCD_DDRAM           7	//DB7: set DD RAM address
// reading:
#define LCD_BUSY            7	//DB7: LCD is busy
#define LCD_LINES			2	//visible lines
#define LCD_LINE_LENGTH		16	//line length (in characters)
// cursor position to DDRAM mapping
#define LCD_LINE0_DDRAMADDR		0x00
#define LCD_LINE1_DDRAMADDR		0x40
#define LCD_LINE2_DDRAMADDR		0x14
#define LCD_LINE3_DDRAMADDR		0x54
// progress bar defines
#define PROGRESSPIXELS_PER_CHAR	6


void LCDsendChar(uint8_t);		//forms data ready to send to 74HC164
void LCDsendCommand(uint8_t);	//forms data ready to send to 74HC164
void LCDinit(void);			//Initializes LCD
void LCDclr(void);				//Clears LCD
void LCDhome(void);			//LCD cursor home
void LCDstring(uint8_t*, uint8_t);	//Outputs string to LCD
void LCDGotoXY(uint8_t, uint8_t);	//Cursor to X Y position
void CopyStringtoLCD(const uint8_t*, uint8_t, uint8_t);//copies flash string to LCD at x,y
void LCDdefinechar(const uint8_t *,uint8_t);//write char to LCD CGRAM 
void LCDshiftRight(uint8_t);	//shift by n characters Right
void LCDshiftLeft(uint8_t);	//shift by n characters Left
void LCDcursorOn(void);		//Underline cursor ON
void LCDcursorOnBlink(void);	//Underline blinking cursor ON
void LCDcursorOFF(void);		//Cursor OFF
void LCDblank(void);			//LCD blank but not cleared
void LCDvisible(void);			//LCD visible
void LCDcursorLeft(uint8_t);	//Shift cursor left by n
void LCDcursorRight(uint8_t);	//shif cursor right by n
// displays a horizontal progress bar at the current cursor location
// <progress> is the value the bargraph should indicate
// <maxprogress> is the value at the end of the bargraph
// <length> is the number of LCD characters that the bargraph should cover
//adapted from AVRLIB - displays progress only for 8 bit variables
void LCDprogressBar(uint8_t progress, uint8_t maxprogress, uint8_t length);


const uint8_t LcdCustomChar[] PROGMEM=//define 8 custom LCD chars
{
	0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, // 0. 0/5 full progress block
	0x00, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x1F, 0x00, // 1. 1/5 full progress block
	0x00, 0x1F, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, // 2. 2/5 full progress block
	0x00, 0x1F, 0x1C, 0x1C, 0x1C, 0x1C, 0x1F, 0x00, // 3. 3/5 full progress block
	0x00, 0x1F, 0x1E, 0x1E, 0x1E, 0x1E, 0x1F, 0x00, // 4. 4/5 full progress block
	0x00, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x00, // 5. 5/5 full progress block
	0x03, 0x07, 0x0F, 0x1F, 0x0F, 0x07, 0x03, 0x00, // 6. rewind arrow
	0x18, 0x1C, 0x1E, 0x1F, 0x1E, 0x1C, 0x18, 0x00  // 7. fast-forward arrow
};


void LCDsendChar(uint8_t ch)		//Sends Char to LCD
{

#ifdef LCD_4bit
	//4 bit part
	LDP=(ch&0b11110000);
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
	LDP=((ch&0b00001111)<<4);
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
#else
	//8 bit part
	LDP=ch;
	LCP|=1<<LCD_RS;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);	
	LCP&=~(1<<LCD_RS);
	_delay_ms(1);
#endif
}
void LCDsendCommand(uint8_t cmd)	//Sends Command to LCD
{
#ifdef LCD_4bit	
	//4 bit part
	LDP=(cmd&0b11110000);
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	LDP=((cmd&0b00001111)<<4);	
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
#else
	//8 bit part
	LDP=cmd;
	LCP|=1<<LCD_E;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);	
#endif
}
void LCDinit(void)//Initializes LCD
{
#ifdef LCD_4bit	
	//4 bit part
	_delay_ms(50);
	LDP=0x00;
	LCP=0x00;
	LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //Registro de datos
	LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;            //Registro de control
   //---------one------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(5);
	//-----------two-----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-------three-------------
   LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-------four-------------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|0<<LCD_D4; //4 bit mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//--------4 bit--dual line---------------
	LCDsendCommand(0b00101000);
   //-----increment address, invisible cursor shift------
	LCDsendCommand(0b00001100);
		//init 8 custom chars
	uint8_t ch=0, chn=0;
	while(ch<64)
	{
		LCDdefinechar((LcdCustomChar+ch),chn++);
		ch=ch+8;
	}


#else
	//8 bit part
	_delay_ms(15);
	LDP=0x00;
	LCP=0x00;
	LDDR|=1<<LCD_D7|1<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<LCD_D3
			|1<<LCD_D2|1<<LCD_D1|1<<LCD_D0;
	LCDR|=1<<LCD_E|1<<LCD_RW|1<<LCD_RS;
   //---------one------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-----------two-----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//-------three-------------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|0<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
	//--------8 bit dual line----------
	LDP=0<<LCD_D7|0<<LCD_D6|1<<LCD_D5|1<<LCD_D4|1<<LCD_D3
			|0<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(1);
   //-----increment address, invisible cursor shift------
	LDP=0<<LCD_D7|0<<LCD_D6|0<<LCD_D5|0<<LCD_D4|1<<LCD_D3
			|1<<LCD_D2|0<<LCD_D1|0<<LCD_D0; //8 it mode
	LCP|=1<<LCD_E|0<<LCD_RW|0<<LCD_RS;		
	_delay_ms(1);
	LCP&=~(1<<LCD_E);
	_delay_ms(5);
		//init custom chars
	uint8_t ch=0, chn=0;
	while(ch<64)
	{
		LCDdefinechar((LcdCustomChar+ch),chn++);
		ch=ch+8;
	}

#endif
}			
void LCDclr(void)				//Clears LCD
{
	LCDsendCommand(1<<LCD_CLR);
}
void LCDhome(void)			//LCD cursor home
{
	LCDsendCommand(1<<LCD_HOME);
}
void LCDstring(uint8_t* data, uint8_t nBytes)	//Outputs string to LCD
{
register uint8_t i;

	// check to make sure we have a good pointer
	if (!data) return;

	// print data
	for(i=0; i<nBytes; i++)
	{
		LCDsendChar(data[i]);
	}
   LCDcursorOFF();
}
void LCDGotoXY(uint8_t x, uint8_t y)	//Cursor to X Y position
{
	register uint8_t DDRAMAddr;
	// remap lines into proper order
	switch(y)
	{
	case 0: DDRAMAddr = LCD_LINE0_DDRAMADDR+x; break;
	case 1: DDRAMAddr = LCD_LINE1_DDRAMADDR+x; break;
	case 2: DDRAMAddr = LCD_LINE2_DDRAMADDR+x; break;
	case 3: DDRAMAddr = LCD_LINE3_DDRAMADDR+x; break;
	default: DDRAMAddr = LCD_LINE0_DDRAMADDR+x;
	}
	// set data address
	LCDsendCommand(1<<LCD_DDRAM | DDRAMAddr);
	
}
//Copies string from flash memory to LCD at x y position
//const uint8_t welcomeln1[] PROGMEM="AVR LCD DEMO\0";
//CopyStringtoLCD(welcomeln1, 3, 1);	
void CopyStringtoLCD(const uint8_t *FlashLoc, uint8_t x, uint8_t y)
{
	uint8_t i;
	LCDGotoXY(x,y);
	for(i=0;(uint8_t)pgm_read_byte(&FlashLoc[i]);i++)
	{
		LCDsendChar((uint8_t)pgm_read_byte(&FlashLoc[i]));
	}
}
//defines char symbol in CGRAM
/*
const uint8_t backslash[] PROGMEM= 
{
0b00000000,//back slash
0b00010000,
0b00001000,
0b00000100,
0b00000010,
0b00000001,
0b00000000,
0b00000000
};
LCDdefinechar(backslash,0);
*/
void LCDdefinechar(const uint8_t *pc,uint8_t char_code){
	uint8_t a, pcc;
	uint16_t i;
	a=(char_code<<3)|0x40;
	for (i=0; i<8; i++){
		pcc=pgm_read_byte(&pc[i]);
		LCDsendCommand(a++);
		LCDsendChar(pcc);
		}
}

void LCDshiftLeft(uint8_t n)	//Scrol n of characters Right
{
   uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x1E);
	}
}
void LCDshiftRight(uint8_t n)	//Scrol n of characters Left
{
   uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x18);
	}
}
void LCDcursorOn(void) //displays LCD cursor
{
	LCDsendCommand(0x0E);
}
void LCDcursorOnBlink(void)	//displays LCD blinking cursor
{
	LCDsendCommand(0x0F);
}
void LCDcursorOFF(void)	//turns OFF cursor
{
	LCDsendCommand(0x0C);
}
void LCDblank(void)		//blanks LCD
{
	LCDsendCommand(0x08);
}
void LCDvisible(void)		//Shows LCD
{
	LCDsendCommand(0x0C);
}
void LCDcursorLeft(uint8_t n)	//Moves cursor by n poisitions left
{
   uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x10);
	}
}
void LCDcursorRight(uint8_t n)	//Moves cursor by n poisitions left
{
   uint8_t i;
	for (i=0;i<n;i++)
	{
		LCDsendCommand(0x14);
	}
}
//adapted fro mAVRLIB
void LCDprogressBar(uint8_t progress, uint8_t maxprogress, uint8_t length)
{
	uint8_t i;
	uint16_t pixelprogress;
	uint8_t c;

	// draw a progress bar displaying (progress / maxprogress)
	// starting from the current cursor position
	// with a total length of "length" characters
	// ***note, LCD chars 0-5 must be programmed as the bar characters
	// char 0 = empty ... char 5 = full

	// total pixel length of bargraph equals length*PROGRESSPIXELS_PER_CHAR;
	// pixel length of bar itself is
	pixelprogress = ((progress*(length*PROGRESSPIXELS_PER_CHAR))/maxprogress);
	
	// print exactly "length" characters
	for(i=0; i<length; i++)
	{
		// check if this is a full block, or partial or empty
		// (u16) cast is needed to avoid sign comparison warning
		if( ((i*(uint16_t)PROGRESSPIXELS_PER_CHAR)+5) > pixelprogress )
		{
			// this is a partial or empty block
			if( ((i*(uint16_t)PROGRESSPIXELS_PER_CHAR)) > pixelprogress )
			{
				// this is an empty block
				// use space character?
				c = 0;
			}
			else
			{
				// this is a partial block
				c = pixelprogress % PROGRESSPIXELS_PER_CHAR;
			}
		}
		else
		{
			// this is a full block
			c = 5;
		}
		
		// write character to display
		LCDsendChar(c);
	}

}



#endif
```

No es mi librería, pero es la que usé y funciona muy bien. Ahora es cuestión de fijarse en como la utilizo en el ejemplo del convertidor analógico a digital. Si algo no esta bien claro, adelante, con confianza pregunta, pero mientras no encuentre mi cable no voy a poder programar y probar los ejemplos.


----------



## fitocondria (Feb 19, 2009)

Y Sánchez dijo:
			
		

> Muchas gracias, lo revisaremos a detalle, y estoy de acuerdo contigo, en que lo delicado son los tiempos y quizá el comportamiento de los puertos del MCU  empleados....



Tienes toda la razón Y Sánchez. Los dos display lcd que tengo de 16*2 no funcionan en cierta conexión en mi atmega32, no me acuerdo de cual es, pero eso me sucedio con los dos, tanto con el jhd como con el tianma. Pero era solo un pin que no me acuerdo cual es. Creo que era en el puerto D. Que por cierto en la simulación del proteus si funciona pero en la practica no funcionaba. Lo mismo me pasaba con lo tiempos de inicialización no importaban en el proteus porque ahí si funcionaba, pero en protoboard no funcionaba y el error solo eran los tiempos de inicialización del LCD.

Así que si no les funciona el lcd pruebenlo en otros puertos, yo hablo por el atmega 32 no se si esto pase tambien en otros microcontroladores de atmel ó es burrada mía. Y los tiempos de inicialización hay que verificarlos, tal y como expongo en una respuesta anterior en este mismo tema.


----------



## kain589 (Mar 11, 2009)

Saludos, estoy interesado en empezar a programar con winavr, pero no encuentro un documento con las funciones que implementa y su sintaxis, me refiero a: configurar perifericos,declaracion variables,sintaxis de cada funcion y que hace...algo parecido a los manuales de C normales, o cd CCs para pic.

¿Alguien sabe donde puedo encontrar algo parecido?


----------



## cristian_elect (Mar 11, 2009)

El archivo de información que biene con el paquete del winavr esta todo. 
Tambien biene en los pdf de los chips atmel hay ejemplos de winavr para configurar puertos y mas.


----------



## kain589 (Mar 11, 2009)

Ok, gracias, creo que te refieres al manual "avr-libc-user-manual" que tiene unas 400 paginas, es verdad las funciones viene al final, divididas por librerias. Tambien tendre en cuenta lo de los datasheet


----------



## dkns (Jul 7, 2009)

fitocondria dijo:
			
		

> Inicio este tema, debido a que varios habían expresado su interes en los microcontroladores de atmel, y debido a mi asesor de tesis, el cual me sugirio que utilizara el microcontrolador atmega32 de la compañia atmel, inicio estas series de prácticas mientras veo futurama.
> 
> Lo siguiente que utilizaré para las prácticas es lo siguiente.
> 
> ...



Que tal amigo, oye tengo una duda que no he encontrado en ningun lado como resolver, y es que como puedo crear una libreria .h (por ejemplo "algo.h") en el AVR studio 4 para el programa que estoy haciendo C y asi ya solo llamarlo con include

y otra duda es que que diferencia hay entre  una libreria que usa < > y una xon " " por ejemplo.. #include <ioavr.h> e #include "stdint.h"?

bueno de ante mano gracias.


----------



## jabc88 (Oct 3, 2009)

comp uedo desbloquear el atmega32? por error lo grabe con oscilador externo de 8MHz y en realidad es interno.


----------



## sqaw (Oct 19, 2009)

no se si voy a yudar mucho, ya veo q es un poco tarde dkns pero hay q poner

#ifndef _ALGO_H
#define _ALGO_H

en el propio archivo de .h y después lo añades al proyecto en el programa q este usando. las librerias q tu hayas creado las llamas con comillas "" y las q estan ya definidas pues las llamas con <>. No soy ninguna experta asi q qiza no, pero si aun tienes la duda lo puedes probar.

mi duda es q creo q tambien he programado mal la frecuencia de mi ATmega128, y ya se q en un post esta explicado pero no me qeda muy claro. si alguien me puede ayudar, genial!


----------



## gonpa (Ago 15, 2011)

Alguien sabe por que cuando uso el delay _delay_ms(xvalor); el tamaño de mi programa cre una brutalidad y cuando uno _delay_loop_2(xvalor); no si respetos los valores por las dudas, pero de un programa con que uso el _delay_loop_2(xvalor); a  _delay_ms(xvalor); el tamaño crece de unos 370bytes a 3500byte por ejemplo.

programo en avr studio 5.

muchas gracias espero que me puedan aclarar mi problema

saludos.


----------



## cosmefulanito04 (Ago 15, 2011)

Si es normal eso, ya que usa ciertas librerias que requieren mucho codigo en ASM (¿porque? ni idea).

Yo para el manejo de un LCD uso un delay como este:


```
void delay_us(u16 cuenta)	//Válido sólo con Xtal=1MHz
{
	u16 aux;
	
	for(aux=0;aux<=cuenta;aux++)
		{
		asm("sub r0,r0");	//tarda 1 clk => 1uS
		}		
}

void delay_ms(u16 cuenta)	//Válido sólo con Xtal=1MHz
{
	u16 aux;
	for(aux=0;aux<=cuenta;aux++)
		{
			delay_us(1000);
		}		
}
```

Tene en cuenta que en ese "uS" no tengo en cuenta el tiempo de salto a la funcion "delay" y ni tampoco el salto del "for", por lo tanto yo diria que esa funcion "delay" tardara 5uS o mas (tendria que ver como se traduce el for en assembler y cuantos clk's tarda el uC en ejecutar un jmp). Pero creo que para un simple delay en el que no necesitas precision del uSeg, te va a servir.


----------



## thunder2 (Ago 15, 2011)

Hola, queria preguntarte si esto que haces es valido para utilizar un ATMEGA23U4, ya que para no complicarse con un programador, pensaria utilizar este micro con USB incorporado.
Muchas gracias y saludos.


----------



## Javiermega (Feb 1, 2012)

Hola
De antemano un saludo a todos los del foro y sin mayor preambulo voy al grano.
Tengo problemas con los Fuses por que quiero utilizar un cristal de 8Mhz con un atmega32 y no he podido lograrlo desde hace varias semanas . Realize un programa para usar un LCD y el USART a esta frecuencia. Programe el micro con el *AVRISP* ajustando los FUSES asi: High=C9 y Low=FF. De esta forma el LCD me saca mensajes revueltos y el USART no funciona definitivamente. 

Ahora si le programo los FUSES asi: High=D9, Low=FF y de todas formas sigue sin funcionar correctamente el atmega32 con el cristal de 8Mhz externo.

Ahora bien, le programo los Fuses para usar el oscilador interno a 8Mhz: High=D9, Low=E4 y de todas formas no sale nada en el LCD ya ni decir nada del USART. 

Podrian orientarme por favor, he leido el datasheet del atmega32 de ahi mis propuestas de los fuses, la verdad estoy un poco desesperado. Francamente he notado que si les funcionan los microcontroladores AVR a muchos y por eso no he querido renunciar a dejarlos.

Ya no se si es el programador o que será, al menos mis programas en el AVRstudio corren bien y la simulacion en el proteus también. 

Les agradesco mucho orientación, gracias.


----------



## Apmavdus (Feb 25, 2012)

Hola que tal, yo tengo un probrema en generar un tono con el atmega8 no tengo ni idea, me habian dicho sobre un libro que esta en ingles pero no lo encuentro, o si alguien sabe como hacer tonos con el atmega8 me gustaria que me ayudara. yo uso el avr studio 4.19. gracias y hasta luego.


----------



## R-Mario (Feb 26, 2012)

Bueno he visto dos formas de generar tonos, uno es usando ciclos for junto con retardos "cosa que le quita el tiempo al procesador" y la otra es usando los timers para que generen una salida de X frecuencia y asi ir generando los distintos tonos. Fijate que el compilador CCS tiene una libreria en C que te permite generar tonos, puedes verla y por asi decirlo "copiarle"


----------

