c - 递增单个字符以输出到 OLED 显示器,但递增 2 而不是 1

标签 c increment avr atmel

有个奇怪的问题。我终于想出了如何将一个在循​​环内递增的变量“i”转换为一个字符串,我可以将该字符串传递给一个函数,该函数将其转换为一个输出到显示器的字符。

问题是,值递增 2 而不是递增 1!我尝试了几种不同的方法,但我不确定问题出在哪里。

最初,我想也许,如果你有一个调用另一个函数的函数,并且它们都使用相同的变量来递增(即 for(int i=0; i<10;++i)),那么“外部”函数将使“i”递增 2,因为它在“外部”循环中递增一次,在“内部”循环中递增一次。但是我认为情况并非如此。如果是这样的话,在我的例子中“i”会增加两个以上,我尝试将所有计数器变量更改为不同的名称而不做任何更改。无论如何,这将是一种愚蠢的语言工作方式。除非确实如此,否则我很乐意得到启发。

这是给我带来麻烦的代码块:

for (int i=0; i<100; i++){
    char c[1]={0};                    // Create variable to hold character
    sprintf(c,"%d", i);               // Copy value of "i" as string to variable
    writeText(c,0,0,WHITE,BLACK,3);   // Write the character "c" at position 0,0. Size 3
    OLED_buffer();                    // Send display buffer
    delay_ms(500);                    // Delay before next increment
}

这里是 writeText():

void writeText(unsigned char *string, int16_t x, int16_t y, uint16_t color, uint16_t bgcolor, uint8_t size){
    unsigned char letter;
    for (int i=0; i<strlen(string); ++i){
        letter = string[i];
        if (letter != NULL){
            drawChar(x+(i*6*size),y,letter,color,bgcolor,size);
        }
    }
}

这里是 drawChar,由 writeText 调用:

void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) {

    if((x >= _width)            ||  // Clip right
    (y >= _height)              ||  // Clip bottom
    ((x + 5 * size - 1) < 0)    ||  // Clip left
    ((y + 8 * size - 1) < 0))       // Clip top
    return;

    for (int8_t i=0; i<6; i++ ) {
        uint8_t line;
        if (i == 5)
        line = 0x0;
        else
        line = font[(c*5)+i];
        for (int8_t j = 0; j<8; j++) {
            if (line & 0x1) {
                if (size == 1) // default size
                drawPixel(x+i, y+j, color);
                else {  // big size
                    fillRect(x+(i*size), y+(j*size), size, size, color);
                }
                } else if (bg != color) {
                if (size == 1) // default size
                drawPixel(x+i, y+j, bg);
                else {  // big size
                    fillRect(x+i*size, y+j*size, size, size, bg);
                }
            }
            line >>= 1;
        }
    }
}

最后是 drawPixel,由 drawChar 调用(尽管我真诚地怀疑问题会这么深):

void drawPixel(int16_t x, int16_t y, uint16_t color) {
    if ((x < 0) || (x >= width()) || (y < 0) || (y >= height()))
    return;

    // check rotation, move pixel around if necessary
    switch (getRotation()) {
        case 1:
        swap(x, y);
        x = WIDTH - x - 1;
        break;
        case 2:
        x = WIDTH - x - 1;
        y = HEIGHT - y - 1;
        break;
        case 3:
        swap(x, y);
        y = HEIGHT - y - 1;
        break;
    }

    // x is which column
    if (color == WHITE)
    buffer[x+(y/8)*SSD1306_LCDWIDTH] |= _BV((y%8));
    else
    buffer[x+(y/8)*SSD1306_LCDWIDTH] &= ~_BV((y%8));
}

所有这一切的结果是显示屏显示的数字增加了我的延迟长度的两倍。例如这里的延迟是 500 毫秒,所以它每 1 秒更新一次。而不是去

1、2、3、4、5...

如其所愿

1, 3, 5, 7, 9...

有没有人可以提供任何建议?我确定这是我初始循环中的一些愚蠢的简单问题,但我现在看不到它。

我正在使用 Atmel Studio 6 对 xmega32a4u 进行编程。显示的库函数是我移植到 Atmel Studio 的 SSD1306 128x32 OLED 的 Adafruit 图形库的一部分。

非常感谢您的帮助!

更新:虽然我的代码确实有一些问题,但真正的问题实际上是 OLED 的处理方式。显然 Adafruit 忘记在他们的库中为显示设置正确的页面地址。由于显示器上的 Controller 可以支持 128x64 和 128x32 显示器,因此必须正确设置显示器的“结束”地址,以便 Controller 知道要访问显示 RAM 的哪些部分。缺少该功能。由于显示器写入数据 RAM 的方式,并且因为它“不知道”显示器只有 32 像素高,所以发送到显示器的每隔一帧实际上都被写入了显示器 RAM 的“底部”部分(即如果显示器是 128x64,将出现的部分,两倍高)。所以现在一切正常!

非常感谢 unwind,如果不是他关于显示时间的建议让我开始思考问题的那一面,我可能要花很长时间才能弄清楚这个问题。

最佳答案

你有一个缓冲区溢出。

这个:

char c[1]={0};                    // Create variable to hold character
sprintf(c,"%d", i);   

没有在字符串缓冲区中分配足够的空间 c保存一位数的字符串。请记住,C 中的字符串以 0 结尾,因此 1 位数字的字符串需要 2 个字符。由于您的循环达到 100,您最终将向缓冲区写入 3 + 1 个字符,覆盖更多。不确定您想象中的效果如何。

很可能sprintf()正在覆盖您的循环索引变量,尽管由于您遇到未定义的行为,任何事情都可能发生。

将这两行更改为:

char c[8];
sprintf(c, "%d, i);

或者,如果有,请使用 snprintf() :

snprintf(c, sizeof c, "%d", i);

防止缓冲区溢出。

如果您只想要 i 的最低有效位,做这样的事情:

snprintf(c, sizeof c, "%d", i % 10);

这使用模(C 中的 %)运算符计算除以 10 的余数,即“个”数。

UPDATE 在阅读了您的评论后,我倾向于认为您的问题是时间问题之一,也许显示内容没有按照您的预期刷新,所以您只能看到您构建的每一秒“框架”。您应该能够使用调试器很容易地看到您确实构建并显示了每个数值,方法是在 sprintf() 之后中断。在根循环中。

更新 2:正因为它困扰了我,你的 writeText()函数可以简化很多,字符与 NULL 的比较很奇怪( NULL 是指针,而不是字符)并且毫无意义,因为您已经检查过 strlen() :

void writeText(const unsigned char *string, int16_t x, int16_t y, uint16_t color,
               uint16_t bgcolor, uint8_t size)
{
  while(*string != '\0')
  {
    drawChar(x + (i * 6 * size), y, *string, color, bgcolor, size);
    ++string;
  }
}

另请注意 const ;采用指向数据的指针的函数,函数只能读取 应始终声明 const .

关于c - 递增单个字符以输出到 OLED 显示器,但递增 2 而不是 1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16912343/

相关文章:

c - strcmp() 给出段错误 : 11 and pointer from integer warning

c++ - 错误 : cast from 'char*' to 'unsigned int' loses precision

c++ - 通过 fscanf() 获取文本文件中的所有字符返回无效的字符计数

java - 有人可以解释 i+++x 吗?

python - 尝试在此单行循环中增加 Y

c++ - 增量工作非常奇怪

c 预处理器宏在扩展后连接参数

组合宏会产生错误

android - 如何在 Android 的 native 代码中获取基于网络的位置?

C - 大括号和双指针内的指针