2013-06-04 52 views
1

有一個奇怪的問題。我終於想出瞭如何將一個循環內增加的變量「i」變成一個字符串,我可以將它傳遞給一個函數,該函數將它轉換爲輸出到顯示器的字符。遞增單個字符輸出到OLED顯示器,但它增加2而不是1

問題是,值增加2而不是1!我嘗試了一些不同的東西,但我不確定問題出在哪裏。最初,我想也許,如果你有一個調用另一個函數的函數,並且它們都使用相同的變量來遞增(即爲(int i = 0; i < 10; ++ i)),那麼「外部」函數會使「i」增加2,因爲它在「外部」循環中增加一次,而在「內部」循環中增加一次。但我認爲情況並非如此。如果它是如此「我」在我的情況下會增加兩個以上,並且我嘗試將所有計數器變量更改爲不同的名稱而不更改。無論如何,這對語言來說將是一個愚蠢的方式。除非是這樣,否則我很樂意開悟。

這裏是代碼塊給我找麻煩:

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)); 
} 

所有這些的結果是顯示屏顯示的數字增加了兩倍的延遲時間。例如,這裏的延遲是500ms,所以它每1秒更新一次。而不是去

1,2,3,4,5 ...

,因爲它應該,這是不言而喻

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

不任何人有任何建議提供?我確信在我的初始循環中這是一個愚蠢的簡單問題,但我現在看不到它。

我正在使用Atmel Studio 6編程一個xmega32a4u。所顯示的庫函數是我用於Atmel Studio的SSD1306 128x32 OLED的Adafruit圖形庫的一部分。

非常感謝您的幫助!

UPDATE:雖然我的代碼確實有一些問題,但真正的問題實際上是OLED的處理方式。顯然Adafruit忘記在他們的庫中設置正確的頁面地址來顯示。由於顯示器上的控制器可以支持128x64以及128x32的顯示器,所以必須正確設置顯示器的「結束」地址,以便控制器知道要訪問的顯示器RAM的哪些部分。該功能缺失。由於顯示器如何寫入數據RAM,並且因爲它不知道顯示器只有32像素高,所以發送到顯示器的每個其他幀實際上都被寫入到顯示器RAM的「底部」部分(即如果顯示器是128x64,那麼會出現的部分是兩倍)。所以現在一切都很好!

非常感謝放鬆,如果不是因爲他關於顯示時間的建議讓我思考問題的這一方面,可能花了我很長時間才能找出問題。

+0

「100」不是單個字符,而是三個。你的外部循環中的sprintf是你的問題的開始。 –

回答

2

你有一個緩衝區溢出。

此:

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

+0

我試着第一次改變你的建議(char c [8])而行爲沒有改變,並且snprintf函數也沒有改變。 現在顯示器向上計數,1,3,5等。一直到99,然後退出循環(循環完成後LED亮起)。我意識到空終止符,但不知怎的,這並沒有發生在我寫這個循環......所以即使有這些變化,我仍然遞增2而不是1。會不會有另一個導致這種情況的溢出?也感謝您的快速響應! – SVFeingold

+0

不知道這是否有助於解決問題,但我將i <100改爲i <1000,並且它很樂意計入3位數字。只有它增加了2,而不是1。仍然難倒... – SVFeingold

+0

此外,請原諒我的無知,但即使我已經寫了char c [2],你能不能把任何字符串放入第一個數組元素,只要它在「char」類型允許的範圍內?換句話說,包含字符串「1234」的數組仍然是一個元素(加上空終止符)數組,對嗎? – SVFeingold