good day. I am working on a project with the ATmega16A where I am trying to control 2 servomotors to maintain the balance of a tray. The problem is that the servos work individually to maintain balance, but when I connect the 2 servos, they stop working. I wanted to see if anyone knows how to make them work together.
para controlar bien servo X
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include “lcd.h”
// Definición de pines para el sensor ADXL335
#define xpin 1 // ADC1 en ATmega16 (ADC1 en PA1)
#define ypin 2 // ADC2 en ATmega16 (ADC2 en PA2)
// Definición de pines para los servos MG90S
#define servoX_pin PB5 // Puerto B, pin 5 para control del servo X (OC1A)
#define servoY_pin PB3 // Puerto B, pin 3 para control del servo Y (OC0)
char buffer[16];
uint16_t last_x_val = 0; // Variable para almacenar la última lectura estable del ADC para el eje X
uint16_t last_y_val = 0; // Variable para almacenar la última lectura estable del ADC para el eje Y
// Función para mapear valores de una escala a otra
int16_t map(int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void setup() {
DDRA = 0x00; // Puerto A como entrada para los pines del ADC
DDRB |= (1 << servoX_pin) | (1 << servoY_pin); // Pines de los servos como salida
lcd_init(LCD_DISP_ON); // Inicializar LCD
}
void setupADC() {
ADMUX = (1 << REFS0); // Referencia de voltaje a AVCC con capacitor externo
ADCSRA = (1 << ADEN) | (1 << ADPS1) | (1 << ADPS0); // Habilitar ADC y configurar prescaler a 8
}
uint16_t ADC_read(uint8_t chan) {
ADMUX = (ADMUX & 0xF8) | (chan & 0x07); // Seleccionar canal
ADCSRA |= (1 << ADSC); // Iniciar la conversión
while (ADCSRA & (1 << ADSC)); // Esperar a que termine la conversión
return ADC; // Devolver el valor leído
}
void controlServoX(uint16_t x_val) {
// Definir una pequeña banda de histeresis para evitar ajustes innecesarios
int16_t hysteresis_min = -3;
int16_t hysteresis_max = 3;
// Comparar la nueva lectura del ADC con la última lectura estable
if (x_val < last_x_val + hysteresis_max && x_val > last_x_val - hysteresis_min) {
// Si la diferencia es menor que la histeresis, mantener la última posición del servo X
return;
}
// Actualizar la última lectura estable del ADC para el eje X
last_x_val = x_val;
// Definir los valores mínimos y máximos del ADC para los ángulos de servo correspondientes para el eje X
uint16_t min_adc = 270;
uint16_t max_adc = 410;
// Definir los ángulos correspondientes a los valores del ADC para el servo X
int16_t min_angle = -90;
int16_t max_angle = 90;
// Mapear el valor del ADC al rango de ángulos para el servo X
int16_t angle = map(x_val, min_adc, max_adc, max_angle, min_angle);
// Convertir el ángulo a un valor adecuado para el servo X (6 a 34 para el PWM)
uint8_t pwm_value = map(angle, min_angle, max_angle, 6, 34);
// Configurar el PWM para el servo X (OCR0)
if (OCR0 < pwm_value) {
for (uint8_t i = OCR0; i <= pwm_value; ++i) {
OCR0 = i;
_delay_ms(5); // Pequeño retraso para el movimiento suave
}
} else {
for (uint8_t i = OCR0; i >= pwm_value; --i) {
OCR0 = i;
_delay_ms(5); // Pequeño retraso para el movimiento suave
}
}
}
void controlServoY(uint16_t y_val) {
// Definir una pequeña banda de histeresis para evitar ajustes innecesarios
int16_t hysteresis_min = -3;
int16_t hysteresis_max = 3;
// Comparar la nueva lectura del ADC con la última lectura estable
if (y_val < last_y_val + hysteresis_max && y_val > last_y_val - hysteresis_min) {
// Si la diferencia es menor que la histeresis, mantener la última posición del servo Y
return;
}
// Actualizar la última lectura estable del ADC para el eje Y
last_y_val = y_val;
// Definir los valores mínimos y máximos del ADC para los ángulos de servo correspondientes para el eje Y
uint16_t min_adc = 270;
uint16_t max_adc = 410;
// Definir los ángulos correspondientes a los valores del ADC para el servo Y
int16_t min_angle = -90;
int16_t max_angle = 90;
// Mapear el valor del ADC al rango de ángulos para el servo Y
int16_t angle = map(y_val, min_adc, max_adc, max_angle, min_angle);
// Convertir el ángulo a un valor adecuado para el servo Y (6 a 34 para el PWM)
uint8_t pwm_value = map(angle, min_angle, max_angle, 6, 34);
// Configurar el PWM para el servo Y (OCR1A)
if (OCR1A < pwm_value) {
for (uint8_t i = OCR1A; i <= pwm_value; ++i) {
OCR1A = i;
_delay_ms(5); // Pequeño retraso para el movimiento suave
}
} else {
for (uint8_t i = OCR1A; i >= pwm_value; --i) {
OCR1A = i;
_delay_ms(5); // Pequeño retraso para el movimiento suave
}
}
}
void Impresion(uint16_t x_val, uint16_t y_val) {
// Mostrar valores en el LCD
lcd_gotoxy(0, 0);
sprintf(buffer, "X: %u", x_val); // Mostrar valor de ADC para X
lcd_puts(buffer);
lcd_gotoxy(0, 1);
sprintf(buffer, "Y: %u", y_val); // Mostrar valor de ADC para Y
lcd_puts(buffer);
}
int main(void) {
setup();
setupADC();
// Configuración del timer para el servo Y (Timer0, PB3, OCR0)
TCCR0 = (1 << WGM00) | (1 << WGM01) | (1 << COM01) | (1 << CS01) | (1 << CS00); // Set Fast PWM, Clear OC0 on compare match, Prescaler de 64
OCR0 = 20; // Valor inicial del PWM para el servo Y
// Configuración del timer para el servo X (Timer1, PB5, OCR1A)
TCCR1A = (1 << WGM10) | (1 << COM1A1); // Set Fast PWM, Clear OC1A on compare match
TCCR1B = (1 << WGM12) | (1 << CS11) | (1 << CS10); // Prescaler de 64
ICR1 = 4999; // Frecuencia de PWM: 50 Hz
OCR1A = 20; // Valor inicial del PWM para el servo X
while (1) {
// Leer valores ADC de los pines asignados
uint16_t x_val = ADC_read(xpin); // Lee el ADC1 (PA1) para el eje X
uint16_t y_val = ADC_read(ypin); // Lee el ADC2 (PA2) para el eje Y
// Controlar el servo X basado en el valor del ADC
controlServoX(x_val);
// Controlar el servo Y basado en el valor del ADC
controlServoY(y_val);
// Mostrar los valores en el LCD durante el movimiento
Impresion(x_val, y_val);
_delay_ms(20); // Pequeño retraso entre cada ajuste más corto para movimiento más suave
// Mostrar los valores finales en el LCD después del movimiento completo
Impresion(x_val, y_val);
_delay_ms(200); // Esperar una fracción de segundo entre cada lectura completa del ADC
}
return 0;
}
Jorge M is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.