【问题标题】:Mapping (x,y) co-ordinates to bits in a byte array - as quickly and efficiently as possible将 (x,y) 坐标映射到字节数组中的位 - 尽可能快速有效
【发布时间】:2012-04-06 04:15:57
【问题描述】:

我正在使用 C#(.NET Micro FrameworkNetduino Plus 上运行)来控制 84 x 48 像素的 LCD 屏幕。

LCD 屏幕中的每个像素都有两种状态:1 (ON) 或 0 (OFF)。为了控制屏幕中的像素,我需要发送一个 504 bytes 数组,其中每个 byte 代表一列 8 个像素(即,屏幕被“拆分”为 6 行,每行 84 x 8 像素)。

最好用一个例子来证明这一点:

  • 字节00000001 (2^0) 表示一列八个像素,其中列顶部的第一个像素为ON (1)。

  • 字节 00001001 (2^0 + 2^3) 表示另一列 8 个像素,其中从列顶部算起的第一个和第四个像素为 ON。

从这里您可以看到按位AND 操作将显示给定列中的哪些像素是ON 或OFF。例如,查看给定 8 像素列中的第 4 个像素是否为 ON:

00001001    AND
00001000
-----------------
00001000 > 0
∴ The 4th pixel is ON

问题是我需要能够使用(x,y) 坐标来访问屏幕中的每个像素。例如,(3,10) 点表示屏幕左上角像素右侧 4 和下方 11 的像素。同样,(83,47) 点代表屏幕右下角的像素。

我编写了以下 C# 代码来实现这一点:

byte[] display = new byte[504];

// storing these means they don't need to be calculated every time:
byte[] base2 = { 1, 2, 4, 8, 16, 32, 64, 128 };

// Determine if the pixel is ON (true) or OFF (false)
public bool PixelState(Pixel px)
{
    return (display[GetColumn(px)] & base2[GetPxNum(px)]) > 0;
}

// Find the number of the pixel in its column of 8
private int GetPxNum(Pixel px)
{
    return px.y % 8;
}

// Find the index of the byte containing the bit representing the state of a pixel
private int GetColumn(Pixel px)
{
    return (px.y / 8 * 84) + px.x;
}

// Set a pixel's state
public void SetPixel(Pixel px, bool state)
{
    int col = GetColumn(px);
    int num = GetPxNum(px);

    if (state && !PixelState(px))
        display[col] += base2[num];
    else if (!state && PixelState(px))
        display[col] -= base2[num];
}

// Represents one (x,y) point
public struct Pixel
{
    public int x, y;

    public Pixel(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

由于这是在微控制器上运行的,因此我需要代码尽可能快速高效。这也是必要的,因为这些方法可能会被快速连续调用多次以更新 LCD 屏幕中的像素。

因此,我的问题是 如何使这段代码更快、更高效?有没有更好的方法来解决这个问题?

编辑:经过一些广泛的测试,我意识到我应该在GetColumn 中使用Math.Floor(或只是一个整数运算)。我已经更新了我的代码。

【问题讨论】:

  • 您如何在微控制器中使用 C#?或者它只是一个概念证明?另外:哪个微控制器?这个问题很大程度上取决于可用的指令集。
  • 当然,我应该在问题中包含该信息。这是 Netduino Plus:netduino.com/netduinoplus/specs.htm,它使用 Atmel AT91SAM7X512 微控制器。
  • 那么您的框架优化几乎受到了限制。这类框架往往很糟糕,所以让它更快更有效的方法是......放弃.NET并坚持使用纯 ASM 或至少是较低级别的语言,如 C(Atmel 的 C 非常酷,你应该使用它!)顺便说一句,你真的需要让它更有效吗?这似乎不会成为瓶颈,因此您可能会成为过早优化的受害者。
  • 哎呀,我忘了你在写比特,这就是为什么我无法理解你的代码:P
  • 顺便说一句,仔细看看 netduino,它看起来像是一个很棒的硬件。有点贵(与我期待的 Raspberry PI 相比),但它看起来很棒。

标签: c# embedded bit-manipulation .net-micro-framework lcd


【解决方案1】:

SetPixel中的这个小sn-p:

if (state && !PixelState(px))
    display[col] += base2[num];
else if (!state && PixelState(px))
    display[col] -= base2[num];

可以替换为:

if (state)
    display[col] |= base2[num];
else
    display[col] &= (byte)~base2[num]; // You could precompute this inverse array too

如果您有足够的可用内存,预计算可能没问题,但说真的,现在 uC 拥有如此强大的处理能力。你真的会注意到一点位移或否定吗?


此外,您可能对不使用 (double)Math.ceiling() 感兴趣,因为您的微控制器可能不支持浮点,因此必须对其进行仿真(因此会降低性能。使用 (float) 会更好(单精度仿真更快)但更好的是:

return ( (px.y/8 + ((px.y%8)?1:0)) * 84 ) + px.x;

编辑:仔细看看netduino,它可能有一个FPU(虽然我在数据表中看不到它,所以它可能没有...... .) 整数数学替代方案可能更快:)


它是否更快只能通过测试来保证,但就像我在 cmets 中所说的那样,这可能会成为一个瓶颈,你看起来就像另一个过早优化的受害者。

这里最大的瓶颈是你的框架。

【讨论】:

  • 抱歉,您的意思是(px.y % 8 > 0) ? 1 : 0)?您的代码出现类型转换错误。
  • 别担心 - 我刚刚意识到我应该在GetColumn 中发言而不是天花板。我已经更新了问题并为您的答案提交了编辑。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 2022-01-17
  • 1970-01-01
  • 2012-07-31
  • 2015-04-04
  • 2014-03-25
  • 1970-01-01
相关资源
最近更新 更多