|
|
View previous topic :: View next topic |
Author |
Message |
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
Question on KS0108 graphics display character update |
Posted: Wed Jan 14, 2015 4:19 pm |
|
|
Hi, i am doing some work for myself using the KS0108 128X64 GLD display and so far I have been able to do quite a bit with it in terms of graphics and character display on a GPS based application using a modified version of CCS GLCD prog example but I seem to have a problem with the flickering when updating the screen. I am using a PIC18F45K22 running at 16 MHz and unfortunately I do not have enough RAM available to use the FAST_GLCD update where you write the entire screen to a RAM page. I tried going to faster clock rates on the PIC but anything >16 MHz gives me crap all over the display and things just don't seem to work (although this may have to do with some other serial process between the GPS receiver and the PIC).
So what I am looking for is a simple method to just update a particular range of characters on a given line location and not have to update the entire screen this would make for a much smoother view. I figure the way to do this is to just write a 5X7 pixel fill in its complementary value (so all pixels are off) to each of the characters I want to update and then update the new value characters. I guess this is probably something that some have already done and I did not want to re-invent the wheel or perhaps there is abetter method. In any event I searched throughout this forum and did not see such answer. Perhaps someone could help me with such.
Thank you |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Thu Jan 15, 2015 8:07 am |
|
|
Hi,
The 'stock' 5x7 character display routine provided by CCS in 'GLCD.c' will turn ON pixels only based on the character data. This means that the display
area must be cleared before each update, which can cause an annoying ' 'flicker' depending on the update rate. I suppose that is what you are
observing?
I solved this issue by explicitly controlling the state (OFF or ON) of each pixel in the character, so I can simply write whenever necessary without
having to clear anything first. I generally also keep track of any values that I'm displaying, and only update the text when there is a change.
Here is the relevant change to glcd_text57:
Code: |
for(j=0; j<5; ++j, x++) // Loop through character byte data
{
for(k=0; k<7; ++k) // Loop through the vertical pixels
{
if(bit_test(pixelData[j], k)) // Check if the pixel should be set
glcd_pixel(x, y+k, ON); // Draws the pixel
else
glcd_pixel(x, y+k, OFF); // Clears the pixel
}
}
|
Hope this helps!
John |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Thu Jan 15, 2015 9:47 am |
|
|
John,
Thank you for your help on this and YES that is exactly the problem I have the characters get written one over the other and if there is any change in any of them you just see the sum of all the previous pixels light up and it is basically unreadable, so I do a total display clear and re-write the screen, now everything is ok but you get the annoying page flicker. For sure, I though your code would definitely work as it seems to me that is exactly what I wanted to do. However, I still have the same problem with the characters overlapping if I don't do a page clear. Perhaps I have not placed your suggested code in the right place.
See excerpt of code where I placed your suggested lines.
Code: |
#ifdef LARGE_LCD
void glcd_text57(int16 x, int16 y, char* textptr, int8 size, int1 color)
#else
void glcd_text57(int8 x, int8 y, char* textptr, int8 size, int1 color)
#endif
{
int8 j, k, l, m; // Loop counters
int8 pixelData[5]; // Stores character data
for(; *textptr != '\0'; ++textptr, ++x)// Loop through the passed string
{
if(*textptr < 'S') // Checks if the letter is in the first font array
memcpy(pixelData, FONT[*textptr - ' '], 5);
else if(*textptr <= '~') // Check if the letter is in the second font array
memcpy(pixelData, FONT2[*textptr - 'S'], 5);
else
memcpy(pixelData, FONT[0], 5); // Default to space
// Handles newline and carriage returns
switch(*textptr)
{
case '\n':
y += 7*size + 1;
continue;
case '\r':
x = 0;
continue;
}
if(x+5*size >= GLCD_WIDTH) // Performs character wrapping
{
x = 0; // Set x at far left position
y += 7*size + 1; // Set y at next position down
}
for(j=0; j<5; ++j, x+=size) // Loop through character byte data
{
for(k=0; k < 7; ++k) // Loop through the vertical pixels
{
// if(bit_test(pixelData[j], k)) // Check if the pixel should be set
if(bit_test(pixelData[j], k)) // Check if the pixel should be set
{
glcd_pixel(x, y+k, ON); // Draws the pixel /////////////////////////////////////////
else /////////////////////////////////////////
glcd_pixel(x, y+k, OFF); // Clears the pixel ///////////////////////////////////////////
for(l=0; l < size; ++l) // These two loops change the
{ // character's size
for(m=0; m < size; ++m)
{
glcd_pixel(x+m, y+k*size+l, color); // Draws the pixel
}
}
}
}
}
}
}
#endif |
|
|
|
Jerson
Joined: 31 Jul 2009 Posts: 125 Location: Bombay, India
|
|
Posted: Thu Jan 15, 2015 7:11 pm |
|
|
The modification should go to the innermost for loop (m) which changes the font size. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Fri Jan 16, 2015 9:05 am |
|
|
I have tried moving these three lines of code inside the for(m) loop but still get the same results, so I am not sure that such method will ever work. The only thing I have been able to do is to write a bar that negates all previous pixels and then re-write once again to update that text field as shown below:
Code: |
glcd_bar(10, 43, 125, 43, 7, OFF);
sprintf(LCDText"Lon:%u:%5.3g%c",Lon_Deg,Lon_Min,E_W);
glcd_text57(10,40, LCDText, 1, ON);
|
Although the above does work if you have more than one field you are updating it tends to give you a refresh flicker similar to the vertical sync on an old B&W TV set. I guess there is no other shortcut methods other than writing to a page of ram (which needs 1K of ram that I don't have here) and then using the FAST_GLCD update.
Maybe using a better display than the KS0108 may also help |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Fri Jan 16, 2015 7:50 pm |
|
|
Hi,
Sorry, I should have posted the entire routine originally. I should be able to get to it this weekend, but if not I'll post it Monday morning!
John |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Jan 19, 2015 8:00 am |
|
|
Hi,
Here is my complete, modified glcd_text57 routine. Note that I have removed the 'Size' parameter as I never found that produced satisfactory
results, so I created my own routine to deal with larger sized fonts!
Code: |
// Purpose: Write text on a graphic LCD
// Inputs: (x,y) - The upper left coordinate of the first letter
// textptr - A pointer to an array of text to display
// color - ON or OFF
void glcd_text57(int x, int y, char* textptr, int1 color)
{
int i, j, k, l, m; // Loop counters
BYTE pixelData[5]; // Stores character data
for(i=0; textptr[i] != '\0'; ++i, ++x) // Loop through the passed string
{
if(textptr[i] < 'S') // Checks if the letter is in the first text array
memcpy(pixelData, TEXT[textptr[i]-' '], 5);
else if(textptr[i] <= '~') // Check if the letter is in the second array
memcpy(pixelData, TEXT2[textptr[i]-'S'], 5);
else
memcpy(pixelData, TEXT[0], 5); // Default to space
if(x+5 >= GLCD_WIDTH) // Performs character wrapping
{
x = 0; // Set x at far left position
y += 7 + 1; // Set y at next position down
}
for(j=0; j<5; ++j, x++) // Loop through character byte data
{
for(k=0; k<7; ++k) // Loop through the vertical pixels
{
if(bit_test(pixelData[j], k)) // Check if the pixel should be set
glcd_pixel(x, y+k, ON); // Draws the pixel
else
glcd_pixel(x, y+k, OFF); // Clears the pixel
}
}
}
}
|
Hope this gets you up-and-running!!
John |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Jan 19, 2015 1:20 pm |
|
|
John,
I certainly appreciate your help with this. I substituted your code for the same routine that you have replaced and although it appears to work at first, the same thing happens when a new field value changes, it just writes over the previous pixels without clearing the past ones and after a couple of screen writes all you have is a mass of previously lit pixels compounded on one another and the entire text line is just totally unreadable. The only way to do this would be to clear the previous characters and then write the new ones. I am now doing this with a negated fill bar and then I write the new characters as I explained before, unfortunately that also gives you some level of field flicker. I am not sure there is a way around other than writing the screen to ram or getting a better display module like the T6963 |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Jan 19, 2015 3:31 pm |
|
|
Hi,
You undoubtedly have something else going on? Can you make a very small, compilable test program for us to look at? Just the absolute minimum
required to demonstrate the problem!
My hunch is that you are somehow shifting the text as you are writing it to the GLCD, which will give you the result that you appear to be seeing even
when using a text routine that clears/writes pixels explicitly.
John |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Mon Jan 19, 2015 5:33 pm |
|
|
Well it is a long program so I will just post the pertinent just to be brief.
.H file
Code: | #include <18F45K22.h>
#device ADC=10
#zero_ram
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOPBADEN //PORTB pins are configured as digital I/O on
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or
#use delay(internal=16000000)
void Init() // initialization
{
set_tris_b(0x00);
set_tris_c(0x80);
set_tris_d(0x00);
setup_wdt(WDT_OFF);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
glcd_init(ON);
}
|
RS232 interrupt and data from GPS
Code: |
#INT_RDA
void RDA_isr()
{ cbuff[next_in] = getc();
last_in = next_in;
if(cbuff[next_in] == '$' ) // this is the begining of the NMEA sentence
count =0; // we set the RecDatBuffer[count] so count is at the begining 0
// if((cbuff[next_in] != '\r' ) || (cbuff[next_in] != '\n' )) // if we wanted to end the NMEA sentence at end of line
if(cbuff[next_in] != '*' ) // keep storing in characters if we have not reached the end of the buffered sentence
{RecDatBuffer[count] = cbuff[next_in];
count++; }
// here we look to see if we have the "$GPRMC" and the termination char available, meaning we have the whole sentence
if((RMC) && (cbuff[next_in] == '*' )) // we terminate at * the two byte checksum wich we discard this is the end of the buffered sentence
{ BufferFlag= TRUE; // now that we have the sentence we set the flag so we can parse the buffered sentence
count++;
RecDatBuffer[count] = NULL; } // put in null delimiter to terminate NMEA sentence
next_in++;
if(next_in == BUFFER_SIZE)
next_in = last_in;
}
|
Routine that actually writes GPS data to the display after parsing NMEA sentence.
Code: |
glcd_bar(10, 13, 125, 13, 7, OFF); ///// draw an invisible bar to erase entire text line
sprintf(LCDText"Date:%u/%u/%lu",monthValue,dayValue,PresentYear);// get the txt content for the line
glcd_text57(10,10, LCDText, 1, ON); // write the entire text line
glcd_bar(10, 23, 125, 23, 7, OFF); //glcd_bar(x1, y1, x2, y2, width, color) glcd_bar(10, 23, 100, 23, 7, OFF);
sprintf(LCDText"UTC:%sH:%sM:%sS",hour_nn,min_nn,sec_nnnnn);
glcd_text57(10,20, LCDText, 1, ON);
glcd_bar(10, 33, 125, 33, 7, OFF);
sprintf(LCDText"Lat:%u:%5.3g%c",Lat_Deg,Lat_Min,N_S);
glcd_text57(10,30, LCDText, 1, ON);
glcd_bar(10, 43, 125, 43, 7, OFF);
sprintf(LCDText"Lon:%u:%5.3g%c",Lon_Deg,Lon_Min,E_W);
glcd_text57(10,40, LCDText, 1, ON);
glcd_bar(10, 53, 125, 53, 7, OFF);
sprintf(LCDText"Status:%s",Status);
glcd_text57(10,50, LCDText, 1, ON);
|
main routine
Code: |
void main()
{
char GPS_String[] = "$GPRMC,172958.00,A,2658.71175,N,08204.50983,W,0.036,,080115,,,D*6A"; // only used for parse testing
//int8 index;
Init();
glcd_init(ON);
glcd_rect(0, 0, 126, 63, YES, ON); // Outline the screen with a square but background is filled ************
sprintf(LCDText"GPS Data\0"); // we use sprintf() to write to the string array LCDtext[]
glcd_text57(22,15, LCDText, 2, OFF); //we write this at 2 times the size of the normal font (1) we also use white background on black letter
sprintf(LCDText"Using GPS click\0");
glcd_text57(20,40, LCDText, 1, OFF);
delay_ms(5000);
glcd_init(ON); // Must initialize the LCD to clear screen
glcd_rect(0, 0, 126, 63, NO, ON);
//ParseNMEA(); // only for manual test of parsing
while(TRUE)
{
if(BufferFlag)
ParseNMEA();
#ifdef FAST_GLCD
glcd_update();
#else
delay_us(1); // Reduces flicker by allowing pixels to be on
// much longer than off
#endif
restart_wdt();
}
}
|
I did not include many of the parsing routines nor did I include the CFAG12864B.c and graphics.c which are CCS examples for the KS0108 that I just modied for my own use. The above program works just fine for the exception that I get the annoying update blinking. I have written this for the 16X2 LCD and it works flawlessly. When you say "you are somehow shifting the text as you are writing it to the GLCD" this may happen if I move the GPS antenna and I get longer strings like "Invalid Data" instead of "Valid Data" which will cause that problem. Perhaps there may be a shift due to loss of data or a longer or shorter data message been written to the screen.
Now for example if I was to continuosly write this data to the screen:
Code: |
sprintf(LCDText"Hello cruel world!");
glcd_text57(10,20, LCDText, 1, ON);
|
I will only see: Hello cruel world! where i wrote to on the LCD without any blurring and everything looks fine!.
But if now I do the following:
Code: |
sprintf(LCDText"the number is: \u",n++);
glcd_text57(10,20, LCDText, 1, ON);
|
The portion that says "the number is:" will look fine, but the actual number (n) printed on the LCD screen turns totally blurry from pixelation as it increments, because the actual character being written is changing and the previous pixels just stay ON which I think is my problem here. |
|
|
Jerson
Joined: 31 Jul 2009 Posts: 125 Location: Bombay, India
|
|
Posted: Mon Jan 19, 2015 10:55 pm |
|
|
can you try a simple exercise?
Change the statement to this
Code: |
sprintf(LCDText,"the number is: %u ",n++);
glcd_text57(10,20, LCDText, 1, ON);
|
By doing this, you are trailing the number with spaces that will erase any residue of longer numbers. |
|
|
cbarberis
Joined: 01 Oct 2003 Posts: 172 Location: Punta Gorda, Florida USA
|
|
Posted: Tue Jan 20, 2015 7:04 pm |
|
|
Thank you Jerson, although I have not had the time to setup my breadboard and do further testing, what you imply I think is correct but unfortunately that blank space takes up valuable number of characters that would exceed my capacity for text on that row and most probably will wrap to the next line below. |
|
|
Jerson
Joined: 31 Jul 2009 Posts: 125 Location: Bombay, India
|
|
Posted: Tue Jan 20, 2015 10:28 pm |
|
|
It is just a suggestion to check if it resolves your problem.
What I do expands on this concept a little bit more
I have a printc routine that uses the character '\r' to trigger a clear to end of line. So printing something like
Code: |
printc("Number is %u\r",num);
|
will print the message with the number followed by as many spaces as will take the cursor to the end of the current row. It is not very fast, but, serves my purpose well. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|