Also ich glaub nicht, daß irgendjemand den Code sehen will oder was damit anfangen kann. Ich musste mich schon etwas auf die Hinterbeine stellen, damit ich den Code schnell genug bekomme und alles eingebaut, was ich gaben wollte. Ausserdem war ich aufn ATmega8 festgelegt, und sooo groß ist der ja auch nicht...

Also hier mal eines von 17 Modulen. Es kümmert sich um die Aufbereitung der Daten für den Multiplex. Dokumentiert ist nicht wirklich viel...
Code:
#include <AVR.h>
#include "ports.h"
#include "pattern.h"
#include <div.h>
#include "timer2.h"
#include "hell.h"
#include "timer1-job.h"
#include <avr/delay.h>

#include "menu.h"

pattern_t pat;

// Feste Muster für Ziffer 0=2, 1, 3
typedef uint16_t muster_t[3][10];

const muster_t m_wurfel PROGMEM = {
	/*1*/		{ 0x0, 0x8, 0x0c, 0x26, 0x33, 0x3b, 0x3f },
	/*2,0*/	{ 0x0, 0x10, 0x101, 0x54, 0x145, 0x155, 0x16d, 0x1d7, 0x1ef, 0x1ff },
	/*3*/		{ 0x0, 0x2, 0x5, 0x7 }
};

const muster_t m_fill PROGMEM = {
	/*1*/		{ 0x0, 0x1, 0x5, 0x15, 0x17, 0x1f, 0x3f },
	/*2,0*/	{ 0x0, 0x1, 0x9, 0x49, 0x4b, 0x5b, 0xdb, 0xdf, 0xff, 0x1ff },
	/*3*/		{ 0x0, 0x1, 0x3, 0x7 }
};

void pattern_out (uint8_t num)
{
	pattern_t *p = &pat;

	RELOAD ("b", p);

	uint8_t off = 0;
	uint8_t tick = p->pwm.tick;
	uint8_t duty = p->pwm.duty;
	uint8_t max  = p->pwm.max;

	uint8_t tnum = num >> 2;

	p->rownum = num = num & 3;

	if (0 == num)
	{
		tick++;

		if (tick >= max)
			tick = 0;

		p->pwm.tick = tick;
	}

	if	(tick >= duty)
		off = 1;

	if (hell.state == HS_MESS)
	{
		if (!off)
			hell.mess_count++;

		return; // TIMSK &= ~TIMSK_T1;
	}

	if (hell.state == HS_PREPARE_MESS)
	{
		hell_mess_start();
		return;
	}
	// alles aus
	SET_KATHODES;

	// Gap durch SOFT-PWM
	if (hell.state == HS_AWAIT_PATTERN_GAP
		// hook in Anfang einer längeren off-Sequenz
		&& num == 0  &&  tick == duty
		// nur, wenn duty < 100%, redundant!
		&& duty < max)
	{
			// 1 extra Gap zum relax der LEDs
			if (tick == duty)
			{
				hell.state = HS_PREPARE_MESS;

				MAKE_IN_ANODES;
				CLR_ANODES;
				SET (PORT_ANO1);			MAKE_OUT (PORT_ANO1);
				SET (PORT_ANO0);			MAKE_OUT (PORT_ANO0);
				SET (PORT_ANO2);			//MAKE_OUT (PORT_ANO2);
			CLR_KATHODES;
			_delay_loop_1 (1);
			SET_KATHODES;

				return;
			}
	}

	CLR_ANODES;
	MAKE_IN_ANODES;
	
	if (num == 3 && tnum <= 3)
	{
		/*3*/
		/*7*/
		/*11*/
		/*15*/
		// Gap durch MUX
		return;
	}
	if (off && num < 3)
		return;

	// PullUps für Spalte4 (rote Spalte als Trenner)
	if (num == 3)
	{
		if (tnum > 3 && (PM_BCD == p->mode))
		{
			tnum %= 4;
			if (tnum < 3)
			{
				if (0 == tnum)	{ MAKE_IN (PORT_ANO0); SET (PORT_ANO0); }
				if (1 == tnum)	{ MAKE_IN (PORT_ANO1); SET (PORT_ANO1); }
				if (2 == tnum)	{ MAKE_IN (PORT_ANO2); SET (PORT_ANO2); }
				CLR (PORT_KAT4);
			}
		}

		return;
	}

	uint16_t bits = pat.row[num];

	uint8_t pow2 = POW2 (num);
	{ // Blinken
		if (pat.blink_count >= 50)
			if (pow2 & pat.blink_row)
				bits &= ~pat.blink_mask;
	}

	uint8_t portc = bits;
	if (0 == num)	SET      (PORT_ANO0);
	if (0 == num)	MAKE_OUT (PORT_ANO0);
	BARRIER;
	if (1 == num)	SET      (PORT_ANO1);
	if (1 == num)	MAKE_OUT (PORT_ANO1);
	BARRIER;
	if (2 == num)	SET      (PORT_ANO2);
	if (2 == num)	MAKE_OUT (PORT_ANO2);
	BARRIER;

	PORTC = ~0x1f | ~portc;
	if (bits & (1<<5))	CLR (PORT_KAT5);
	if (bits & (1<<6))	CLR (PORT_KAT6);
	if (bits & (1<<7))	CLR (PORT_KAT7);
	if (bits & (1<<8))	CLR (PORT_KAT8);
}

uint16_t set_n_bits0 (uint8_t total, uint8_t n)
{
	return set_n_bits (total, n, 0);
}

// setzt n bits von total (rechts)
// 0 <= n <= total
// verwendet rndval[]
uint16_t set_n_bits (uint8_t total, uint8_t n, uint32_t quot /*rndval*/)
{
	uint16_t val;

	if (n > total)
		n = total;

		val = 0;

	while (n != 0)
	{
		uint8_t  pos;

		// Constraint "e" forces quot into y,z
		// Otherwise z has to be marked as clobbered (by udiv32)

		__asm__ __volatile (
			"movw r22, %A0"      CR_TAB
			"movw r24, %C0"      CR_TAB
			"mov r18, %3"        CR_TAB
			"clr r19"	         CR_TAB
			"clr r20"  	         CR_TAB
			"clr r21"            CR_TAB
			"rcall __udivmodsi4" CR_TAB
			"movw %A0, r18"      CR_TAB
			"movw %C0, r20"      CR_TAB
			"mov  %1, r22"
				: "=e" (quot), "=r" (pos) /* rem */
				:  "0" (quot), "r" (total)
				: "r18", "r19", "r20", "r21",
				  "r22", "r23", "r24", "r25",
				  "r26", "r27" 
		);

		uint16_t mask = 1;

		// pos-tes freies Bit suchen
		while (1)
		{
			if (!(val & mask))
				if (pos-- == 0)
					break;

			mask <<= 1;
		}

		val |= mask;

		total--;
		n--;
	}

	return val;
}

/*
 Bildet pat.bits[] ab auf pat.row[]
 pat.bits[4]: Bitpattern der einzelnen Ziffern
 pat.row[3]:  Die 3 geMUXten Zeilen

 Durch diese Anordnung der Bits werden nur gleichfarbige
 LEDs gegeneinander gemultiplext.

 8 765 43 210    set bits: pat.row[?]
 3 222 11 000    pat.data[?]

 2 876 54 876    pat.row[2]
 1 543 32 543    pat.row[1]
 0 210 10 210    pat.row[0]

 # @@@ ** QQQ    row 2
 # @@@ ** QQQ    row 1
 # @@@ ** QQQ    row 0

*/

uint16_t bits_to_row (uint8_t row)
{
	pattern_t *pp = &pat;
	RELOAD ("z", pp);

	uint8_t val0 = pp->bits[0];
	uint8_t val1 = pp->bits[1];
	uint8_t val2 = pp->bits[2];
	uint8_t val3 = pp->bits[3];

	if (0 == row)
	{
		val1 <<= 3;
		val2 <<= 5;
	}

	if (1 == row)
	{
		val0 >>= 3;
		val1 <<= 1;
		val2 <<= 2;
		val3 >>= 1;
	}

	if (2 == row)
	{
		val0 = pp->bits[0] >> 1;		val0 >>= 5;
		val1 >>= 1;
		val2 = pp->bits[2] >> 1;
		val3 >>= 2;
	}

	val0 &= 7;    // 000000111
	val1 &= 3<<3; // 000011000
	val2 &= 7<<5; // 011100000

	uint16_t res = val0 | val1 | val2;

	if (val3 & 1) // 100000000
		res |= 0x100;

	return res;
}

void digit_to_bits (uint8_t n, uint8_t max)
{
	uint16_t wert;
	uint8_t mask = POW2 (n);
	uint8_t dig = pat.digit[n+2];

	if (dig > max)
		dig = max;

	if (PM_WURFEL == pat.mode || PM_FILL == pat.mode)
	{
		// 1-->0        0,2-->1       3-->2
		uint8_t idx = n-1;
		if (idx >= 0x80)
			idx = 1;

		const muster_t * muster = & m_wurfel;
		if (PM_FILL == pat.mode)
			muster = & m_fill;

		wert = pgm_read_word (& (*muster)[idx][dig]);
	}
	else if (PM_COLORS == pat.mode)
	{
		wert = 0;

		if (pat.data[0] & mask)	wert = 0xffff;
	}
	else //(PM_RANDOM == p->mode)
	{
		wert = set_n_bits (max, dig, pat.rand[n]);
	}

	pat.bits[n] = wert;
}

static uint16_t pattern_data_to_row_2434 (uint8_t data)
{
	udiv8_t qrem = { .quot = data};

	uint8_t j, shift = 0;
	uint16_t row = 0;

	for (j=0; j<4; j++)
	{
		uint8_t leds = 3;
		if (j == 3) leds >>= 1;
		if (j == 1) leds--;

		qrem = udiv8 (qrem.quot, leds+1);
		row |= set_n_bits0 (leds, qrem.rem) << shift;
		shift += leds;
	}

	return row;
}

static uint16_t pattern_data_to_row_bin (uint8_t data)
{
	uint16_t row = data;
	uint8_t data3 = pat.data3;

	if (data3 & 1)
		row |= 0x100;

	pat.data3 = (data3 >> 1);

	return row;
}

void pattern_data_to_rows()
{
	pattern_t * pp = &pat;
	RELOAD ("y", pp);

	uint16_t (*func) (uint8_t);

	if (PM_BIN == pp->mode)
	{
		pp->data3 = pp->data[3];
		func = pattern_data_to_row_bin;
		goto _call_func;
	}

	if (PM_2434 == pp->mode)// || PM_BIN == pp->mode)
	{
		func = pattern_data_to_row_2434;

_call_func:;
		pp->row2[0] = func (pp->data[0]);
		pp->row2[1] = func (pp->data[1]);
		pp->row2[2] = func (pp->data[2]);

		goto _eiuhr;
	}

	{
		udiv8_t qrem;

		qrem = udiv8 (pp->data[0], 10); pp->digit[0] = qrem.rem; pp->digit[1] = qrem.quot;
		qrem = udiv8 (pp->data[1], 10); pp->digit[2] = qrem.rem; pp->digit[3] = qrem.quot;
		qrem = udiv8 (pp->data[2], 10); pp->digit[4] = qrem.rem; pp->digit[5] = qrem.quot;
	}

	if (PM_BCD == pp->mode) // || PM_BCD5 == pp->mode)
	{
		uint8_t i, * pdig = pp->digit;
		for (i=0; i<=2; i++)
		{
			uint8_t dig0 = *pdig++;
			uint8_t dig1 = *pdig++;
			dig1 = swap (dig1);

			pp->row2[i] = (dig1 << 1) | dig0;
		}
	}
	else
	{
		digit_to_bits (0, 9);
		digit_to_bits (1, 6);
		digit_to_bits (2, 9);
		digit_to_bits (3, 3);

		pp->row2[0] = bits_to_row (0);
		pp->row2[1] = bits_to_row (1);
		pp->row2[2] = bits_to_row (2);
	}
_eiuhr:;

#define BLINK_DAUER 15
	uint16_t row0 = pp->row2[0];
	uint8_t blink;

	blink = count.ms10.eiuhr_blink-(50-BLINK_DAUER/5);

	if (MID_MAIN == menu.id
		&& menu.eiuhr.runs
		&& blink < BLINK_DAUER)
	{
		row0 ^= 1;
	}
	pp->row[0] = row0;
	pp->row[1] = pp->row2[1];
	pp->row[2] = pp->row2[2];
}