有个奇怪的问题。我终于想出了如何将一个在循环内递增的变量“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/