/* 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-8 | 0
|