Estoy aprendiendo sobre la programación de microcontroladores AVR y actualmente tengo una luz intermitente LED simple configurada en un ATtiny26.
Un potenciómetro de 10k está conectado a ADC7 (pin 7) como en el ejemplo de la parte 1 de este tutorial . Los pines de salida del puerto B están conectados a los LED a través de transistores en una matriz multiplexada. (El circuito funciona bien sin el ADC involucrado).
Para probar/aprender, estoy parpadeando un solo LED y esperando una cantidad de milisegundos igual a lo que se lee del ADC. Tengo un problema cuando trato de multiplicar el valor para implementar demoras más largas.
Pensé que el problema era que la variable en la que almaceno el ADCH era una int
pero necesita ser otra cosa porque este es un microcontrolador de 8 bits y int
solo puede ser 0-255. Sin embargo, sustituir long
no funcionó.
Aquí está el código que funciona:
#define F_CPU 1000000UL
#define ADC_VREF_TYPE = 0x40
int SD = 1;
int main()
{
// Set port A to output (1)
DDRA = 0b11111111;
// Set port B, pin 3, to input (0)
DDRB &= ~(1 << PB3);
// Set control and status register
ADCSR = 0b11100111;
// Set ADC multiplexer selection register
ADMUX = 0b00100111;
while (1)
{
// Set SD (step delay) to value from ADC
SD = ADCH;
// Turn on LED (it is a multiplexer, so two pins are used)
PORTA = 0b00010001;
// Wait for SD milliseconds
milli_delay(SD);
// Turn off LED
PORTA = 0b00000000;
// Wait for SD milliseconds
milli_delay(SD);
}
}
El problema ocurre cuando trato de usar un multiplicador como este:
SD = ADCH * 10;
Al hacer esto, el LED parpadeará rápidamente en un extremo del barrido del potenciómetro, pero se iluminará fijo y permanecerá así en algún punto mientras gira el potenciómetro a velocidades más lentas (valores ADCH más grandes); esencialmente "bloqueándose" y requiriendo un reinicio mientras el potenciómetro está nuevamente en la posición original. Supongo que estoy tratando de almacenar un valor mayor que el que contiene el tipo numérico, pero parece que no puedo superar esto cambiando el tipo de variable. Lo he intentado long
y uint32_t
realmente no entiendo qué tienen los tipos numéricos en este micro.
P: ¿Qué debo hacer para poder implementar demoras que van desde 0 hasta, por ejemplo, 2000 milisegundos?
FYI tengo las siguientes bibliotecas incluidas:
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <math.h>
Editar:
Lo había colocado _delay_ms(x)
directamente en mi ejemplo para evitar publicar las funciones que realmente estoy usando y que llaman _delay_ms(1)
dentro de un bucle. Pensé que sería más conciso, pero como señaló una respuesta, en realidad parecía ser un error.
int
solo puede ser 0-255
Eso no es correcto. En el C
lenguaje de programación, an int
siempre tiene al menos 16 bits de ancho, incluso en micros de 8 bits. A char
tiene 8 bits de ancho.
Pero al usar inttypes.h
, recomiendo enfáticamente usar los tipos explícitos como uint8_t
, int16_t
o uint32_t
.
Su verdadero error es usar _delay_ms()
con un parámetro variable. Esto no está permitido, ya que es una macro que involucra cálculos de coma flotante, al menos en avr gcc. Se supone que debes usar algo como esto:
void DelayMs(int delay) {
while(delay--) _delay_ms(1);
}
ADCH * 10
funcionaría perfectamente. ¿Alguna idea adicional de por qué podría no ser así?Creo que el problema es que tienes el resultado ADC justificado a la izquierda en el registro de resultados:
Su código a continuación muestra que ha configurado ADLAR en 1 (justificado a la izquierda):
// Set ADC multiplexer selection register
ADMUX = 0b00100111;
Esto significa que cuando está leyendo el valor ADC en ADCH, está saltando por completo los dos bits menos significativos (LSB). Esto significa que está leyendo el número como si fuera 4 veces más pequeño (desplazamientos de dos bits a la derecha).
Lo que quieres hacer es configurarlo justificado a la DERECHA:
// Set ADC multiplexer selection register
ADMUX = 0b00000111;
y lea su valor ADC de ADCL (el registro de resultado ADC inferior):
while (1)
{
// Set SD (step delay) to value from ADC
SD = ADCL;
// Turn on LED (it is a multiplexer, so two pins are used)
PORTA = 0b00010001;
// Wait for SD milliseconds
milli_delay(SD);
// Turn off LED
PORTA = 0b00000000;
// Wait for SD milliseconds
milli_delay(SD);
}
justamente
JYelton