Thursday, December 5, 2019

Raster Fonts on Arduino

I was asked a while ago to come up with software to print raster fonts with an arduino. This may seem simple until you realize that you must render each line of pixels individually or you’ll run out of ram. Throw some non-fixed width fonts in there and it’s a real nightmare. Anyways here’s the gist of it:

void setup()
{
	Serial.begin(38400);
	Wire.begin(); //Begin I2C as master
	pinMode(LEDPIN, OUTPUT);
	pinMode(BUTTON, INPUT);
}
 
void serialPrint(unsigned char ch, unsigned short xPos)
{
	for (int j = 6; j > -1; j--)
	{
		Serial.write(pgm_read_byte(&CharTable[ch][j + 2 + 7 * xPos]));
	}
}
 
void loop()
{
	boolean bState = digitalRead(BUTTON);
	if (nReadings < 4 && bState)
	{
		int thisReading = 0;
 
	}
	if (!bState)
	{
		nReadings++;
		while (!bState)
			bState = digitalRead(BUTTON);
	}
	if (nReadings == 4)
	{
		int curPos = 0;
		char first[50] = "";
		char second[50] = "";
		char third[50] = "";
		char fourth[50] = "";
		char fifth[50] = "";
		char sixth[50] ="";
		char seventh[50] ="";
		char eighth[50] ="";
		sprintf(&second[strlen(second)], "%3d", maxVals[0] / 87 - 18);
		sprintf(&third[strlen(third)], "%3d", maxVals[1] / 87 - 18);
		sprintf(&fourth[strlen(fourth)], "%3d", maxVals[2] / 87 - 18);
		sprintf(&fifth[strlen(fifth)], "%3d", maxVals[3] / 87 - 18);
 
		char *linesToPrint[] = { eighth, seventh, sixth, fifth, fourth, third, second, first };
		unsigned short maxLen = 0;
		for (int i = 0; i < 8; i++)
		{
				int currentWidth = 0;
				for (int j = 0; j < strlen(linesToPrint[i]); j++)
				{
					char CurrentCharacter = linesToPrint[i][j];
					currentWidth = currentWidth + pgm_read_byte(&CharTable[CurrentCharacter][1]);
				}
				if (currentWidth > maxLen)
					maxLen = currentWidth;
 
		}
		while (curPos < maxLen)
		{
			Serial.write(0x04);
			Serial.write(0x38);
			for (int j = 0; j < 8; j++)
			{
				unsigned short accum = 0;
				unsigned short charPos = 0;
				while(accum < curPos + 1)
				{
					if (charPos >= strlen(linesToPrint[j]))
					{
						serialPrint(32, 1);
						accum = curPos + 1;
						break;
					}
					if (accum + pgm_read_byte(&CharTable[linesToPrint[j][charPos]][1]) < curPos + 1)
					{
						accum = accum + pgm_read_byte(&CharTable[linesToPrint[j][charPos]][1]);
						charPos++;
					}
					else
					{
						serialPrint(linesToPrint[j][charPos], curPos - accum);
						accum = curPos + 1;
					}
				}
			}
			curPos++;
		}
		Serial.write(0x0C);
		nReadings = 0;
		maxVals[0] = 0;
		maxVals[1] = 0;
		maxVals[2] = 0;
		maxVals[3] = 0;
	}
	delay(5);
}