我希望能够在我的LCD模块上以0英尺到20000英尺的高度显示英尺。从电位计读取数字,我可以旋转以更改值。此时电位器显示从0到1023,但我需要适当缩放这些,以便从0-20000英尺读取。除此之外,我希望下面的行显示一个“条形图”来表示海拔高度增加。 LCD每行有20个块,因此条形图的范围可以从1个块到20个块。
sprintf(buf, "Altitude: %d ", DELVAL2); // display altitude level
lcd_putxy(1,0,buf);
for (delay = 0; delay < 50000; delay++); // introduce a delay
sprintf(buf, "*", DELVAL2 ); // display bar graph
lcd_putxy(2,0,buf);
for (delay = 0; delay < 50000; delay++); // introduce a delay
到目前为止,这是我的代码。它从电位计DELVAL2
读取值并将其显示在LCD上。有人可以解释一下我如何适当地缩放数据以生成高度和条形图的方法。
答案 0 :(得分:1)
如果您的DELVAL2在0-1023范围内,您可以将其缩放到0-20000,但是你不能获得比(1/1024)* 20000更高的分辨率。为什么?您可以读取的最小值(单个位)是1/1024。您的最大值为20000,因此DELVAL2上的一位更改将导致20000/1024 = 19,53的缩放值更改。
您可以计算如何缩放它,它已在stackoverflow上描述: How to scale down a range of numbers with a known min and max value
您必须记住,您可能会陷入浮点运算,这是您可能想要避免的事情。例如,你可以做这样的事情
scaled = (DELVAL2 * 1953) / 1000;
而不是
scaled = DELVAL2 * 19.53;
请记住,在此计算中可以获得的最大值将是1024 * 1953 = 1999872,因此您需要32位变量。可能需要额外的强制转换,具体取决于您的体系结构和编译器,例如
scaled = (DELVAL2 * (uint32_t)1953) / 1000;
关于第二个问题 - 条形图 - 你很好。计算您需要多少个符号并绘制它们。它缩小而不是向上缩小。简单的划分就足够了。当您知道需要多少个符号时,可以用简单的循环生成它们
for(int i = 0; i < num; i++)
buf[i] = '*';
buf[i] = 0; //last symbol is 0 to stop drawing
lcd_putxy(2,0,buf);
答案 1 :(得分:0)
将[0...1023]
缩放为[0...20000]
乘以20,000,然后除以1023.
int altitude = (int) ((potentiometer*20000L + 1023/2)/1023);
代码使用long
乘法,因为int
在微控制器上可能只有16位。如果INT_MAX == 0x7FFFFFFF
,则无需。
+ 1023/2
是提供四舍五入的转化。
答案 2 :(得分:0)
据推测,buf
是一个16位整数,并包含底值。据推测,你可以依赖它限制在值[0,1023]。
如果你这样做
int scaledbuf;
scaledbuf = buf >> 5;
您将在[0,32736]范围内获得scaledbuf
的值。然后你可以做
if (scaledbuf > 20000) scaledbuf = 20000;
以牺牲你的一些范围为代价,这将给你一个[0,20000]范围内的值而不进行任何乘法,只有左移。
但是,无论如何,你都要在延迟循环中进行循环,所以你可以将乘法的成本控制在20以上。
int scaledbuf;
scaledbuf = buf * 20;
if (scaledbuf > 20000) scaledbuf = 20000;
这样可以在保持16位算术范围的同时保留更多的音域范围。