Fast 7-segment number display for TFT

Thanks :smiley:

Looks great, very useful addition for TFT screens.

only minor adaptation is necessary for full compatibility with ILI9341 TFT:

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

void setup() {
  tft.begin();
  tft.fillScreen(ILI9341_BLACK); // nema default
}

void loop() {
  draw7Number(millis() / 1000 , 20 , 40 , 10 , ILI9341_WHITE , ILI9341_BLACK, -2);
}


/**********************************************************************************
 Routine to Draw Large 7-Segment formated number with Arduino TFT Library
    by William Zaggle  (Uses TFT Library DrawLine functions).

   int n - The number to be displayed
   int xLoc = The x location of the upper left corner of the number
   int yLoc = The y location of the upper left corner of the number
   int cSe = The size of the number. Range 1 to 10 uses Large Shaped Segments.
   fC is the foreground color of the number
   bC is the background color of the number (prevents having to clear previous space)
   nD is the number of digit spaces to occupy (must include space for minus sign for numbers < 0)
   nD < 0 Suppresses leading zero
  
   Sample Use: Fill the screen with a 2-digit number suppressing leading zero 

          draw7Number(38,20,40,10,WHITE, BLACK, -2);

**********************************************************************************/
void draw7Number(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S1=cS,S2=5*cS,S3=2*cS,S4=7*cS,x1=(S3/2)+1,x2=(2*S1)+S2+1,y1=yLoc+x1,y3=yLoc+(2*S1)+S4+1;
  unsigned int seg[7][3]={{(S3/2)+1,yLoc,1},{x2,y1,0},{x2,y3+x1,0},{x1,(2*y3)-yLoc,1},{0,y3+x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (xLoc+=cnt*(d=(2*S1)+S2+(2*S3)+2);cnt>0;cnt--){
    for (i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,xLoc-=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;s=(2*S1)/S3;
      if (seg[j][2])for(w=S2,t=seg[j][1]+S3,h=seg[j][1]+(S3/2),a=xLoc+seg[j][0]+S1,b=seg[j][1];b<h;b++,a-=s,w+=(2*s))tft.drawFastHLine(a,b,w,col);
      else for(w=S4,t=xLoc+seg[j][0]+S3,h=xLoc+seg[j][0]+S3/2,b=xLoc+seg[j][0],a=seg[j][1]+S1;b<h;b++,a-=s,w+=(2*s))tft.drawFastVLine(b,a,w,col);
      for (;b<t;b++,a+=s,w-=(2*s))seg[j][2]?tft.drawFastHLine(a,b,w,col):tft.drawFastVLine(b,a,w,col);
    }
  }
}

And realy big numbers on 240x320 tft. becomes available thanks to Mr. William Zaggle

I realized some may be using other orientations of the display and need numbers shown accordingly.

Here are versions for all four directions just in case... :slight_smile:

/* Routine to Draw Large 7-Segment formated number with Arduino TFT Library
   Contributed by William Zaggle  (Uses TFT Library DrawLine and Fill Rectangle functions).

   int n - The number to be displayed
   int xLoc = The x location of the upper left corner of the number
   int yLoc = The y location of the upper left corner of the number
   int cS = The size of the number. 
   fC is the foreground color of the number
   bC is the background color of the number (prevents having to clear previous space)
   nD is the number of digit spaces to occupy (must include space for minus sign for numbers < 0).


    // Example to draw the number 37 in four directions in four corners of the display
    draw7Number(37,10,10,4,WHITE,BLACK,2);          //LEFT2RIGHT
    draw7Number90(37,10,310,4,WHITE,BLACK,2);     //DOWN2UP
    draw7Number180(37,230,310,4,WHITE,BLACK,2);  //RIGHT2LEFT
    draw7Number270(37,230,10,4,WHITE,BLACK,2);    //UP2DOWN
*/
void draw7Number(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S2=5*cS,S3=2*cS,S4=7*cS,x1=cS+1,x2=S3+S2+1,y1=yLoc+x1,y3=yLoc+S3+S4+1;
  unsigned int seg[7][3]={{x1,yLoc,1},{x2,y1,0},{x2,y3+x1,0},{x1,(2*y3)-yLoc,1},{0,y3+x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (xLoc+=cnt*(d=S2+(3*S3)+2);cnt>0;cnt--){
    for (i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,xLoc-=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;
      if (seg[j][2])for(w=S2,t=seg[j][1]+S3,h=seg[j][1]+cS,a=xLoc+seg[j][0]+cS,b=seg[j][1];b<h;b++,a--,w+=2)Tft.drawHorizontalLine(a,b,w,col);
      else for(w=S4,t=xLoc+seg[j][0]+S3,h=xLoc+seg[j][0]+cS,b=xLoc+seg[j][0],a=seg[j][1]+cS;b<h;b++,a--,w+=2)Tft.drawVerticalLine(b,a,w,col);
      for (;b<t;b++,a++,w-=2)seg[j][2]?Tft.drawHorizontalLine(a,b,w,col):Tft.drawVerticalLine(b,a,w,col);
    }
  }
}

void draw7Number90(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S2=5*cS,S3=2*cS,S4=7*cS;
  unsigned int x1=cS+1,x2=S3+S2+1,y1=xLoc+x1,y3=xLoc+S3+S4+1;
  unsigned int seg[7][3]={{x1,xLoc,1},{x2,y1,0},{x2,y3+x1,0},{x1,(2*y3)-xLoc,1},{0,y3+x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (yLoc-=cnt*(d=S2+(3*S3)+2);cnt>0;cnt--){
    for (  i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,yLoc+=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;
      if (seg[j][2])for(w=S2,t=seg[j][1]+S3,h=seg[j][1]+cS,a=yLoc-(seg[j][0]+cS+S2-1),b=seg[j][1];b<h;b++,a--,w+=2)Tft.drawVerticalLine(b,a,w,col);
      else for(w=S4,t=yLoc-seg[j][0]-S3,h=yLoc-seg[j][0]-cS,b=yLoc-seg[j][0],a=seg[j][1]+cS;b>h;b--,a--,w+=2)Tft.drawHorizontalLine(a,b,w,col);
      for (;seg[j][2]?b<t:b>t;seg[j][2]?b++:b--,a++,w-=2)seg[j][2]?Tft.drawVerticalLine(b,a,w,col):Tft.drawHorizontalLine(a,b,w,col);
    }
  }
}


void draw7Number180(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S2=5*cS,S3=2*cS,S4=7*cS;
  unsigned int x1=cS,x2=S3+S2+1,y1=yLoc-x1,y3=yLoc-S3-S4-1;
  unsigned int seg[7][3]={{x1,yLoc,1},{x2,y1,0},{x2,y3-x1,0},{x1,(2*y3)-yLoc,1},{0,y3-x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (xLoc-=cnt*(d=S2+(3*S3)+2);cnt>0;cnt--){
    for (i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,xLoc+=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;
      if (seg[j][2])for(w=S2,t=seg[j][1]-S3,h=seg[j][1]-cS,a=xLoc-(seg[j][0]+cS+S2),b=seg[j][1];b>h;b--,a--,w+=2)Tft.drawHorizontalLine(a,b,w,col);
      else for(w=S4,t=xLoc-seg[j][0]-S3,h=xLoc-seg[j][0]-cS,b=xLoc-seg[j][0],a=seg[j][1]-cS-S4;b>h;b--,a--,w+=2)Tft.drawVerticalLine(b,a,w,col);
      for (;b>t;b--,a++,w-=2)seg[j][2]?Tft.drawHorizontalLine(a,b,w,col):Tft.drawVerticalLine(b,a,w,col);
    }
  }
}

void draw7Number270(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S2=5*cS,S3=2*cS,S4=7*cS;
  unsigned int x1=cS+1,x2=S3+S2+1,y1=xLoc-x1,y3=xLoc-S3-S4-1;
  unsigned int seg[7][3]={{x1,xLoc,1},{x2,y1,0},{x2,y3-x1,0},{x1,(2*y3)-xLoc,1},{0,y3-x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (yLoc+=cnt*(d=S2+(3*S3)+2);cnt>0;cnt--){
    for (i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,yLoc-=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;
      if (seg[j][2])for(w=S2,t=seg[j][1]-S3,h=seg[j][1]-cS,a=yLoc+(seg[j][0]+cS),b=seg[j][1];b>h;b--,a--,w+=2)Tft.drawVerticalLine(b,a,w,col);
      else for(w=S4,t=yLoc+seg[j][0]+S3,h=yLoc+seg[j][0]+cS,b=yLoc+seg[j][0],a=seg[j][1]-cS-S4+1;b<h;b++,a--,w+=2)Tft.drawHorizontalLine(a,b,w,col);
      for (;seg[j][2]?b>t:b<t;seg[j][2]?b--:b++,a++,w-=2)seg[j][2]?Tft.drawVerticalLine(b,a,w,col):Tft.drawHorizontalLine(a,b,w,col);
    }
  }
}

Here are the full conversions for all the Adafruit library users. Thanks Common_Ground.

I picked up one of these just to test and be sure they all worked. Also attached is a diagram that shows the pixel spacing for the numbers. The diagram should help because with really large leading zero blanked numbers, the actual displayed number often needs to be centered. One example is when displaying something like the day of the month in the center of the screen. The 31st, the 11th and the 1st should all be centered.

For those who don't know already, the way to do this is to first use the width function nD(11cS+2)-2cS to find what the width of the two digits will be for the size. Then use half of this as the xoffset from the center of the screen. So a 2 digit number at size 8 would be width 2(11x8+2)-16 or 164 pixels. Half of that would be 82 pixels so this is the amount to offset the width to start. So using xLoc as the center of the screen (120 for a 240 pixel width screen)...

draw7number(N, xLoc-82, yloc, 8, fC, bC, 2)

Now if you wanted even the # 1 to be centered as well as the number 11 or the number 31, you have to take a look at the number itself. Looking at the diagram, it works out that for half the pixel change for those numbersis 4 x cS pixels for numbers less than 20 and less than 2, plus an additional 2 x cS pixels for numbers less than 10.

draw7number(N, xLoc-82-((N<20)+(n<2))*20-(N<10)*10, yLoc, 8, fC, bC, -2)

This also exposes that the 5x and 7x scalers S2 and S4 could easily be changed on the 1st line of the function if someone wanted taller, shorter, fatter or skinnier numbers. All three scalers S2, S3 and S4 could also be adjusted down in fact if someone wanted really tiny numbers.

Hope this helps someone. :slight_smile:

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"

// For the Adafruit shield, these are the default.
#define TFT_DC 9
#define TFT_CS 10

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// If using the breakout, change pins as desired
//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

void setup() {
 
  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
}


void loop(void) {
    draw7Number(millis() / 1000 ,10,10,4, ILI9341_WHITE , ILI9341_BLACK,2);        //LEFT2RIGHT
    draw7Number90(millis() / 1000 ,10,310,4, ILI9341_WHITE , ILI9341_BLACK,2);     //DOWN2UP
    draw7Number180(millis() / 1000 ,230,310,4, ILI9341_WHITE , ILI9341_BLACK,2);  //RIGHT2LEFT
    draw7Number270(millis() / 1000 ,230,10,4, ILI9341_WHITE , ILI9341_BLACK,2);    //UP2DOWN
}

/* Routine to Draw Large 7-Segment formated number with Arduino TFT Library
   Contributed by William Zaggle  (Uses TFT Library DrawLine and Fill Rectangle functions).

   int n - The number to be displayed
   int xLoc = The x location of the upper left corner of the number
   int yLoc = The y location of the upper left corner of the number
   int cS = The size of the number. 
   fC is the foreground color of the number
   bC is the background color of the number (prevents having to clear previous space)
   nD is the number of digit spaces to occupy (must include space for minus sign for numbers < 0).


    // Example to draw the number 37 in four directions in four corners of the display
    draw7Number(37,10,10,4, ILI9341_WHITE , ILI9341_BLACK,2);          //LEFT2RIGHT
    draw7Number90(37,10,310,4, ILI9341_WHITE , ILI9341_BLACK,2);     //DOWN2UP
    draw7Number180(37,230,310,4, ILI9341_WHITE , ILI9341_BLACK,2);  //RIGHT2LEFT
    draw7Number270(37,230,10,4, ILI9341_WHITE , ILI9341_BLACK,2);    //UP2DOWN
*/
void draw7Number(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S2=5*cS,S3=2*cS,S4=7*cS,x1=cS+1,x2=S3+S2+1,y1=yLoc+x1,y3=yLoc+S3+S4+1;
  unsigned int seg[7][3]={{x1,yLoc,1},{x2,y1,0},{x2,y3+x1,0},{x1,(2*y3)-yLoc,1},{0,y3+x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (xLoc+=cnt*(d=S2+(3*S3)+2);cnt>0;cnt--){
    for (i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,xLoc-=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;
      if (seg[j][2])for(w=S2,t=seg[j][1]+S3,h=seg[j][1]+cS,a=xLoc+seg[j][0]+cS,b=seg[j][1];b<h;b++,a--,w+=2)tft.drawFastHLine(a,b,w,col);
      else for(w=S4,t=xLoc+seg[j][0]+S3,h=xLoc+seg[j][0]+cS,b=xLoc+seg[j][0],a=seg[j][1]+cS;b<h;b++,a--,w+=2)tft.drawFastVLine(b,a,w,col);
      for (;b<t;b++,a++,w-=2)seg[j][2]?tft.drawFastHLine(a,b,w,col):tft.drawFastVLine(b,a,w,col);
    }
  }
}
  
void draw7Number90(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S2=5*cS,S3=2*cS,S4=7*cS;
  unsigned int x1=cS+1,x2=S3+S2+1,y1=xLoc+x1,y3=xLoc+S3+S4+1;
  unsigned int seg[7][3]={{x1,xLoc,1},{x2,y1,0},{x2,y3+x1,0},{x1,(2*y3)-xLoc,1},{0,y3+x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (yLoc-=cnt*(d=S2+(3*S3)+2);cnt>0;cnt--){
    for (  i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,yLoc+=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;
      if (seg[j][2])for(w=S2,t=seg[j][1]+S3,h=seg[j][1]+cS,a=yLoc-(seg[j][0]+cS+S2-1),b=seg[j][1];b<h;b++,a--,w+=2)tft.drawFastVLine(b,a,w,col);
      else for(w=S4,t=yLoc-seg[j][0]-S3,h=yLoc-seg[j][0]-cS,b=yLoc-seg[j][0],a=seg[j][1]+cS;b>h;b--,a--,w+=2)tft.drawFastHLine(a,b,w,col);
      for (;seg[j][2]?b<t:b>t;seg[j][2]?b++:b--,a++,w-=2)seg[j][2]?tft.drawFastVLine(b,a,w,col):tft.drawFastHLine(a,b,w,col);
    }
  }
}


void draw7Number180(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S2=5*cS,S3=2*cS,S4=7*cS;
  unsigned int x1=cS,x2=S3+S2+1,y1=yLoc-x1,y3=yLoc-S3-S4-1;
  unsigned int seg[7][3]={{x1,yLoc,1},{x2,y1,0},{x2,y3-x1,0},{x1,(2*y3)-yLoc,1},{0,y3-x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (xLoc-=cnt*(d=S2+(3*S3)+2);cnt>0;cnt--){
    for (i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,xLoc+=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;
      if (seg[j][2])for(w=S2,t=seg[j][1]-S3,h=seg[j][1]-cS,a=xLoc-(seg[j][0]+cS+S2),b=seg[j][1];b>h;b--,a--,w+=2)tft.drawFastHLine(a,b,w,col);
      else for(w=S4,t=xLoc-seg[j][0]-S3,h=xLoc-seg[j][0]-cS,b=xLoc-seg[j][0],a=seg[j][1]-cS-S4;b>h;b--,a--,w+=2)tft.drawFastVLine(b,a,w,col);
      for (;b>t;b--,a++,w-=2)seg[j][2]?tft.drawFastHLine(a,b,w,col):tft.drawFastVLine(b,a,w,col);
    }
  }
}

void draw7Number270(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num=abs(n),i,s,t,w,col,h,a,b,si=0,j=1,d=0,S2=5*cS,S3=2*cS,S4=7*cS;
  unsigned int x1=cS+1,x2=S3+S2+1,y1=xLoc-x1,y3=xLoc-S3-S4-1;
  unsigned int seg[7][3]={{x1,xLoc,1},{x2,y1,0},{x2,y3-x1,0},{x1,(2*y3)-xLoc,1},{0,y3-x1,0},{0,y1,0},{x1,y3,1}};
  unsigned char nums[12]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x67,0x00,0x40},c=(c=abs(cS))>10?10:(c<1)?1:c,cnt=(cnt=abs(nD))>10?10:(cnt<1)?1:cnt;
  for (yLoc+=cnt*(d=S2+(3*S3)+2);cnt>0;cnt--){
    for (i=(num>9)?num%10:((!cnt)&&(n<0))?11:((nD<0)&&(!num))?10:num,yLoc-=d,num/=10,j=0;j<7;++j){
      col=(nums[i]&(1<<j))?fC:bC;
      if (seg[j][2])for(w=S2,t=seg[j][1]-S3,h=seg[j][1]-cS,a=yLoc+(seg[j][0]+cS),b=seg[j][1];b>h;b--,a--,w+=2)tft.drawFastVLine(b,a,w,col);
      else for(w=S4,t=yLoc+seg[j][0]+S3,h=yLoc+seg[j][0]+cS,b=yLoc+seg[j][0],a=seg[j][1]-cS-S4+1;b<h;b++,a--,w+=2)tft.drawFastHLine(a,b,w,col);
      for (;seg[j][2]?b>t:b<t;seg[j][2]?b--:b++,a++,w-=2)seg[j][2]?tft.drawFastVLine(b,a,w,col):tft.drawFastHLine(a,b,w,col);
    }
  }
}

It is pretty compressed so not that readable

Why? That's gotta be some of the ugliest code I've seen in a long time.

Sorry Wesfw,

Didn't know there was extra points for pretty... :cry: But it is a fair request.

Here is a greatly expanded and commented version of Draw7. I will work on expanding the other three directions for all the big code lovers or those that just like to follow what is going on.

WZ

void draw7Number(int n, unsigned int xLoc, unsigned int yLoc, char cS, unsigned int fC, unsigned int bC, char nD) {
  unsigned int num = abs(n), i, s, t, w, col, h, a, b, si = 0, j = 1, d = 0;
  unsigned int S2 = 5 * cS;  // width of horizontal segments   5 times the cS
  unsigned int S3 = 2 * cS;  // thickness of a segment 2 times the cs
  unsigned int S4 = 7 * cS;  // height of vertical segments 7 times the cS
  unsigned int x1 = cS + 1;  // starting x location of horizontal segments
  unsigned int x2 = S3 + S2 + 1; // starting x location of right side segments
  unsigned int y1 = yLoc + x1; // starting y location of top side segments
  unsigned int y3 = yLoc + S3 + S4 + 1; // starting y location of bottom side segments
  unsigned int seg[7][3] = {{x1, yLoc, 1}, {x2, y1, 0}, {x2, y3 + x1, 0}, {x1, (2 * y3) - yLoc, 1}, {0, y3 + x1, 0}, {0, y1, 0}, {x1, y3, 1}}; // actual x,y locations of all 7 segments with direction
  unsigned char nums[12] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x67, 0x00, 0x40};  // segment defintions for all 10 numbers plus blank and minus sign
  unsigned char c, cnt;
  
  c = abs(cS);         // get character size between 1 and 10 ignoring sign
  if (c>10) c= 10;
  if (c<1) c = 1;
  
  cnt = abs(nD);      // get number of digits between 1 and 10 ignoring sign
  if (cnt > 10) cnt = 10;
  if (cnt < 1) cnt = 1; 
  
  xLoc += (cnt-1) * (d = S2 + (3 * S3) + 2);   // set starting x at last digit location
  
  while( cnt > 0) {                   // for cnt number of places
  
    --cnt;
    
    if (num > 9) i = num%10;           //get the last digit 
    else if (!cnt && n<0) i = 11;              //show minus sign if 1st position and negative number
    else if (nD < 0 && !num) i = 10;   //show blanks if remaining number is zero
    else i = num;

    num = num/10;   // trim this digit from the number  
    
    for (j = 0; j < 7; ++j) {          // draw all seven segments
      
      if (nums[i] & (1 << j)) col = fC;  // if segment is On use foreground color
      else col = bC;                    // else use background color

      if (seg[j][2]) {
        
        w = S2;                        // Starting width of segment (side)
        t = seg[j][1] + S3;            // maximum thickness of segment
        h = seg[j][1] + cS;            // half way point thickness of segment
        a = xLoc + seg[j][0] + cS;     // starting x location
        b = seg[j][1];                 // starting y location
        
        while (b < h) {                // until x location = half way
           tft.drawFastHLine(a, b, w, col); //Draw a horizontal segment top 
           a--;                         // move the x position by -1
           b++;                         // move the y position by 1
           w += 2;                      // make the line wider by 2
        }
        
      } else {
        
        w = S4;                        // Starting height of segment (side)
        t = xLoc + seg[j][0] + S3;     // maximum thickness of segment
        h = xLoc + seg[j][0] + cS;     // half way point thickness of segment
        a = seg[j][1] + cS;            // starting y location 
        b = xLoc + seg[j][0];          // starting x location
        
        while (b < h) {                // until x location = half way
          tft.drawFastVLine(b, a, w, col);  // Draw a vertical line right side
          a--;                          //  move the y position by -1
          b++;                          //  move teh x position by 1
          w += 2;                       //  make the line wider by 2
        }
      }
      
      while (b < t) {  //finish drawing horizontal bottom or vertical left side of segment 
        if (seg[j][2]) {
           tft.drawFastHLine(a, b, w, col);  // Draw Horizonal line bottom
        } else {
           tft.drawFastVLine(b, a, w, col);  // Draw Vertical line left side
        }
        b++;        // keep moving the x or y draw position until t 
        a++;        // move the length or height starting position back the other way.
        w -= 2;     // move the length or height back the other way
      }
    }
    
    xLoc -=d;       // move to next digit position
  }
}

Thanks. Much nicer! They compile to the same code, right?

You might get a very small improvement by making "nums" static const...
Are fastvline and fasthline about the same speed? I was wondering if it could draw all the lines in the faster direction, and benefit... (raster scans strike again!)

Do you want N to be a long? An int on avr won't give you more than 6 digit positions...

Ps: the diagram in msg3 was lovely, and really helpful in understanding what you were doing.

Thanks again westfw...

Good call with the long. Not sure about the direction change if the extra looping on one side would offset less looping in the display memory direction or not, but might be worth testing if indeed raster is faster.

Just displaying 10 five digit numbers of size 1 showing current millis() gave:

00593
00603
00613
00622
00632
00642
00652
00662
00671
00681

So it got all 10 displayed inside of the second at size 1 averaging 9.8 ms.

Changing to 7 five digit numbers of size 2 showing current millis() gave:

00593
00618
00644
00668
00694
00719
00744

So this size slowed to an average 25.2ms.

Maybe using these benchmarks, I will try drawing in the bit friendly direction only and see if it makes a difference.

But compared to what I was getting with sprintf and drawstring and all the filled rectangles it was a big improvement in both speed and looks for any number.

WZ

Here is the expanded code in all four direction for those interested, with comments and the Long rather than Int Number value (thanks westfw :wink: ). If I find time I may look at combining them into a single function with a direction parameter.

This latest code is still the Adafruit library version with FastHLine and FastVLine.

Sorry all four versions no longer fit in-line in their big readable format. So you will have to see the attached file to get the changes.

BTW Westfw... writing in only the raster direction was not enough of a difference to overcome the overhead of writing more lines in the segment width direction rather than fewer in the segment length direction. But thanks again for the suggestion.

WZ

draw7Number.c (20.6 KB)

So, seeing as we are laying into wzaggle and critiquing his code :slight_smile: ,

   a--;   // move the x position by -1

This kind of comment is never necessary.

   foo(2);   // call the foo function, passing it a parameter of 2

Doesn't tell you anything. Just call 'a' something a bit more descriptive.

Here's a pair of functions just to draw the segments.

// note that a thickness of n will give you a segment 2n+1 pixels wide. Minimum thickness is zero.
// take care not to make your line thicker than 2 times the length
void horizontalSegment(int x, int y, int segLen, int segThick, int foreC, int backC) {
  tft.drawFastHLine(x, y, segLen, foreC);
  
  while(segThick>0) {
    tft.drawFastHLine(x, y-segThick, segThick, backC);
    tft.drawFastHLine(x+segThick, y-segThick, segLen-segThick*2, foreC);
    tft.drawFastHLine(x+segLen-segThick, y-segThick, segThick, foreC);
    
    tft.drawFastHLine(x, y+segThick, segThick, backC);
    tft.drawFastHLine(x+segThick, y+segThick, segLen-segThick*2, foreC);
    tft.drawFastHLine(x+segLen-segThick, y+segThick, segThick, foreC);
    
    segThick--;
  }
}

// note that a thickness of n will give you a segment 2n+1 pixels wide. Minimum thickness is zero.
// take care not to make your line thicker than 2 times the length
void verticalSegment(int x, int y, int segLen, int segThick, int foreC, int backC) {
  tft.drawFastVLine(x, y, segLen, foreC);
  
  while(segThick>0) {
    tft.drawFastVLine(x-segThick, y, segThick, backC);
    tft.drawFastVLine(x-segThick, y+segThick, segLen-segThick*2, foreC);
    tft.drawFastVLine(x-segThick, y+segLen-segThick, segThick, backC);
    
    tft.drawFastVLine(x+segThick, y, segThick, backC);
    tft.drawFastVLine(x+segThick, y+segThick, segLen-segThick*2, foreC);
    tft.drawFastVLine(x+segThick, y+segLen-segThick, segThick, backC);
    
    segThick--;
  }
}
a--;   // move the x position by -1

This kind of comment is never necessary.

In this case, it's sorta nice since sometimes x is called y...

Cool!

Looks like I went full circle from no comments to too many comments. I guess the nice thing about having too many of them is that people can always delete them or just ignore them. But I am plenty tough so feel free to critique away! I've been coding for 45 years but there is always more to learn. :slight_smile:

In the readability effort I changed all the x's to always be x's and the y's to always be y's.

I like PaulMurray's idea of drawing in from both sides at the same time. (Thanks) (I know a Paul Z Murray at McGill U. who would certainly have thought of this very thing.) I taught university level computer graphics with him back in the 80's but have obviously forgotten way too much.

I just needed nicer numbers for my clock/calendar indoor/outdoor temp display project. Hopefully others will benefit.

WZ

I taught university level computer graphics with him back in the 80's but have obviously forgotten way too much.

Did you by any chance know Norm Badler at UPenn?

Doesn't ring my somewhat cracked bell westfw. Possibly crossed paths at a SIGGRAPH or ASEE conference someplace, but too long ago.

Well, this is the best bit of code Ive stumbled across. Im a newbie to this Arduino programming and Id never of figured this out. I was struggling with dreadful refresh times using big numbers and the Adafruit library.

Thanks a million. My project can now use the Adafruit 1770 2.8" TFT display and has lightning quick refresh' now:)

One question though, how can I justify the numbers to the right? For example, I need to display altitude. For the most part the display will show 2 digits, occasionally there will be a <0m value and >1000m value, so Id like the 10's and 100's numbers to always be in the same position and the 1000's and -ve sign to appear and disappear as required without moving the 10's and 100's digits.

Many thanks.
Jon

Hey,

Easiest way to right justify is just to use -4 for the last number in the call. This says always use four number places and the - will blank any leading zeros rather than pad the 1000, 100 or 10's place with zero.

Hope that helps.

William

i can only seem to have the number 8 shown. regardless of the number i want to display

@max44,
What is your hardware & software setup?

I need to use this to display the value of an analog input. It will be a voltage that needs to have a decimal. Is that possible with this?