Open DamRCorba opened 3 months ago
Gracias por las aclaraciones. Ya esta corregido. Saludos
En ese formato esta bien como para la entrega. Leyendo tu memoria entiendo que el estado de espera y el estado de levantado hacen lo mismo.. O sea solo esperan la señal para subir o para bajar.
Opcion 1 Te sobra n estado, el de levantado. Tendria que ir de espera a levantando o bajando y de cualquiera de ellos volver a espera.
Opcion 2 Te falta aclarar que el estado de espera mantiene una barrera alta para que pase el transito y el estado de levantado la mantiene baja.
TAMBIEN TENES QUE DECIDIR SI LO HACES CON LPC845-BRK O SIMULADO EN PROTEUS CON ATMEGA128
Pensé que la maquina de estados tenia que poder manejar todas las posibles transiciones. Si las dos opciones son validas, entonces la 1 (eliminar un estado), me parece mejor. El trabajo Lo voy a hacer en Proteus con ATMEGA128.
Correcto, todas las transiciones y todos los estados. El tema es que tu estado de puente elevado y puente bajo hacen lo mismo, esperar.
Si esos estados harían algo diferente, como bajar o subir una barrera, entonces si deberían ser estados diferentes.
Ahí vi que modificaste el diagrama. Esta todo correcto. Ya podrías comenzar a escribir código. Recorda, que cada estado tiene que estar representado por una funcion. Esas funciones tienen que devolver un estado.
A nivel mcu, solo deberias usar entradas. El sensor de altura de puente como lo tenes pensado implementar?
Buenas profe. Ahí actualicé el TP, aunque todavía me falta terminarlo. Por alguna razón, al iniciarse el programa pasa de estado de "espera" a estado "elevando" sin apretar ningún switch; una vez que se hace descender el puente, queda en estado de espera normalmente hasta que se presione el switch de "subir". La altura esta simulada con un simple contador, todavía no implementé el sensor en el código, y tampoco se controla la velocidad del motor por PWM con ningún timer. No estaba seguro de como conectarlo, debería conectar el pin que use para pwm del atmega a la entrada ENA del L298? otra consulta es si debería usar una interrupción cuando la altura del sensor llegue al máximo o al mínimo.
Hola Roger, esta bastante bien. Aunque requiere varias correcciones.
Para empezar el codigo deberia estar estructurado en 3 archivos de fuente, main.c, estados.c y funciones.c
En el main deberia estar el cascaron de la maquina de estados. La funcion init, y el while 1 con el llamado al vector de punteros a funciones de los estados.
En e estados.c deberian estar solo las funciones de estado, en donde no se aplique nada relacionado con el micro, ahi deberias tener llamados para lecturas y escrituras, pero no con la interaccion directa del micro.
En funciones.c se encuentran las funciones que son llamadas desde estados.c para interactuar con el micro.
Este tipo de principio de separacion de codigo llamado SOLID, tiene el objetivo de permitir cambiar al microcontrolador solamente modificando el codigo de funciones.c el cual deberian ser interacciones simples con el micro.
Por otro lado, con respecto al GPIO, te sugiero que utilices a las definiciones de pines hechas con REGBIT, te seran mucho mas simples ya que vas a obtener el valor del bit sin necesidad de enmascarar.
Ya hice varias correcciones. Aunque sigue con la misma falla, el código quedó estructurado como debería. No se si las funciones de funciones.c también deberían ser punteros a funciones. Y tambien reemplace los set_bit y clear_bit por REGBIT.
Hola Roger, Estas usando mal al REGBIT y la lib en general. La avr_api en la seccion de GPIO tiene todas las definiciones necesarias para tal caso.
Deberias usarlo como una definicion y luego solo llamarlo.
Ejemplo de uso, en el archivo de conf.h
#include "avr_api.h"
// Definiciones de puertos para el Relay
#define RELE_PORT avr_GPIO_C
#define RELE_PIN avr_GPIO_PIN_0
#define RELE avr_GPIOC_OUT_0
// Definiciones de puertos para el LED
#define LED_PORT avr_GPIO_C
#define LED_PIN avr_GPIO_PIN_1
#define LED avr_GPIOC_OUT_1
// Definiciones de puertos para el Pulsador
#define PULSA_PORT avr_GPIO_C
#define PULSA_PIN avr_GPIO_PIN_2
#define PULSADOR avr_GPIOC_IN_2
En el archivo de funciones para la inicializacion:
void init_mcu(void){
GpioInitStructure_AVR rele, led, pulsador;
pulsador.port = PULSA_PORT;
pulsador.pines = PULSA_PIN;
pulsador.modo = avr_GPIO_mode_Input;
init_gpio(pulsador);
rele.port = RELE_PORT;
rele.pines = RELE_PIN;
rele.modo = avr_GPIO_mode_Output;
init_gpio(rele);
led.port = LED_PORT;
led.pines = LED_PIN;
led.modo = avr_GPIO_mode_Output;
init_gpio(led);
if(PULSADOR) RELE = 0; //pone en 0 al pin del rele si el pulsador da un 1 en la entrada
}
Por otro lado, vi que estas usando la _delay_ms. En el TP no estan permitidas las funciones bloqueantes ni los bucles. Por lo que la funcion de delay no va. Lo ideal seria usarlo con un timer de systick a 1ms y una variable global que cuente los ticks.
Por ultimo, respondiendo a tu pregunta. El unico vector de punteros a funciones obligatorio es el del main para los estados. Los demas no deberian ser necesarios al menos en los proyectos simples del TP.
Buenas profe. Ya hice algunas correcciones, aunque sigue sin funcionar, elimine las _delay_ms y agregue algunas definiciones basándome en esos ejemplos. Cuando compilé el archivo avr_Timers.c, me arrojó un error de que la variable F_CPU no estaba definida. Será que estoy inicializando al el timer?
Hola Roger, ahi vi que estas usando mal la incluicion de la lib. En mylib.h haces:
#include <avr/io.h>
#include <avr_api/avr_api.h>
Y lo correcto seria:
#include "avr_api/avr_api.h"
la api, no es una libreria de sistema, por ende va entre comillas. Poniendola entre <> termina en el error de no encontrarla. Una vez que haces el include de la api no necesitas agregar a las subpartes de la lib en forma separada.
Me llama un poco la atencion lo avr_Timers.c. Como estas compilando? Los archivos de la api se tienen que compilar en su totalidad como parte del proyecto, estan todos vinculados y ademas es necesario que usen las configuraciones del proyecto. Proteus genera el entorno para programar al ATMEGA128 en el momento que creas al proyecto, eso le da la posibilidad de agregar las libs de avr y configurarlas para que sean la de un ATMEGA 128 con F_CPU X.
Estas compilando desde proteus?
Estaba compilando desde vscode, con estos comandos: avr-gcc -Os -mmcu=atmega128 -c estados.c -o estados.o avr-gcc -mmcu=atmega128 main.o funciones.o estados.o avr_api.o avr_gpio.o avr_Adc.o avr_Timers.o avr_Extint.o -o puenteAVR.elf avr-objcopy -O ihex -R .eeprom puenteAVR.elf puenteAVR.hex
Y despues cargaba el archivo .hex a proteus. Cuando compilo el Timers.c con la linea: avr-gcc -Os -mmcu=atmega128 -c avr_api/avr_Timers.c -o avr_Timers.o; me sale un error como este:
avr_api/avr_Timers.c: In function 'init_Systick_timer': avr_api/avr_Timers.c:117: error: 'F_CPU' undeclared (first use in this function) avr_api/avr_Timers.c:117: error: (Each undeclared identifier is reported only once avr_api/avr_Timers.c:117: error: for each function it appears in.) avr_api/avr_Timers.c: In function 'getprescaler': avr_api/avr_Timers.c:267: error: 'F_CPU' undeclared (first use in this function)
Claro, lo mas facil es que hagas todo en proteus.
el comando que estas usando incluye a todo el proyecto es por eso que te esta dando error. una alternativa es que compiles
con avr-gcc -Os -mmcu=atmega128 *.c avr_api/*.c
Lo que te esta pasando es que la compilacion no es completa para todo el proyecto. Cuando lo haces en un IDE, o incluso en proteus, genera un makefile donde estan todas la configuraciones de compilacion y de ahi se puede obtener el release y el debug.
Por ejemplo, podrias crear un makefile con una estructura como la siguiente
# Configuración del proyecto
MCU = atmega128
TARGET = main
SRC_DIR = . avr_api
C_SOURCES = $(foreach dir,$(SRC_DIR),$(wildcard $(dir)/*.c))
OBJ_FILES = $(C_SOURCES:.c=.o)
# Opciones del compilador
CC = avr-gcc
CFLAGS = -mmcu=$(MCU) -Wall -Os -std=c99
LDFLAGS = -mmcu=$(MCU)
# Opciones para generar el HEX
OBJCOPY = avr-objcopy
OBJFLAGS = -O ihex -R .eeprom
# Reglas principales
all: $(TARGET).hex
$(TARGET).elf: $(OBJ_FILES)
$(CC) $(LDFLAGS) -o $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
$(TARGET).hex: $(TARGET).elf
$(OBJCOPY) $(OBJFLAGS) $< $@
# Limpieza de archivos generados
clean:
rm -f $(OBJ_FILES) $(TARGET).elf $(TARGET).hex
# Subir al microcontrolador (requiere avrdude)
upload: $(TARGET).hex
avrdude -c <programmer> -p $(MCU) -U flash:w:$(TARGET).hex:i
.PHONY: all clean upload
Esto depues te dejaria usar el comando "make" para compilar, "make clean" para borrar los archivos generados y "make upload" para cargar el codigo en el micro real.
Esto siempre hablando en un entorno linux
Con este comando me salieron todos los errores juntos, avr-gcc -Os -mmcu=atmega128 .c avr_api/.c
estados.c: In function 'f_espera_puente': estados.c:5: warning: return makes pointer from integer without a cast estados.c: In function 'f_elevando_puente': estados.c:19: warning: return makes pointer from integer without a cast estados.c: In function 'f_elevado_puente': estados.c:26: warning: return makes pointer from integer without a cast estados.c:28: warning: return makes pointer from integer without a cast main.c: In function 'main': main.c:5: warning: initialization from incompatible pointer type main.c:5: warning: initialization from incompatible pointer type main.c:5: warning: initialization from incompatible pointer type main.c:5: warning: initialization from incompatible pointer type avr_api/avr_Timers.c: In function 'init_Systick_timer': avr_api/avr_Timers.c:117: error: 'F_CPU' undeclared (first use in this function) avr_api/avr_Timers.c:117: error: (Each undeclared identifier is reported only once avr_api/avr_Timers.c:117: error: for each function it appears in.) avr_api/avr_Timers.c: In function 'getprescaler': avr_api/avr_Timers.c:267: error: 'F_CPU' undeclared (first use in this function) avr_api/avr_Uart.c: In function 'init_uart_avr': avr_api/avr_Uart.c:701: error: 'F_CPU' undeclared (first use in this function) avr_api/avr_Uart.c:701: error: (Each undeclared identifier is reported only once avr_api/avr_Uart.c:701: error: for each function it appears in.)
Los warnings de estados.c se iban si les agrego un casteo en el: return (int *)elevando (aunque no entendi bien si hay diferencia). Los otros son de la linea del vector de estados en el main, tampoco entendí porqué salen. Los ultimos son los que le decia del F_CPU
esta claro que como lo estas compilando falta el archivo de cabecera que gernera el IDE. Hay algunas macros como F_CPU que se crean en la configuracion del proyecto. Podrias definirla con un #define F_CPU 16000000.
Lo ideal es que para evitar problemas para resolver el TP lo hagas directamente en el IDE de Proteus.
Ya lo pude compilar desde Proteus, había elegido mal el compilador cuando creé el proyecto, y solo me tomaba lenguaje ensamblador. Ya hice unas modificaciones y aunque no da mas errores al compilar, todavia se inicia solo en estado elevando. Tambien funciona el timer que hace titilar los leds, pero dejo de girar el motor
Eso es porque los pulsadores estan mal conectados. Deberian ir a 5V -> R10K -> conexion a micro, Pulsador, capacitor y del otro extremo del capacitor y el pulsador la tierra.
En definitiva. El punto que ahora usas para conectar la pata del micro deberia ir a 5V. Y la conexion al micro deberia ir en el nodo que se unen la resistencia con el capacitor y el pulsador. Si tenes un Pulsador Normal Abierto. Tenes un 1 en y 0 al apretar. Si tenes un pulsador Normal cerrado tenes 0 en reposo y 1 al pulsar
Ya corregí los pulsadores. También agregué las estructuras para el adc y el pwm, y aunque no funcionan como se espera no generaron errores de compilación y el programa sigue funcionando como estaba (se enciende solo, el motor tiene demasiada velocidad, el sensor no se lee). Una pregunta respecto al sensor ¿hay que agregar alguna linea de código para que el sensor varié su valor? Entiendo que el potenciómetro toma una señal analógica y la convierte en un valor en bits que luego se compara con el valor mínimo y máximo de altura. Pero, tengo la duda de si el sensor simulado se eleva de forma automática o si debo controlar su variación mediante alguna acción en el código.
Tampoco supe como modificar la estuctura del pwm mientras esta en ejecucion, hice esto y creo que no funcionó, o si, porque el pwm titila como si estuviera funcionando, pero igual deberia hacerlo con la api.
void activar_motor_bajar(void) {
OCR1A = 64; //linea dudosa
//configuracion para descenso
IN1 = 0;
IN2 = 1;
return;
}
Si, Seguramente te esta faltando la linea "sei()" que es la instruccion que habilita la interrupciones del micro. Deberia estar al final del init
Nono. Ya me paso en un momento y no me andaba. Pero ahí esta, justo antes del return en la función init_puente
es raro lo de los errores de compilacion. Podrias compartir algunas screenshots? Estas compilando en proteus, no? Por otro lado veo que estas usando el duty_b la linea OCR1A toca al canal A no al B. que de todas formas no es necesaria porque al iniciarlo con la estructura no se modifica mas, al menos que quieras variar al pwm.
El pin de salida del OCR1A B o C el que estes usando lo tenes que configurar como salida tambien.
Buenas profe, compilar si que compila aunque no funciona como deberia. El motor se enciende solo al iniciar. Aunque no pasa al estado elevando sin pulsar los switch (ya que los leds no parpadean) pero en el estado espera el motor esta girando solo (seguramente hay mas cosas mal conectadas). Le dejo el screenshot con algunos warnings . Y dos consultas puntuales:
1_ Esta correcta esta función para devolver el valor del sensor? unsigned int leer_sensor(void) { return leer_ADC(avr_ADC_canal0); }
2_ Cuando no tenia configurado el PWM tenia la condicion: if (SWITCH_UP = 0) { ENA = 1} (cuando el pulsador esta en bajo prender el motor). Ahora en el pin ENA del L298 tengo el PWM, y no se como configurar esa condición. O si debería cambiar las conexiones.
Hola roger, los warnings es porque estas devolviendo siempre punteros pero en tus returns pones valores.
Entiendo que lo correcto es que pongas valores por lo que deberias sacar los "*" .
estados_t *(f_elevando_puente)(void) <---- deberia ser estados_t (f_elevando_puente)(void)
No se si la confunsion la tenes por el tema del vector de punteros a funciones. de ser asi. El vector puede llamar a cualquier funcion mientras estas tengan el mismo formato de prototipo.
vos tenes:
estados_t (*vectorEstados[])(void)
por lo tanto tus prototipos pueden ser:
estados_t f_elevando_puente(void)
estados_t funcionx(void)
estados_t funciony(void)
estados_t funcionETC(void)
Eso tambien puede estar haciendo que los estados que se llaman sean erroneos.
Para apagar el PWM lo que deberias hacer es cambiar la base de tiempo del timer a sin prescaler. Eso lo frena y forzas el valor de ENA al nivel de reposo. Crea una funcion de stop y run que modifiquen solamente el prescaler del timer pwm
Saludos
Pensé que las funciones de estados debían ser si o si punteros a funciones. No tuve en cuenta que el vector en si era el que almacenaba las direcciones.
Bien profe. Ya corregí todos los puntos. Definí como salida el pin para el pwm, definí una estructura de inicialización de pwm como variable global para que pueda ser modificada por las funciones run y stop; y ahora ya funciona bien, se mueve a baja velocidad, cambia de dirección y ya no inicia encendido.
Respecto de la lectura del sensor, ya lo definí como entrada, e inicialice la estructura del adc. Pero aun me arroja este error:
../funciones.c: In function 'activar_motor_subir': [../funciones.c:85: warning: comparison between pointer and integer]
No entiendo porque me da ese error en la linea 85 si estoy comparando dos unsigned int. O en realidad es un puntero a la direccion de memoria del ADC y por eso salta el error? en ese caso probé cambiando el tipo de dato que devuelve la función leer_sensor() cambiandola a "avr_ADC_Value_t" pero tampoco funciono, ni tampoco funciono haciendo un casteo del dato devuelto por la funcion leer_adc.
Otra observación es que si configuro la macro ALTURA_MIN como 0 me da un warning advirtiendo que el valor de la dirección de "leer_sensor" nunca puede ser NULL.
Gracias. Saludos.
Claro, No. Se pide un vector de punteros a funciones que llame a las funciones de estado. Igual lo que hiciste no fue hacer a las funciones de estado como puntero de funciones sino que era funciones comunes que devolvían un puntero.
Ahora esta mucho mejor. El error de la linea 85 es de cansancio.
if (leer_sensor == ALTURA_MAX) { // esto esta mal
stop(); // esto esta bien
}
if (leer_sensor() == ALTURA_MAX) { // esto esta bien
stop(); // esto esta bien
}
Te falto el paréntesis en el llamado de la funcion. si no lo pones, lo que hace el lenguaje es comparar la posicion de memoria de la funcion con el int. Al margen de no estar ejecutando la funcion de lectura.
Creo que ya casi lo tenes. Si con esto ya te anda todo faltaria completar el informe con screenshots de los estados o un video con el funcionamiento.
Hola Roger, para empezar tenes que elegir uno de los dos casos. En mi opinión es mejor el puente levadizo para lo que corresponde a una maquina de estados.
En cuanto a la presentación todo el "informe" tiene que estar en markdown, sin pdfs adjuntos. En tu Readme se tiene que poder ver el entregable.
En cuanto al diagrama, primero tiene que haber una memoria descriptiva que explique al proyecto y el diagrama tiene que ser la representación de esas palabras. Una vez que hagas esas correcciones por favor contéstame por acá.