我用AVR微控制器构建键盘灯。
有两个按钮,BRIGHT和DIM,以及一个白色LED。
LED并非线性,因此我需要使用对数刻度(在较高值时增加亮度,在较低值时使用较小的步长)。
为此,我调整了在PWM比较匹配控制寄存器中添加或减去1之间的延迟。
while (1) {
if (btn_high() && OCR0A < 255) OCR0A += 1;
if (btn_low() && OCR0A > 0) OCR0A -= 1;
if (OCR0A < 25)
_delay_ms(30);
else if (OCR0A < 50)
_delay_ms(25);
else if (OCR0A < 128)
_delay_ms(17);
else
_delay_ms(5);
}
它很好用,但是当它从一种速度变为另一种速度时,它是一个可见的步骤。如果延迟调整顺利,情况会好得多。
我可以使用一些简单的公式吗? 它不得包含除法,模数,sqrt,日志或任何其他高级数学。我可以使用乘法,加法,子和位操作。另外,我不能在其中使用浮动。
或许只是某种查找表?我真的很高兴为这个if-else乱七八糟添加更多分支。
答案 0 :(得分:2)
发布的传输函数非常线性。建议线性延迟计算。
delay = 32 - OCR0A/8;
接受编辑后
各种look-up-tables适用于近似拟合的简单方程(构造为避免中间值> 65535),例如
BRIGHTNESS_60 = (((index*index)>>2 + 128)*index)>>8;
答案 1 :(得分:1)
缩放isn't quite logarithmic只需使用log()
就不够了。
我过去通过使用具有18个条目的LUT并且一次执行整个步骤来解决这个问题(即控制变量从0到17变化然后通过LUT推进),但是如果更精细的控制是然后需要52或更多是必要的。请确保put it in flash,以便它不会消耗任何SRAM。
由MightyPork编辑
我最后使用的数组 - 通过线性插值从原始数组中获得。
<强>基本强>
#define BRIGHTNESS_LEN 60
const uint8_t BRIGHTNESS[] PROGMEM = {
0, 1, 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 7, 8, 9,
10, 11, 13, 14, 16, 18, 21, 24, 27, 30, 32,
35, 38, 40, 42, 45, 48, 50, 54, 58, 61, 65,
69, 72, 76, 80, 85, 90, 95, 100, 106, 112,
119, 125, 134, 142, 151, 160, 170, 180, 190,
200, 214, 228, 241, 255
};
<强>平滑强>
#define BRIGHTNESS_LEN 121
const uint8_t BRIGHTNESS[] PROGMEM = {
0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5,
6, 6, 6, 7, 7, 8, 8, 8, 9, 10, 10, 10, 11, 12, 13, 14, 14,
15, 16, 17, 18, 20, 21, 22, 24, 26, 27, 28, 30, 31, 32, 34,
35, 36, 38, 39, 40, 41, 42, 44, 45, 46, 48, 49, 50, 52, 54,
56, 58, 59, 61, 63, 65, 67, 69, 71, 72, 74, 76, 78, 80, 82,
85, 88, 90, 92, 95, 98, 100, 103, 106, 109, 112, 116, 119,
122, 125, 129, 134, 138, 142, 147, 151, 156, 160, 165, 170,
175, 180, 185, 190, 195, 200, 207, 214, 221, 228, 234, 241,
248, 255
};
答案 2 :(得分:0)
听起来你真的想要使用对数的一些线性函数,但没有浮点数学库的开销。粗略的固定点对数可以编码为
uint_8 log2fix(uint_8 in)
{
if(in == 0)
return 0;
uint_8 out = 0;
while(in > 0)
{
in = in >> 1;
out++;
}
return out - 1;
}
这将给你一个粗略的近似值。如果您想要更精确,fast fixed point algorithm可以修改Q8.0 to Q3.5。
答案 3 :(得分:0)
你的问题过于复杂。您已经通过定义变量更新速率而不是变量PWM步骤将对数问题转换为线性问题 - 因此您基本上已经解决了问题,但没有看到简单的算术关系。
如果你选择了OCR0A vs延迟点(25,30),(50,25),(128,17),可以看出这是由(近似) y = 0.125x + 32 ,可以重新排列为 y = 32 - x / 8
所以你需要的是:
while (1)
{
if (btn_high() && OCR0A < 255) OCR0A += 1;
if (btn_low() && OCR0A > 0) OCR0A -= 1;
_delay_ms( 32 - OCR0A / 8 ) ;
}