Estaba usando un ATtiny para iluminar mi terraza. El brillo se controla usando una olla conectada al pin ADC.
Intentó la función exponencial y la salida PWM basada en eso parece estar dando un aumento lineal en el brillo percibido.
Estaba usando estas fórmulas:
out = pow(out_max, in/in_max)
Attiny85 @ 8MHz estaba tardando unos 210us en realizar el cálculo anterior. Para mejorar el rendimiento, hizo una tabla de búsqueda. Como la entrada era de ADC de 10 bits y la memoria ATtiny es limitada, también quería crear una tabla más corta.
En lugar de hacer una tabla de búsqueda con 1024 entradas, hizo una tabla de búsqueda inversa con 256 entradas (512 bytes) en la memoria del programa (PGMEM). Se escribió una función para realizar una búsqueda binaria en esa tabla. Este método solo requiere 28uS para cada búsqueda. Si uso una tabla de búsqueda directa, requeriría 2kb de memoria, pero la búsqueda tomaría solo 4 uS más o menos.
Los valores calculados en la tabla de búsqueda usan solo el rango de entrada 32-991, descartando el rango inferior / superior de ADC, en caso de que haya un problema con el circuito.
A continuación se muestra lo que tengo ahora.
// programa de prueba anti_log
/ * LED conectado a PIN6 (PB1) * /
#define LED 1
// tabla de búsqueda Anti-Log (inversa)
// y = 0-255 (salida pwm), rango_y = 256
// x = 0-1023 (entrada ADC de 10 bits);
// suponiendo que no se pueden usar valores de salida ADC inferior / superior
// descartando los primeros 32 y los últimos 32 valores.
// min_x = 32, max_x = 1023-min_x, x_range = 1024-2 * min_x
// ANTI_LOG [y] = round (x_range * log (y, base = y_range) + min_x)
// dado un valor de x, realice una búsqueda binaria en la tabla a continuación
// toma aproximadamente 28uS para el reloj Attiny85 @ 8MHz
PROGMEM prog_uint16_t ANTI_LOG [] = {
0x0000, 0x0020, 0x0098, 0x00de, 0x0110, 0x0137, 0x0156, 0x0171, 0x0188, 0x019c, 0x01af, 0x01bf, 0x01ce, 0x01dc, 0x01e9, 0x01f5,
0x0200, 0x020a, 0x0214, 0x021e, 0x0227, 0x022f, 0x0237, 0x023f, 0x0246, 0x024d, 0x0254, 0x025b, 0x0261, 0x0267, 0x026d, 0x0273,
0x0278, 0x027d, 0x0282, 0x0288, 0x028c, 0x0291, 0x0296, 0x029a, 0x029f, 0x02a3, 0x02a7, 0x02ab, 0x02af, 0x02b3, 0x02b7, 0x02b7, 0x02b7, 0x02b7, 0x02b7, 0x02b7, 0x02b7
0x02be, 0x02c2, 0x02c5, 0x02c9, 0x02cc, 0x02cf, 0x02d3, 0x02d6, 0x02d9, 0x02dc, 0x02df, 0x02e2, 0x02e5, 0x02e8, 0x02e8, 0x02e8, 0x02e8, 0x02e8, 0x02e8, 0x02e8
0x02f0, 0x02f3, 0x02f5, 0x02f8, 0x02fa, 0x02fd, 0x0300, 0x0302, 0x0304, 0x0307, 0x0309, 0x030b, 0x030e, 0x0310, 0x0312, 0x0312
0x0317, 0x0319, 0x031b, 0x031d, 0x031f, 0x0321, 0x0323, 0x0325, 0x0327, 0x0329, 0x032b, 0x032d, 0x032f, 0x0331, 0x0333, 0x0334,
0x0336, 0x0338, 0x033a, 0x033c, 0x033d, 0x033f, 0x0341, 0x0342, 0x0344, 0x0346, 0x0347, 0x0349, 0x034b, 0x034c, 0x034e, 0x034f,
0x0351, 0x0352, 0x0354, 0x0355, 0x0357, 0x0358, 0x035a, 0x035b, 0x035d, 0x035e, 0x0360, 0x0361, 0x0363, 0x0364, 0x0365, 0x0367,
0x0368, 0x0369, 0x036b, 0x036c, 0x036d, 0x036f, 0x0370, 0x0371, 0x0372, 0x0374, 0x0375, 0x0376, 0x0378, 0x0379, 0x037a, 0x037b,
0x037c, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0385, 0x0386, 0x0387, 0x0388, 0x0389, 0x038a, 0x038b, 0x038c, 0x038e,
0x038f, 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e,
0x039f, 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7, 0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x03ac, 0x33, 0x3, 0
0x03ae, 0x03af, 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03ba, 0x03ba, 0x03ba, 0x03ba, 0x03ba, 0x03ba, 0x03
0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03bf, 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c7, 0x03c7, 0x03c7, 0x03c7, 0x03c7, 0x03c7, 0x03c7
0x03c9, 0x03ca, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03cd, 0x03ce, 0x03cf, 0x03d0, 0x03d0, 0x03d1, 0x03d2, 0x03d3, 0x03d4, 0x03d3, 0x03
0x03d5, 0x03d6, 0x03d6, 0x03d7, 0x03d8, 0x03d8, 0x03d9, 0x03da, 0x03db, 0x03db, 0x03dc, 0x03dd, 0x03dd, 0x03df, 0x03df, 0x03df, 0x03df, 0x03
};
// Búsqueda binaria usando la tabla anterior.
byte antilog (int x)
{
byte y = 0x80;
int av;
para (int i = 0x40; i> 0; i >> = 1)
{
av = pgm_read_word_near (ANTI_LOG + y);
si (av> x)
{
y - = i;
}
más si (av <x)
{
y | = i;
}
más
{
volver y;
}
}
if (pgm_read_word_near (ANTI_LOG + y)> x)
{
y - = 1;
}
volver y;
}
configuración nula ()
{
pinMode (LED, SALIDA);
digitalWrite (LED, BAJO);
}
#define MIN_X 0
#define MAX_X 1024
bucle vacío ()
{
int i;
// antilog_drive
para (i = MIN_X; i <MAX_X; i ++)
{
analogWrite (LED, antilog (i));
retraso (2);
}
para (--i; i> = MIN_X; i--)
{
analogWrite (LED, antilog (i));
retraso (2);
}
retraso (1000);
// accionamiento lineal
para (i = MIN_X; i <MAX_X; i ++)
{
analogWrite (LED, i >> 2);
retraso (2);
}
para (--i; i> = MIN_X; i--)
{
analogWrite (LED, i >> 2);
retraso (2);
}
retraso (2000);
}