Hola, estoy aprendiendo microcontroladores con el atmega16 y tengo que construir un sumo que funciona con sensores digitales.
El problema es que la simulación los motores funcionan en Proteus tal cual lo esperado en el código que hice en Microchip Studio.
A la hora del montaje revisé el L298N con un Arduino UNO y respondió perfectamente (al menos con esto de los motores que es lo que más me interesa resolver primero), el Atmega16 es detectado sin problemas por el software AVRDUDE instalado en mi laptop, he revisado las conexiones muchísimas veces, pero el resultado que tengo es infructífero. Así que quería saber que consideraciones se deben tomar en cuenta en el montaje para los proyectos del Atmega16.
Adjunto el código y la simulación en un archivo .rar por si alguien me puede ayudar, ¡Muchas gracias!
PD: igual pongo también aquí el código por si algo:
El problema es que la simulación los motores funcionan en Proteus tal cual lo esperado en el código que hice en Microchip Studio.
A la hora del montaje revisé el L298N con un Arduino UNO y respondió perfectamente (al menos con esto de los motores que es lo que más me interesa resolver primero), el Atmega16 es detectado sin problemas por el software AVRDUDE instalado en mi laptop, he revisado las conexiones muchísimas veces, pero el resultado que tengo es infructífero. Así que quería saber que consideraciones se deben tomar en cuenta en el montaje para los proyectos del Atmega16.
Adjunto el código y la simulación en un archivo .rar por si alguien me puede ayudar, ¡Muchas gracias!
PD: igual pongo también aquí el código por si algo:
C:
#include <avr/io.h>
#include <util/delay.h>
#include "lcd/lcd.h"
#include <stdlib.h>
#include <avr/interrupt.h>
#define F_CPU 16000000L
volatile uint16_t overflow_count = 0; // Variable para contar desbordamientos
int main(void)
{
atmega_init();
lcd_init(LCD_DISP_ON);
char str[16];
overline_set(); //Definición del comportamiento de INT1 e INT2
Timer0_Init(); // Inicializar Timer0
sei();// Habilitar interrupciones globales
PORTA|= (1<<PA0);
_delay_ms(5000);
while(1){
status_LCD();
if (!(PINA & (1 << PA0)) && !(PINA & (1 << PA1)) && (PINA & (1 << PA3)) && (PINA & (1 << PA4))) //No detección en ningún lado
{
on_guard(); // Si se cumple la condición, establecer en cero los pines A5, A6, A7, B0 y B1. Luego empezará a buscar
lcd_clrscr();
lcd_puts("Guard Routine");
_delay_ms(1000);
lcd_clrscr();
}
else
{
if ((PINA & (1<<PA2)))//Detección trasera
{
to_B();
}
else
{
if((PINA & (1<<PA1)))//Detección frontal
{
to_F();
lcd_clrscr();
lcd_puts("Front Routine");
_delay_ms(1000);
lcd_clrscr();
}
else
{
if((PINA & ~(1<<PA3)))//Detección izq
{
to_L();
}
}
}
}
}
return 0;
}
void Timer0_Init() {
TCCR0 |= (1 << CS02) | (1 << CS00); // Prescaler de 1024
TIMSK |= (1 << TOIE0); // Habilitar la interrupción de desbordamiento de Timer/Counter0
}
void on_guard(void){
//Teniendo en cuenta que PA6 Y PB1 ya están en 0 lógico entonces:
stop_wheels();
PORTA |= (1 << PA7); //Pongo 1 lógico en el ENABLE y en PA7
PORTA &= ~(1 << PA6);//Pongo 0 lógico en PA6. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTA
PORTB |= (1 << PB3); //Pongo 1 lógico en PB0
PORTB &= ~(1 << PB1);//Pongo 0 lógico en PB1. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTB
PORTA |= (1 << PA5); //Activa el enable
}
void to_B(void) //To back side
{
stop_wheels();
PORTA |= (1 << PA6); //Pongo 1 lógico en el ENABLE y en PA7
PORTA &= ~(1 << PA7);//Pongo 0 lógico en PA6. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTA
PORTB |= (1 << PB1); //Pongo 1 lógico en PB0
PORTB &= ~(1 << PB3);//Pongo 0 lógico en PB1. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTB
PORTA |= (1 << PA5); //Activa el enable
}
void to_F(void) //To front side
{
stop_wheels();
PORTA |= (1 << PA6); //Pongo 1 lógico en el ENABLE y en PA7
PORTA &= ~(1 << PA7);//Pongo 0 lógico en PA6. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTA
PORTB |= (1 << PB3); //Pongo 1 lógico en PB0
PORTB &= ~(1 << PB1);//Pongo 0 lógico en PB1. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTB
PORTA |= (1 << PA5); //Activa el enable
}
void to_L(void) //To left side
{
stop_wheels();
PORTA |= (1 << PA7); //Pongo 1 lógico en el ENABLE y en PA7
PORTA &= ~(1 << PA6);//Pongo 0 lógico en PA6. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTA
PORTB |= (1 << PB3); //Pongo 1 lógico en PB0
PORTB &= ~(1 << PB1);//Pongo 0 lógico en PB1. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTB
PORTA |= (1 << PA5); //Activa el enable
}
void to_R(void)
{
stop_wheels();
PORTA |= (1 << PA6); //Pongo 1 lógico en el ENABLE y en PA7
PORTA &= ~(1 << PA7);//Pongo 0 lógico en PA6. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTA
PORTB |= (1 << PB1); //Pongo 1 lógico en PB0
PORTB &= ~(1 << PB3);//Pongo 0 lógico en PB1. No entiendo porqué se pone AND, se supone que eso reescribe todo PORTB
PORTA |= (1 << PA5); //Activa el enable
}
void stop_wheels(void)// stop, duh
{
PORTA &= (~(1 << PA6) | ~(1 << PA7));
PORTB &= (~(1 << PB1) | ~(1 << PB3));
_delay_ms(300);
}
void atmega_init(void)//Inicialización de todos los puertos del Atmega
{
//PA1, PA2, PA3, PA4 son Sensores IR. PA5 es el ENABLE de un par de motores, y PA6,PA7 el control de estos.
DDRA &= ~( (1 << DDA1) | (1 << DDA2) | (1 << DDA3) | (1 << DDA4) ); // Configurar pines A1, A2, A3 y A4 como entradas (poner en 0 lógico)
DDRA |= ( (1 << DDA0) | (1 << DDA5) | (1 << DDA6) | (1 << DDA7) ); // Configurar pines A5, A6 y A7 como salidas (poner en 1 lógico). El pin A0 es el led intermitente
DDRB&=~(1<<DDB2); //PB2-INT2 sensor IR UNDER BACK. PB1 y PB3 es control del segundo par de motores, donde PA5=ENABLES.
DDRB |= ((1 << DDB1) | (1 << DDB3));
DDRD|=(0<<DDD3); //Pone como entrada a PD3, y todo lo demás del Port D lo deja tal cual estaba. Esto es para evitar darle fallas al trabajo de la LCD
PORTA |= (1 << PA5); // Establecer en "1" lógico (Habilitar motores)
}
void overline_set(void) //Configuración de los registros para INT1 e INT2
{
//El INT1 se ejecuta al encender el uC. Tal vez debo cambiar el comportamiento a "Rising edge", como el INT2
MCUCR=(0<<ISC11) & (1<<ISC10); // Definiendo comportamiento de la INT1 como "Any logical change interruption" usando el comando 01 en ISC11 e ISC10 respectivamente
GICR |= (1 << INT1) |(1 << INT2) ; //Habilitar int externas, Al poner 1<<INT2 ya se está habilitando como "rising edge change", es decir la INT2 se va a ejecutar cuando detecte un 1 logico.
}
void status_LCD(void) //Rutina del LCD
{
lcd_gotoxy(0,0);
lcd_puts("S1:");
lcd_gotoxy(5,0);
lcd_puts("S2:");
lcd_gotoxy(10,0);
lcd_puts("S3:");
lcd_gotoxy(0,1);
lcd_puts("S4:");
lcd_gotoxy(5,1);
lcd_puts("S5:");
lcd_gotoxy(10,1);
lcd_puts("S6:");
if(PINA & (1<<PA1)){
lcd_gotoxy(3,0);
lcd_puts("1");
}
else{
lcd_gotoxy(3,0);
lcd_puts("0");
}
if(PINA & (1<<PA2)){
lcd_gotoxy(8,0);
lcd_puts("1");
}
else{
lcd_gotoxy(8,0);
lcd_puts("0");
}
if(PINA & (1<<PA3)){
lcd_gotoxy(13,0);
lcd_puts("1");
}
else{
lcd_gotoxy(13,0);
lcd_puts("0");
}
if(PINA & (1<<PA4)){
lcd_gotoxy(3,1);
lcd_puts("1");
}
else{
lcd_gotoxy(3,1);
lcd_puts("0");
}
if(PINB & (1<<PB2))
{
lcd_gotoxy(8,1);
lcd_puts("1");
}
else{
lcd_gotoxy(8,1);
lcd_puts("0");
}
if(PIND & (1<<PD3)){
lcd_gotoxy(13,1);
lcd_puts("1");
}
else{
lcd_gotoxy(13,1);
lcd_puts("0");
}
}
ISR(INT1_vect) //Rutina de interrupción INT1:detección del Sensor S6 (Under Front)
{
lcd_clrscr();
lcd_puts("UnderFront Routine");
_delay_ms(1000);
lcd_clrscr();
}
ISR(INT2_vect) //Rutina de interrupción INT2:detección del Sensor S5 (Under Back)
{
lcd_clrscr();
lcd_puts("UnderBack Routine");
_delay_ms(1000);
lcd_clrscr();
}
ISR(TIMER0_OVF_vect) //Rutina de interrupción TIMER0: Led intermitente
{
overflow_count++; // Incrementar contador de desbordamientos
if (overflow_count >= 78125) {
PORTA ^= (1 << PA0);
// Realizar acciones cuando se alcanzan los 78125 desbordamientos (aproximadamente 5 segundos
}
}