Source file: /~heha/Mikrocontroller/Displays/max.zip/main.cpp

/* LED-Display 32×8 mit 4x MAX7219

Hardware: ATmega32U4 auf Pro Micro
Pin	Port	Funktion
1	Ucc	Ucc
2	GND	GND
3	DIN	MOSI	B2	SPI-Interface
4	CS		B6	SPI-Interface
5	CLK	SCK	B1	SPI-Interface

Funktion: Uhr
*/

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
//#include <avr/interrupt.h>
//#include <avr/sleep.h>
//#include <avr/fuse.h>
#include <avr/signature.h>	// gepatcht: "const" weg!

//FUSES={
// 0x7B,	// Stromspar-Oszillator 128 kHz ohne Taktteiler
// 0xF9,	// Brown-Out unter 4,3 V
//};

typedef unsigned char byte;
#define NOINIT __attribute__((section(".noinit")))
//#define W 32
#define H 8
#define LEN 4	// Kettenlänge verketteter MAX7219

static void setbytes(unsigned w) {
 PORTB&=~0x40;	// CS Low
 byte i=LEN; do{
  SPDR=w>>8;	// D15..D8
  while (!(SPSR&0x80));	// warte bis fertig
  SPDR=w;	// D7..D0
  while (!(SPSR&0x80));	// warte bis fertig
 }while (--i);
 PORTB|= 0x40;	// CS High
}

static const byte*setbytes(byte prefix, const byte*line) {
 PORTB&=~0x40;	// CS Low
 byte i=LEN; do{
  SPDR=prefix;	// D15..D8
  while (!(SPSR&0x80));	// warte bis fertig
  SPDR=line[--i];	// D7..D0
  while (!(SPSR&0x80));	// warte bis fertig
 }while (i);
 PORTB|= 0x40;	// CS High
 return line+LEN;
}

static byte screenbuffer[LEN*H];

static void screenout() {
 const byte*l=screenbuffer;
 for(byte y=0; y<H;) l=setbytes(++y,l);
}

// Daten der Breite w und Höhe h (max.8) an Position x/y in screenbuffer ausgeben
// Die Daten liegen stets in Spalten-Bytes ("Sprossen") mit Bit0 = oben vor.
// Kein Clipping!!
static void bitblt(const byte*data, byte w, byte h, byte x, byte y=0) {
 do{					// Anzahl Sprossen
  byte b=pgm_read_byte(data++);
  byte m=0x80>>(x&7);			// Bitposition (Spalte)
  byte*buf=screenbuffer+y*LEN+(x>>3);	// Byteposition (Spalte)
  for (byte i=0; i<h; i++,b>>=1,buf+=LEN) {	// Jedes Bit eine Zeile
   if (b&1) *buf|=m; else *buf&=~m;	// Bits setzen oder löschen
  }
  x++;
 }while(--w);
}

static const PROGMEM byte fnt4x7[4*10]={
 0x3E,0x41,0x41,0x3E,	// 0
 0x04,0x02,0x7F,0x00,	// 1
 0x62,0x51,0x49,0x46,	// 2
 0x22,0x49,0x49,0x36,	// 3
 0x18,0x14,0x12,0x7F,	// 4
 0x27,0x45,0x45,0x39,	// 5
 0x3E,0x49,0x49,0x30,	// 6
 0x01,0x71,0x09,0x07,	// 7
 0x36,0x49,0x49,0x36,	// 8
 0x06,0x49,0x49,0x3E};	// 9

static const PROGMEM byte fnt3x5[3*10]={
 0x0E,0x11,0x0E,	// 0
 0x04,0x02,0x1F,	// 1
 0x19,0x15,0x12,	// 2
 0x15,0x15,0x1F,	// 3
 0x0C,0x0A,0x1F,	// 4
 0x17,0x15,0x1D,	// 5
 0x1E,0x15,0x09,	// 6
 0x01,0x19,0x07,	// 7
 0x1F,0x15,0x1F,	// 8
 0x17,0x15,0x1F};	// 9

static const PROGMEM byte dp[1*2]={
 0x00,0x22};		// kein Doppelpunkt, Doppelpunkt

static void outdigit(byte digit, byte x, byte y=0) {
 bitblt(fnt4x7+digit*4,4,7,x,y);
}

static void outsmall(byte digit, byte x, byte y=0) {
 bitblt(fnt3x5+digit*3,3,5,x,y);
}

static struct _time{
 byte sec,min,hour;
 byte day,mon,year;
 void advance();
}time;		// für Uhr vorbereiten

void _time::advance() {
 if (++time.sec==60) {
  time.sec=0;
  if (++time.min==60) {
   time.min=0;
   if (++time.hour==24) {
    time.hour=0;
    if (++time.day==32) {
     time.day=1;
     if (++time.mon==13) {
      time.mon=1;
      if (++time.year==100) time.year=0;
     }
    }
   }
  }
 }
}

int main() {
 PORTB = 0xF8;	// h1hh h000
 DDRB  = 0x47;	// 3+1 Ausgänge
 ACSR  = 0x80;	// Analogvergleicher aus
 SPCR  = 0x50;	// SPI-Modus 0, Master, MSB zuerst, f/4, PB3:1 gehen zum SPI
 SPSR  =0x81;	// Doppelte Frequenz: 8 MHz
// sei();		// zunächst ist INT0 die einzige Interruptquelle
 setbytes(0x0900);	// No-Decode Mode
 setbytes(0x0A03);	// Reduzierte Helligkeit
 setbytes(0x0B07);	// Scan-Limit: Alle Teilen
 setbytes(0x0C01);	// Kein Shutdown
 setbytes(0x0F00);	// Normalbterieb
 for(;;) {
  outdigit(time.hour/10,0);
  outdigit(time.hour%10,5);
  bitblt(dp+(PORTB&1),1,7,10);
  outdigit(time.min/10,12);
  outdigit(time.min%10,17);
  outsmall(time.sec/10,25);
  outsmall(time.sec%10,29);
  screenout();
  time.advance();
  PINB  |= 0x01;	// RX-LED blinken lassen
  _delay_ms(50);
 }
}
Detected encoding: UTF-80