Having a strange problem. I finally figured out how to turn a variable "i" that increments inside a loop into a string that I can pass to a function which turns it into a character that is output to a display.
The trouble is, the value increments by 2 rather than by 1! I have tried a few different things but I'm not sure where the problem lies.
Initially, I thought that perhaps, if you have a function that calls another function, and they both use the same variable to increment (i.e. for(int i=0; i<10; ++i)), then the "outer" function would have "i" increment by two because it is incremented once in the "outer" loop and once in the "inner" loop. However I think this is not the case. If it were so "i" would get incremented by more than two in my case, and I tried changing all the counter variables to different names with no change. It would be a silly way for the language to work, anyway. Unless of course it IS the case, I'd love to be enlightened.
Here is the code block giving me trouble:
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
}
Here is 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);
}
}
}
Here is drawChar, called by 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;
}
}
}
And finally drawPixel, called by drawChar (though I sincerely doubt the problem goes this deep):
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));
}
The result of all this is that the display shows a number that increments by twice the length of my delay. So for instance the delay here is 500ms, so it updates every 1 second. Rather than going
1, 2, 3, 4, 5...
as it should, it goes
1, 3, 5, 7, 9...
Does anyone have any advice to offer? I'm sure that it is some stupid simple problem in my initial loop, but I just can't see it right now.
I am using Atmel Studio 6 to program an xmega32a4u. The library functions shown are part of the Adafruit graphics library for the SSD1306 128x32 OLED that I ported into Atmel Studio.
Thanks so much for the help!
UPDATE: Although my code did have some problems, the real issue was actually with the way the OLED was addressed. Apparently Adafruit forgot to set the correct page address in their libraries for the display. As the controller on the display can support a 128x64 as well as a 128x32 display, the "end" address for the display must be set correctly so that the controller knows which parts of the display RAM to access. That function was missing. Because of how the display writes the data ram and because it didn't "know" that the display was only 32 pixels tall, every other frame sent to the display was actually being written to the "bottom" part of the display ram (i.e. the part that WOULD appear if the display was 128x64, twice as tall). So now everything works great!
A big thanks to unwind, if not for his suggestion about the display timing getting me thinking about that side of the issue, it might have taken me a long time to figure out the problem.