Sei sulla pagina 1di 25

1.

LOOP TEXT LED Matrix 24x6

#define BA {B01110000,B10001000,B10001000,B11111000,B10001000,B10001000}
#define BB {B11110000,B10001000,B10001000,B11110000,B10001000,B11111000}
#define BC {B11111000,B10000000,B10000000,B10000000,B10000000,B11111000}
#define BD {B11110000,B10001000,B10001000,B10001000,B10001000,B11110000}
#define BE {B11111000,B10000000,B10000000,B11110000,B10000000,B11111000}
#define BF {B11111000,B10000000,B10000000,B11110000,B10000000,B10000000}
#define BG {B01110000,B10001000,B10000000,B10011000,B10001000,B01110000}
#define BH {B10001000,B10001000,B11111000,B10001000,B10001000,B10001000}
#define BI {B11111000,B00100000,B00100000,B00100000,B00100000,B11111000}
#define BJ {B00111000,B00010000,B00010000,B00010000,B10010000,B01100000}
#define BM {B10001000,B11011000,B10101000,B10101000,B10001000,B10001000}
#define BN {B10001000,B11001000,B10101000,B10101000,B10011000,B10001000}
#define BL {B10000000,B10000000,B10000000,B10000000,B10000000,B11111000}
#define BO {B01110000,B10001000,B10001000,B10001000,B10001000,B01110000}
#define BP {B11110000,B10001000,B10001000,B11110000,B10000000,B10000000}
#define BQ {B01110000,B10001000,B10101000,B10011000,B01111000,B00001000}
#define BR {B11110000,B10001000,B10001000,B11110000,B10001000,B10001000}
#define BS {B01110000,B10001000,B01100000,B00010000,B10001000,B01110000}
#define BK {B10001000,B10010000,B11100000,B11100000,B10010000,B10001000}
#define BT {B11111000,B00100000,B00100000,B00100000,B00100000,B00100000}
#define BU {B10001000,B10001000,B10001000,B10001000,B10001000,B01110000}
#define BV {B10001000,B10001000,B10001000,B10001000,B01010000,B00100000}
#define BW {B10001000,B10001000,B10101000,B10101000,B10101000,B01010000}
#define BX {B10001000,B01010000,B00100000,B00100000,B01010000,B10001000}
#define BY {B10001000,B01010000,B00100000,B00100000,B00100000,B00100000}
#define BZ {B11111000,B00001000,B00110000,B01100000,B10000000,B11111000}
#define LA{B00000000,B01110000,B00001000,B01111000,B10001000,B01111000}
#define LB{B10000000,B10000000,B10110000,B11001000,B10001000,B11110000}
#define LC{B00000000,B01110000,B10000000,B10000000,B10001000,B01110000}
#define LD{B00001000,B00001000,B01111000,B10001000,B10001000,B01111000}
#define LE{B00000000,B01110000,B10001000,B11111000,B10000000,B01110000}
#define LF{B00110000,B01001000,B01000000,B11100000,B01000000,B01000000}
#define LG{B00000000,B01111000,B10001000,B01111000,B00001000,B01110000}
#define LH{B10000000,B10000000,B10110000,B11001000,B10001000,B10001000}
#define LI{B00100000,B00000000,B01100000,B00100000,B00100000,B01111000}
#define LJ{B00010000,B00000000,B00111000,B00010000,B10010000,B01100000}
#define LK{B10000000,B10010000,B10100000,B11000000,B10100000,B10010000}
#define LL{B01100000,B00100000,B00100000,B00100000,B00100000,B01111000}
#define LM{B00000000,B00000000,B11010000,B10101000,B10101000,B10001000}
#define LN{B00000000,B00000000,B10110000,B11001000,B10001000,B10001000}
#define LO{B00000000,B01110000,B10001000,B10001000,B10001000,B01110000}
#define LP{B00000000,B11110000,B10001000,B11110000,B10000000,B10000000}
#define LQ{B00000000,B01101000,B10011000,B01111000,B00001000,B00001000}
#define LR{B00000000,B00000000,B10110000,B11001000,B10000000,B10000000}
#define LS{B00000000,B01110000,B10000000,B01110000,B00001000,B11110000}
#define LT{B01000000,B01000000,B11100000,B01000000,B01001000,B00110000}
#define LU{B00000000,B00000000,B10001000,B10001000,B10011000,B01101000}
#define LV{B00000000,B00000000,B10001000,B10001000,B01010000,B00100000}
#define LW{B00000000,B00000000,B10001000,B10101000,B10101000,B01010000}
#define LX{B00000000,B10001000,B01010000,B00100000,B01010000,B10001000}
#define LY{B00000000,B10001000,B10001000,B01111000,B00001000,B01110000}
#define LZ{B00000000,B11111000,B00010000,B00100000,B01000000,B11111000}
#define SPACE{B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}
#define NUM0{B01110000,B10011000,B10101000,B10101000,B11001000,B01110000}
#define NUM1{B00100000,B01100000,B10100000,B00100000,B00100000,B01110000}
#define NUM2{B01110000,B10001000,B00001000,B01110000,B10000000,B11111000}
#define NUM3{B11110000,B00001000,B00001000,B01111000,B00001000,B11110000}
#define NUM4{B10001000,B10001000,B10001000,B11111000,B00001000,B00001000}
#define NUM5{B11111000,B10000000,B11110000,B00001000,B10001000,B01110000}
#define NUM6{B11111000,B10000000,B11111000,B10001000,B10001000,B11111000}
#define NUM7{B11111000,B00001000,B00001000,B01111000,B00001000,B00001000}
#define NUM8{B11111000,B10001000,B11111000,B10001000,B10001000,B11111000}
#define NUM9{B11111000,B10001000,B11111000,B00001000,B00001000,B11111000}
#define DEVIDE{B00001000,B00010000,B00100000,B00100000,B01000000,B10000000}
#define TWODOTS{B01100000,B01100000,B00000000,B00000000,B01100000,B01100000}
#define DOT{B00000000,B00000000,B00000000,B00000000,B01100000,B01100000}
#define COMA{B00000000,B00000000,B00000000,B00110000,B00110000,B01100000}
#define LINE{B00000000,B00000000,B11111000,B11111000,B00000000,B00000000}
#define QUASTION{B01110000,B10001000,B00010000,B00100000,B00000000,B00100000}
#define MARK{B00100000,B01110000,B01110000,B00100000,B00000000,B00100000}

int latchPin = 10;


int clockPin = 13;
int dataPin = 11;
int clock = 9;
int Reset = 8;
int latchPinPORTB = latchPin - 8;
int clockPinPORTB = clockPin - 8;
int dataPinPORTB = dataPin - 8;
int i = 0;
long scrolling_word[6];
int array_turn=0;
byte your_text[8][6]={BH,BI,SPACE,BW,BO,BR,BL,BD};//PUT YOU TEXT HERE

void setup(){
Serial.begin(9600);
pinMode(dataPin,OUTPUT);
pinMode(clockPin,OUTPUT);
pinMode(latchPin,OUTPUT);
pinMode(clock,OUTPUT);
pinMode(Reset,OUTPUT);
digitalWrite(Reset,HIGH);
digitalWrite(Reset,LOW);
setupSPI();
}

void display_word(int loops,byte word_print[][6],int num_patterns,int delay_langth){//


this function displays your symbols
i = 0;// resets the counter fot the 4017
for(int g=0;g<6;g++)//resets the the long int where your word goes
scrolling_word[g] = 0;
for(int x=0;x<num_patterns;x++){//main loop, goes over your symbols
// you will need to find a better way to make the symbols scroll my way is limited
for 24 columns

for(int r=0;r<6;r++)//puts the buildes the first symbol


scrolling_word[r] |= word_print[x][r];
for (int z=0;z<6;z++){//the sctolling action
for(int p=0;p<6;p++)
scrolling_word[p] = scrolling_word[p] << 1;
// end of the scrolling funcion
for(int t=0;t<delay_langth;t++){// delay function, it just loops over the same
display
for(int y=0;y<6;y++){// scaning the display
if(i == 6){// counting up to 6 with the 4017
digitalWrite(Reset,HIGH);
digitalWrite(Reset,LOW);
i = 0;
}
latchOff();
spi_transfer(make_word(0x01000000,y));// sending the data
spi_transfer(make_word(0x00010000,y));
spi_transfer(make_word(0x00000100,y));
latchOn();
delayMicroseconds(800);//waiting a bit
latchOff();
spi_transfer(0);// clearing the data
spi_transfer(0);
spi_transfer(0);
latchOn();
digitalWrite(clock,HIGH);//counting up with the 4017
digitalWrite(clock,LOW);
i++;
}
}
}
}
finish_scroll(delay_langth);
}

void finish_scroll(int delay_scroll){// this function is the same as the funcion above,
it just finishing scrolling
for (int n=0;n<24;n++){
for(int h=0;h<6;h++)
scrolling_word[h] = scrolling_word[h] << 1;
for(int w=0;w<delay_scroll;w++){
for(int k=0;k<6;k++){
if(i == 6){
digitalWrite(Reset,HIGH);
digitalWrite(Reset,LOW);
i = 0;
}
latchOff();
spi_transfer(make_word(0x01000000,k));
spi_transfer(make_word(0x00010000,k));
spi_transfer(make_word(0x00000100,k));
latchOn();
delayMicroseconds(800);
latchOff();
spi_transfer(0);
spi_transfer(0);
spi_transfer(0);
latchOn();
digitalWrite(clock,HIGH);
digitalWrite(clock,LOW);
i++;
}
}
}
}

byte make_word (long posistion,byte turn){


byte dummy_word = 0;
for(int q=0;q<8;q++){
if(scrolling_word[turn] & (posistion<<q))
dummy_word |= 0x01<<q;
}
return dummy_word;
}

void loop() {

display_word(1,your_text,8,15);// calls for the display_pattern function and


says that int loop = 15(if you do more loop the pattern whould scrole slower).

void latchOn(){
bitSet(PORTB,latchPinPORTB);
}

void latchOff(){
bitClear(PORTB,latchPinPORTB);
}
void setupSPI(){
byte clr;
SPCR |= ( (1<<SPE) | (1<<MSTR) ); // enable SPI as master
//SPCR |= ( (1<<SPR1) | (1<<SPR0) ); // set prescaler bits
SPCR &= ~( (1<<SPR1) | (1<<SPR0) ); // clear prescaler bits
clr=SPSR; // clear SPI status reg
clr=SPDR; // clear SPI data reg
SPSR |= (1<<SPI2X); // set prescaler bits
//SPSR &= ~(1<<SPI2X); // clear prescaler bits

delay(10);
}
byte spi_transfer(byte data)
{
SPDR = data; // Start the transmission
while (!(SPSR & (1<<SPIF))) // Wait the end of the transmission
{
};
return SPDR; // return the received byte, we don't need that
}

2. WORK LED 24x6

#define BA {B01110000,B10001000,B10001000,B11111000,B10001000,B10001000}
#define BB {B11110000,B10001000,B10001000,B11110000,B10001000,B11111000}
#define BC {B11111000,B10000000,B10000000,B10000000,B10000000,B11111000}
#define BD {B11110000,B10001000,B10001000,B10001000,B10001000,B11110000}
#define BE {B11111000,B10000000,B10000000,B11110000,B10000000,B11111000}
#define BF {B11111000,B10000000,B10000000,B11110000,B10000000,B10000000}
#define BG {B01110000,B10001000,B10000000,B10011000,B10001000,B01110000}
#define BH {B10001000,B10001000,B11111000,B10001000,B10001000,B10001000}
#define BI {B11111000,B00100000,B00100000,B00100000,B00100000,B11111000}
#define BJ {B00111000,B00010000,B00010000,B00010000,B10010000,B01100000}
#define BM {B10001000,B11011000,B10101000,B10101000,B10001000,B10001000}
#define BN {B10001000,B11001000,B10101000,B10101000,B10011000,B10001000}
#define BL {B10000000,B10000000,B10000000,B10000000,B10000000,B11111000}
#define BO {B01110000,B10001000,B10001000,B10001000,B10001000,B01110000}
#define BP {B11110000,B10001000,B10001000,B11110000,B10000000,B10000000}
#define BQ {B01110000,B10001000,B10101000,B10011000,B01111000,B00001000}
#define BR {B11110000,B10001000,B10001000,B11110000,B10001000,B10001000}
#define BS {B01110000,B10001000,B01100000,B00010000,B10001000,B01110000}
#define BK {B10001000,B10010000,B11100000,B11100000,B10010000,B10001000}
#define BT {B11111000,B00100000,B00100000,B00100000,B00100000,B00100000}
#define BU {B10001000,B10001000,B10001000,B10001000,B10001000,B01110000}
#define BV {B10001000,B10001000,B10001000,B10001000,B01010000,B00100000}
#define BW {B10001000,B10001000,B10101000,B10101000,B10101000,B01010000}
#define BX {B10001000,B01010000,B00100000,B00100000,B01010000,B10001000}
#define BY {B10001000,B01010000,B00100000,B00100000,B00100000,B00100000}
#define BZ {B11111000,B00001000,B00110000,B01100000,B10000000,B11111000}
#define LA{B00000000,B01110000,B00001000,B01111000,B10001000,B01111000}
#define LB{B10000000,B10000000,B10110000,B11001000,B10001000,B11110000}
#define LC{B00000000,B01110000,B10000000,B10000000,B10001000,B01110000}
#define LD{B00001000,B00001000,B01111000,B10001000,B10001000,B01111000}
#define LE{B00000000,B01110000,B10001000,B11111000,B10000000,B01110000}
#define LF{B00110000,B01001000,B01000000,B11100000,B01000000,B01000000}
#define LG{B00000000,B01111000,B10001000,B01111000,B00001000,B01110000}
#define LH{B10000000,B10000000,B10110000,B11001000,B10001000,B10001000}
#define LI{B00100000,B00000000,B01100000,B00100000,B00100000,B01111000}
#define LJ{B00010000,B00000000,B00111000,B00010000,B10010000,B01100000}
#define LK{B10000000,B10010000,B10100000,B11000000,B10100000,B10010000}
#define LL{B01100000,B00100000,B00100000,B00100000,B00100000,B01111000}
#define LM{B00000000,B00000000,B11010000,B10101000,B10101000,B10001000}
#define LN{B00000000,B00000000,B10110000,B11001000,B10001000,B10001000}
#define LO{B00000000,B01110000,B10001000,B10001000,B10001000,B01110000}
#define LP{B00000000,B11110000,B10001000,B11110000,B10000000,B10000000}
#define LQ{B00000000,B01101000,B10011000,B01111000,B00001000,B00001000}
#define LR{B00000000,B00000000,B10110000,B11001000,B10000000,B10000000}
#define LS{B00000000,B01110000,B10000000,B01110000,B00001000,B11110000}
#define LT{B01000000,B01000000,B11100000,B01000000,B01001000,B00110000}
#define LU{B00000000,B00000000,B10001000,B10001000,B10011000,B01101000}
#define LV{B00000000,B00000000,B10001000,B10001000,B01010000,B00100000}
#define LW{B00000000,B00000000,B10001000,B10101000,B10101000,B01010000}
#define LX{B00000000,B10001000,B01010000,B00100000,B01010000,B10001000}
#define LY{B00000000,B10001000,B10001000,B01111000,B00001000,B01110000}
#define LZ{B00000000,B11111000,B00010000,B00100000,B01000000,B11111000}
#define SPACE{B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}
#define NUM0{B01110000,B10011000,B10101000,B10101000,B11001000,B01110000}
#define NUM1{B00100000,B01100000,B10100000,B00100000,B00100000,B01110000}
#define NUM2{B01110000,B10001000,B00001000,B01110000,B10000000,B11111000}
#define NUM3{B11110000,B00001000,B00001000,B01111000,B00001000,B11110000}
#define NUM4{B10001000,B10001000,B10001000,B11111000,B00001000,B00001000}
#define NUM5{B11111000,B10000000,B11110000,B00001000,B10001000,B01110000}
#define NUM6{B11111000,B10000000,B11111000,B10001000,B10001000,B11111000}
#define NUM7{B11111000,B00001000,B00001000,B01111000,B00001000,B00001000}
#define NUM8{B11111000,B10001000,B11111000,B10001000,B10001000,B11111000}
#define NUM9{B11111000,B10001000,B11111000,B00001000,B00001000,B11111000}
#define DEVIDE{B00001000,B00010000,B00100000,B00100000,B01000000,B10000000}
#define TWODOTS{B01100000,B01100000,B00000000,B00000000,B01100000,B01100000}
#define DOT{B00000000,B00000000,B00000000,B00000000,B01100000,B01100000}
#define COMA{B00000000,B00000000,B00000000,B00110000,B00110000,B01100000}
#define LINE{B00000000,B00000000,B11111000,B11111000,B00000000,B00000000}
#define QUASTION{B01110000,B10001000,B00010000,B00100000,B00000000,B00100000}
#define MARK{B00100000,B01110000,B01110000,B00100000,B00000000,B00100000}

int latchPin = 10;


int clockPin = 13;
int dataPin = 11;
int clock = 9;
int Reset = 8;
int latchPinPORTB = latchPin - 8;
int clockPinPORTB = clockPin - 8;
int dataPinPORTB = dataPin - 8;
int i = 0;
int incomingByte[44];
long scrolling_word[6];
int array_turn=0;
byte patterns[100][6];
byte dummy_array[70][6]
={BA,BB,BC,BD,BE,BF,BG,BH,BI,BJ,BK,BL,BM,BN,BO,BP,BQ,BR,BS,BT,BU,BV,BW,BX,BY,BZ,SPACE,N
UM0,NUM1,NUM2,NUM3,NUM4,NUM5,NUM6,NUM7,NUM8,NUM9,DEVIDE,TWODOTS,DOT,COMA,LINE,QUASTION,
MARK,LA,LB,LC,LD,LE,LF,LG,LH,LI,LJ,LK,LL,LM,LN,LO,LP,LQ,LR,LS,LT,LU,LV,LW,LX,LY,LZ};
void setup(){
Serial.begin(9600);
pinMode(dataPin,OUTPUT);
pinMode(clockPin,OUTPUT);
pinMode(latchPin,OUTPUT);
pinMode(clock,OUTPUT);
pinMode(Reset,OUTPUT);
digitalWrite(Reset,HIGH);
digitalWrite(Reset,LOW);
setupSPI();
}

void display_word(int loops,byte word_print[][6],int num_patterns,int delay_langth){//


this function displays your symbols
i = 0;// resets the counter fot the 4017
for(int g=0;g<6;g++)//resets the the long int where your word goes
scrolling_word[g] = 0;
for(int x=0;x<num_patterns;x++){//main loop, goes over your symbols
// you will need to find a better way to make the symbols scroll my way is limited
for 24 columns

for(int r=0;r<6;r++)//puts the buildes the first symbol


scrolling_word[r] |= word_print[x][r];
for (int z=0;z<6;z++){//the sctolling action
for(int p=0;p<6;p++)
scrolling_word[p] = scrolling_word[p] << 1;
// end of the scrolling funcion
for(int t=0;t<delay_langth;t++){// delay function, it just loops over the same
display
for(int y=0;y<6;y++){// scaning the display
if(i == 6){// counting up to 6 with the 4017
digitalWrite(Reset,HIGH);
digitalWrite(Reset,LOW);
i = 0;
}
latchOff();
spi_transfer(make_word(0x01000000,y));// sending the data
spi_transfer(make_word(0x00010000,y));
spi_transfer(make_word(0x00000100,y));
latchOn();
delayMicroseconds(800);//waiting a bit
latchOff();
spi_transfer(0);// clearing the data
spi_transfer(0);
spi_transfer(0);
latchOn();
digitalWrite(clock,HIGH);//counting up with the 4017
digitalWrite(clock,LOW);
i++;
}
}
}
}
finish_scroll(delay_langth);
}

void finish_scroll(int delay_scroll){// this function is the same as the funcion above,
it just finishing scrolling
for (int n=0;n<24;n++){
for(int h=0;h<6;h++)
scrolling_word[h] = scrolling_word[h] << 1;
for(int w=0;w<delay_scroll;w++){
for(int k=0;k<6;k++){
if(i == 6){
digitalWrite(Reset,HIGH);
digitalWrite(Reset,LOW);
i = 0;
}
latchOff();
spi_transfer(make_word(0x01000000,k));
spi_transfer(make_word(0x00010000,k));
spi_transfer(make_word(0x00000100,k));
latchOn();
delayMicroseconds(800);
latchOff();
spi_transfer(0);
spi_transfer(0);
spi_transfer(0);
latchOn();
digitalWrite(clock,HIGH);
digitalWrite(clock,LOW);
i++;
}
}
}
}

byte make_word (long posistion,byte turn){


byte dummy_word = 0;
for(int q=0;q<8;q++){
if(scrolling_word[turn] & (posistion<<q))
dummy_word |= 0x01<<q;
}
return dummy_word;
}

void loop() {

// send data only when you receive data:


if(Serial.available() > 0){
delay(100);
incomingByte[array_turn] = Serial.read();
array_turn++;
}
else{
if(array_turn != 0){
for(int az=0;az<array_turn;az++){
if((incomingByte[az] > 64 && incomingByte[az] < 91) ||
(incomingByte[az] > 96 && incomingByte[az] < 123)){
if(incomingByte[az] > 64 && incomingByte[az] < 91){
for(int lal=0;lal<6;lal++)
patterns[az][lal] = dummy_array[incomingByte[az] - 65][lal];
}
else{
for(int lal=0;lal<6;lal++)
patterns[az][lal] = dummy_array[incomingByte[az] - 53][lal];
}}
else{
switch(incomingByte[az]){
case 32://space
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[26][lol];
break;
case 33://mark
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[43][lol];
break;
case 45://line
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[41][lol];
break;
case 44://coma
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[40][lol];
break;
case 46://dot
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[39][lol];
break;
case 47://dvide
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[37][lol];
break;
case 48://0
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[27][lol];
break;
case 49://1
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[28][lol];
break;
case 50://2
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[29][lol];
break;
case 51://3
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[30][lol];
break;
case 52://4
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[31][lol];
break;
case 53://5
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[32][lol];
break;
case 54://6
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[33][lol];
break;
case 55://7
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[34][lol];
break;
case 56://8
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[35][lol];
break;
case 57://9
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[36][lol];
break;
case 58://tow dots
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[38][lol];
break;
case 63://quastion
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[42][lol];
break;
default:
for(int lol=0;lol<6;lol++)
patterns[az][lol] = dummy_array[26][lol];
break;
}
}
}
}
display_word(1,patterns,array_turn,15);
array_turn =0;
}
}

//display_word(1,patterns,43,15);// calls for the display_pattern function and says


that int loop = 15(if you do more loop the pattern whould scrrol slower).

void latchOn(){
bitSet(PORTB,latchPinPORTB);
}

void latchOff(){
bitClear(PORTB,latchPinPORTB);
}

void setupSPI(){
byte clr;
SPCR |= ( (1<<SPE) | (1<<MSTR) ); // enable SPI as master
//SPCR |= ( (1<<SPR1) | (1<<SPR0) ); // set prescaler bits
SPCR &= ~( (1<<SPR1) | (1<<SPR0) ); // clear prescaler bits
clr=SPSR; // clear SPI status reg
clr=SPDR; // clear SPI data reg
SPSR |= (1<<SPI2X); // set prescaler bits
//SPSR &= ~(1<<SPI2X); // clear prescaler bits

delay(10);
}
byte spi_transfer(byte data)
{
SPDR = data; // Start the transmission
while (!(SPSR & (1<<SPIF))) // Wait the end of the transmission
{
};
return SPDR; // return the received byte, we don't need that
}

3. LED Matrix 24x8

//tốc độ chạy chữ, càng lớn chạy càng lâu


const byte SPEED = 4;

//kéo lên HIGH để cháy đèn LED, xài chung cho ROW và COL
const byte LATCH = 2;

const byte CLOCK_ROW = 3;


const byte DATA_ROW = 4;

const byte CLOCK_COL = 5;


const byte DATA_COL = 6;

//Dùng cho ROW, ứng với {00000001, 00000010, 00000100, 00001000, 00010000, 00100000, 01000000,
10000000};
const byte ROWS[8] = {1, 2, 4, 8, 16, 32, 64, 128};

//Ma trận gồm 8 dòng và 24 cột


//Mỗi byte trong 8 byte của một phần tử trong mảng sau ứng với 1 cột của ma trận. Vậy tại sao
có 8 byte trong khi chỉ cần 5 cột là đủ biểu diễn một kí tự?
//Đó là vì dư ra cho tiện cho làm thêm các hình khác, trái tim chẳng hạn

//Mình chỉ làm kí tự hoa, số và vài kí tự đặt biệt


//Chữ thường làm hơi xấu nên sẽ tính sau

//Mình cũng sẽ đăng một phần mềm nhỏ nhỏ do mình viết dùng để tạo các kí tự
byte up[26][8] = {
{B00111111, B01010000, B10010000, B01010000, B00111111, B00000000, B00000000, B00000000},//A
{B11111111, B10010001, B10010001, B10010001, B01101110, B00000000, B00000000, B000000 00},//B
{B01111110, B10000001, B10000001, B10000001, B10000001, B00000000, B00000000, B00000000},//C
{B11111111, B10000001, B10000001, B10000001, B01111110, B00000000, B00000000, B00000000},//D
{B11111111, B10010001, B10010001, B10010001, B10010001, B00000000, B00000000, B00000000},//E
{B11111111, B10010000, B10010000, B10010000, B10010000, B00000000, B00000000, B00000000},//F
{B01111110, B10000001, B10000001, B10001001, B01001110, B00001000, B00000000, B00000000},//G
{B11111111, B00010000, B00010000, B00010000, B11111111, B00000000, B00000000, B00000000},//H
{B10000001, B10000001, B11111111, B10000001, B10000001, B00000000, B00000000, B00000000},//I
{B10000011, B10000001, B11111111, B10000000, B10000000, B00000000, B00000000, B00000000},//J
{B11111111, B00011000, B00100100, B01000010, B10000001, B00000000, B00000000, B00000000},//K
{B11111111, B00000001, B00000001, B00000001, B00000001, B00000000, B00000000, B00000000},//L
{B11111111, B01000000, B00100000, B01000000, B11111111, B00000000, B00000000, B00000000},//M
{B11111111, B01000000, B00100000, B00010000, B11111111, B00000000, B00000000, B00000000},//N
{B01111110, B10000001, B10000001, B10000001, B01111110, B00000000, B00000000, B00000000},//O
{B11111111, B10010000, B10010000, B10010000, B01100000, B00000000, B00000000, B00000000},//P
{B01111110, B10000001, B10000001, B10000101, B01111110, B00000001, B00000000, B00000000},//Q
{B11111111, B10011000, B10010100, B10010010, B01100001, B00000000, B00000000, B00000000},//R
{B01100001, B10010001, B10010001, B10010001, B01001110, B00000000, B00000000, B00000000},//S
{B10000000, B10000000, B11111111, B10000000, B10000000, B00000000, B00000000, B00000000},//T
{B11111110, B00000001, B00000001, B00000001, B11111110, B00000000, B00000000, B00000000},//U
{B11111100, B00000010, B00000001, B00000010, B11111100, B00000000, B00000000, B00000000},//V
{B11111111, B00000010, B00000100, B00000010, B11111111, B00000000, B00000000, B00000000},//W
{B11000011, B00100100, B00011000, B00100100, B11000011, B00000000, B00000000, B00000000},//X
{B11100000, B00010000, B00001111, B00010000, B11100000, B00000000, B00000000, B00000000},//Y
{B10000111, B10001001, B10010001, B10100001, B11000001, B00000000, B00000000, B00000000}//Z
};

byte num[10][8] = {
{B01111110, B10000001, B10000001, B10000001, B01111110, B00000000, B00000000, B00000000},//0
{B00100001, B01000001, B11111111, B00000001, B00000001, B00000000, B00000000, B00000000},//1
{B01000011, B10000101, B10001001, B10010001, B01100001, B00000000, B00000000, B00000000},//2
{B01000001, B10010001, B10010001, B10010001, B01101110, B00000000, B00000000, B00000000},//3
{B11110000, B00010000, B00010000, B11111111, B00000000, B00000000, B00000000, B00000000},//4
{B11110001, B10010001, B10010001, B10010001, B10001110, B00000000, B00000000, B00000000},//5
{B01111110, B10010001, B10010001, B10010001, B10001110, B00000000, B00000000, B00000000},//6
{B10000000, B10000000, B10011111, B10100000, B11000000, B00000000, B00000000, B00000000},//7
{B01101110, B10010001, B10010001, B10010001, B01101110, B00000000, B00000000, B00000000},//8
{B01100000, B10010001, B10010001, B10010001, B01111110, B00000000, B00000000, B00000000}//9
};

byte specials[5][8] = {
{B00011000, B00100100, B01000010, B00100001, B01000010, B00100100, B00011000,
B00000000},//HEART
{B00000001, B00000110, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000},//,
{B00000001, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000},//.
{B11111101, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000}//!
};

//Lưu trữ giá trị để biểu diễn ma trận, 24 byte là 24 cột


//1 byte = 8 bit ứng mỗi điểm trên cột
byte leds[24];

void copyArr(byte target[8], byte source[8]) {


for (byte i = 0; i < 8; i++) {
target[i] = source[i];
}
}

//Tìm xem một kí tự ứng với đâu trong các mảng UP, NUM, SPECIALS)
void getArrFromChar(char ch, byte arr[8]) {
byte ind = (byte) ch; //Lấy mã ASCII của kí tự

if ((ind >= 48) && (ind <= 57)) {


copyArr(arr, num[ind - 48]);
return;
}

if ((ind >= 65) && (ind <= 90)) {


copyArr(arr, up[ind - 65]);
return;
}

switch (ch) {
case '$': {
copyArr(arr, specials[0]);
break;
}
case ',': {
copyArr(arr, specials[1]);
break;
}
case '.': {
copyArr(arr, specials[2]);
break;
}
case '!': {
copyArr(arr, specials[3]);
break;
}
};
}

//Thêm một kí tự, sau đó gọi hàm addCol để hiển thị từng phần của kí tự
void addChar(char chr) {
byte arr[8];
getArrFromChar(chr, arr);
for (byte i = 0; i < 8; i++) {
if (arr[i] != 0) {
addCol(arr[i]);
}
}
addCol(0);
}

//Thêm vào một cột vào mảng leds để hiển thị


void addCol(byte col) {
moveLeft();
leds[23] = col;
show(leds, SPEED);
}

void moveLeft() {
for (byte i = 0; i < 23; i++) {
leds[i] = leds[i + 1];
}
}

void parseString(String s) {
s += " ";
for (byte i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') {
addCol(0);
addCol(0);
} else {
addChar(s.charAt(i));
}
}
}

//Hiển thị mảng leds ra ma trận


void show(byte leds[24], byte hold) {
for (byte k = 0; k < hold; k++) {
for (byte i = 0; i < 8; i++) {
byte d[3] = {0, 0, 0};

for (byte j = 0; j < 24; j++) {


d[ j / 8] = d[j / 8] | ((leds[j] >> i & 1) * ROWS[7 - j % 8]);
}

digitalWrite(LATCH, LOW);
shiftOut(DATA_ROW, CLOCK_ROW, LSBFIRST, ROWS[i]);
shiftOut(DATA_COL, CLOCK_COL, MSBFIRST, d[0]);
shiftOut(DATA_COL, CLOCK_COL, MSBFIRST, d[1]);
shiftOut(DATA_COL, CLOCK_COL, MSBFIRST, d[2]);
digitalWrite(LATCH, HIGH);
// delay(10); bỏ comment nếu bạn muốn tìm hiểu kĩ thuật quét LED
}
}
}

void initPin() {
pinMode(LATCH, OUTPUT);
pinMode(CLOCK_COL, OUTPUT);
pinMode(DATA_COL, OUTPUT);
pinMode(CLOCK_ROW, OUTPUT);
pinMode(DATA_ROW, OUTPUT);
}

void setup() {
Serial.begin(9600);
initPin();
}

void loop() {
parseString("HAPPY NEW YEAR 2016");
}

4. LED Matrix 8x8

const int DATA = 12;// pin 12 của Arduino nối với pin DATA của 74HC595
const int CLOCK = 10;//pin 10 của Arduino nối với pin CLOCK của 74HC595
const int LATCH = 11;//pin 11 của Arduino nối với pin LATCH của 74HC595
/* hàng và cột của LED matrix*/
int row[] = {1, 2, 4, 8, 16, 32, 64, 128};
int column[] = {128, 64, 32, 16, 8, 4, 2, 1};
/*biểu diễn các ký tự chữ và số ở dạng HEX*/
unsigned int characterHEX[][8] = {
{0x18,0x3C,0x66,0x66,0x7E,0x66,0x66,0x66},//A
{0x78,0x64,0x68,0x78,0x64,0x66,0x66,0x7C},//B
{0x3C,0x62,0x60,0x60,0x60,0x62,0x62,0x3C},//C
{0x78,0x64,0x66,0x66,0x66,0x66,0x64,0x78},//D
{0x7E,0x60,0x60,0x7C,0x60,0x60,0x60,0x7E},//E
{0x7E,0x60,0x60,0x7C,0x60,0x60,0x60,0x60},//F
{0x3C,0x62,0x60,0x60,0x66,0x62,0x62,0x3C},//G
{0x66,0x66,0x66,0x7E,0x66,0x66,0x66,0x66},//H
{0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x7E},//I
{0x7E,0x18,0x18,0x18,0x18,0x18,0x1A,0x0C},//J
{0x62,0x64,0x68,0x70,0x70,0x68,0x64,0x62},//K
{0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E},//L
{0xC3,0xE7,0xDB,0xDB,0xC3,0xC3,0xC3,0xC3},//M
{0x62,0x62,0x52,0x52,0x4A,0x4A,0x46,0x46},//N
{0x3C,0x66,0x66,0x66,0x66,0x66,0x66,0x3C},//O
{0x7C,0x62,0x62,0x7C,0x60,0x60,0x60,0x60},//P
{0x38,0x64,0x64,0x64,0x64,0x6C,0x64,0x3A},//Q
{0x7C,0x62,0x62,0x7C,0x70,0x68,0x64,0x62},//R
{0x1C,0x22,0x30,0x18,0x0C,0x46,0x46,0x3C},//S
{0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18},//T
{0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x3C},//U
{0x66,0x66,0x66,0x66,0x66,0x66,0x3C,0x18},//V
{0x81,0x81,0x81,0x81,0x81,0x99,0x99,0x66},//W
{0x42,0x42,0x24,0x18,0x18,0x24,0x42,0x42},//X
{0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x18},//Y
{0x7E,0x02,0x04,0x08,0x10,0x20,0x40,0x7E},//Z
{0x3C,0x66,0x66,0x6E,0x76,0x66,0x66,0x3C},//0
{0x18,0x38,0x58,0x18,0x18,0x18,0x18,0x7E},//1
{0x3C,0x66,0x66,0x0C,0x18,0x30,0x7E,0x7E},//2
{0x7E,0x0C,0x18,0x3C,0x06,0x06,0x46,0x3C},//3
{0x0C,0x18,0x30,0x6C,0x6C,0x7E,0x0C,0x0C},//4
{0x7E,0x60,0x60,0x7C,0x06,0x06,0x46,0x3C},//5
{0x04,0x08,0x10,0x38,0x6C,0x66,0x66,0x3C},//6
{0x7E,0x46,0x0C,0x18,0x18,0x18,0x18,0x18},//7
{0x3C,0x66,0x66,0x3C,0x66,0x66,0x66,0x3C},//8
{0x3C,0x66,0x66,0x36,0x1C,0x08,0x10,0x20},//9
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},// khoảng trắng
{0x00,0x66,0xFF,0xFF,0x7E,0x3C,0x18,0x00}// hình trái tim, kí hiệu là '&'
};
/* ký tự đại diện để biểu diễn chữ và số trên matrix*/
char character[] =
{'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V
','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9',' ','&'};
void setup()
{
Serial.begin(9600);// Serial với baudrate 9600
/* 3 pins DATA, CLOCK, LATCH cần phải để OUTPUT*/
pinMode(DATA,OUTPUT);
pinMode(CLOCK,OUTPUT);
pinMode(LATCH,OUTPUT);
/* in ra cổng Serial "ENTER A STRING"*/
Serial.println("ENTER A STRING");
}
/* hàm nhấp nháy chữ*/
/* image là ký tự cần hiển thị,
times là số lần nhấp nháy,
on, off là độ dài của hiệu ứng*/
void blinkImage(unsigned int image[],int times,int on,int off)
{
for(int i=0;i<times;i++)
{
displayImage(image,on);// hiển thị

clearImage(off);// xóa
}
}
/*hàm hiển thị chữ lên LED matrix*/
/* image là ký tự cần hiển thị,
duration là độ dài của hiệu ứng*/
void displayImage(unsigned int image[],int duration)
{
for(int hold=0;hold<duration;hold++)
{
for(int a=0;a<8;a++)
{
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST,~image[a]);//column
shiftOut(DATA, CLOCK, MSBFIRST,row[a]);//row
digitalWrite(LATCH, HIGH);
delay(1);
}
}
}
/* hàm clear LED matrix*/
/* duration là độ dài của hiệu ứng clear*/
void clearImage(int duration)
{
for(int hold=0;hold<duration;hold++)
{
for(int a=0;a<8;a++)
{
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST,B11111111);//column
shiftOut(DATA, CLOCK, MSBFIRST,row[a]);//row
digitalWrite(LATCH, HIGH);
delay(1);
}
}
}
/*hàm scroll image sang trái*/
/* image là ký tự cần hiển thị*/
void scrollImage(unsigned int image[])
{
int shift, hold, a;//biến shift dùng để lưu số bit cần shiftOut
//biến hold dùng để điều chỉnh độ dài của hiệu ứng
//biến a dùng để lưu column và row hiện tại
for(shift = 0; shift < 9; shift++)
{
for(hold = 0; hold < 30; hold++)
{
for(a = 0; a < 8; a++)
{
digitalWrite(LATCH, 0);
/* dịch ký tự sang trái*/
shiftOut(DATA,CLOCK,MSBFIRST,~(image[a]<<shift));//column
shiftOut(DATA,CLOCK,MSBFIRST,row[a]);//row
digitalWrite(LATCH, 1);
delay(1);
}
}
}

}
void loop()
{
String string;// khai báo biến String object
/* đọc dữ liệu từ cổng Serial */
while(Serial.available() > 0)
{
char ch = Serial.read();
string += ch;// lưu ký tự vừa nhận được vào biến string
delay(5);// delay để đợi ký tự tiếp theo, KHÔNG THỂ THIẾU
}
Serial.println(string);// in string ra Serial monitor
/* hiển thị ra LED matrix */
while(Serial.available() == 0)
{
/*so sánh từng phần tử của string với
các ký tự đã được lưu trong mảng character[].
Nếu ký tự xuất hiện trong string tồn tại
trong mảng character[] thì hiển thị ra LED matrix,
nếu không tồn tại thì báo "invalid character"*/
for(int k = 0;k < string.length();k++)
{
for(int i=0;i < sizeof(character);i++)
{
if(string.charAt(k) == character[i])
{
//bỏ "//" nếu muốn sử dụng hàm blinkImage()
//blinkImage(characterHEX[i],1,30,30);
scrollImage(characterHEX[i]);
break;
}
/* nếu ko tồn tại ký tự xuất hiện trong string*/
if((i == (sizeof(character) - 1)) && (string.charAt(k) != character[i]))
{
Serial.print(string.charAt(k));
Serial.println(":invalid character");
}
}
/*kiểm tra xem có dữ liệu mới hay không*/
if(Serial.available() > 0)
break;
}
delay(300);
}
}
Giải thích
//hàng và cột của LED matrix
int row[] = {1, 2, 4, 8, 16, 32, 64, 128};
int column[] = {128, 64, 32, 16, 8, 4, 2, 1};
=> dùng để kiểm soát hàng và cột của matrix.
1 = B00000001 => hàng 0
2 = B00000010 => hàng 1
4 = B00000100 => hàng 2
....
128 = B10000000 => hàng 7
tương tự đối với cột.
- Tạo ký tự. Để biểu diễn chữ 'I' ra LED matrix, ta sẽ tạo 1 mảng sau:
I[] = {
B01111110,
B00011000,
B00011000,
B00011000,
B00011000,
B00011000,
B00011000,
B01111110};
những vị trí có số 1 sẽ là những điểm sẽ sáng trên LED matrix. Để ngắn gọn, ta có thể chuyển mảng trên về dạng số
HEX: B0111 1110 => 0111 = 7 (DEC) = 7 (HEX); 1110 = 14 (DEC) = E (HEX); ==> B01111110 =
0x7E;
tương tự ta sẽ được: I[] = {0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x7E};
==> trong đoạn code trên mình chỉ mới tạo 26 chữ cái (có mấy cái hơi xấu) và 10 chữ số, các bạn có thể chỉnh sửa cho nó đẹp
hơn và sáng tạo ra những hình ảnh khác nhé!

- hàm displayImage()

/*hàm hiển thị chữ lên LED matrix*/


/* image là ký tự cần hiển thị,
duration là độ dài của hiệu ứng*/
void displayImage(unsigned int image[],int duration)
{
for(int hold=0;hold<duration;hold++)
{
for(int a=0;a<8;a++)
{
digitalWrite(LATCH, LOW);
shiftOut(DATA, CLOCK, MSBFIRST,~image[a]);//column
shiftOut(DATA, CLOCK, MSBFIRST,row[a]);//row
digitalWrite(LATCH, HIGH);
delay(1);
}
}
}

=> Tại 1 thời điểm, chúng ta chỉ có thể điều khiển các LEDs của 1 row, do đó, trong thực tế, hình ảnh ta thấy được trên LED
matrix là do "hiện tượng lưu ảnh" của mắt, khi chúng ta quét các hàng của matrix với tốc độ rất nhanh. Để làm được việc này, sau
mỗi lần shiftOut, ta chỉ delay 1/1000 giây, và lặp lại "duration" lần sau khi đã shiftOut hết 8 bit. Giá trị của biến duration càng lớn
thì thời gian của hiệu ứng càng dài.

==> Ta sử dụng bitwise NOT (~) khi shiftOut columns, vì để bật 1 LED, row cần được nối VCC (set 1), column cần được nối
GND (set 0).

==> Nếu sử dụng LSBFIRST, ta có thể lật ngược ký tự so với ban đầu.

/*hàm scroll image sang trái*/


/* image là ký tự cần hiển thị*/
void scrollImage(unsigned int image[])
{
int shift, hold, a;//biến shift dùng để lưu số bit cần shiftOut
//biến hold dùng để điều chỉnh độ dài của hiệu ứng
//biến a dùng để lưu column và row hiện tại
for(shift = 0; shift < 9; shift++)
{
for(hold = 0; hold < 30; hold++)
{
for(a = 0; a < 8; a++)
{
digitalWrite(LATCH, 0);
/* dịch ký tự sang trái*/
shiftOut(DATA,CLOCK,MSBFIRST,~(image[a]<<shift));//column
shiftOut(DATA,CLOCK,MSBFIRST,row[a]);//row
digitalWrite(LATCH, 1);
delay(1);
}
}
}
}
5. LED Matrix 24x8 bằng AVR

a.
#include <mega8515.h>
#include <delay.h>
#define SCK PORTB.7 //Chân cấp xung để đưa data vào trong thanh ghi dịch
#define DATA PORTB.5 //Chân đưa data vào thanh ghi dịch
#define SCL PORTB.3 //Khi data đã vào trong thanh ghi dịch, đưa một xung ra chân này để
đưa data từ thanh ghi dịch ra các chân của IC74HC595

//Bốn chân sau đây điều khiển việc cấp nguồn ra các hàng của led ma trận
#define A PORTC.0;
#define B PORTC.1;
#define C PORTC.2;
#define OE1 PORTC.3;

unsigned char i,j;


void Data_in(unsigned char k){ // k là bit dữ liệu vào có giá trị là 0 hoặc 1;
DATA=k; // DATA đưa dữ liệu vào thanh ghi dịch
SCK=0; // Tạo ra một xung ở chân SCK
SCK=1;
}
void LatchData(){
SCL=0; // Sau khi đưa đủ dữ liệu vào các thanh ghi dịch
SCL=1; // ta tạo một xung để đưa dữ liệu từ thanh ghi dịch ra các chân của 74HC595
}
void main(void){
DDRB=0xFF; // Cho PORTB, PORTC là output hết
DDRC=0xFF;
SCK=1; // Ban đầu đưa các chân này lên 1
SCL=1; // Để tạo xung ta sẽ cho nó băng 0 rồi lại bằng 1
while (1){
for (i=0;i<=7;i++){ // 8 hàng, từ hàng 0 đến hàng 7 (H1 - H8)
// Ta có tất cả 8 hàng và 24 cột. Do đó phải đưa 24 bit dữ liệu ra các thanh ghi dịch
(vòng lặp for gọi 12 lần, mỗi lần đưa ra 1 bit 1, 1 bit 0)
for (j=1;j<=12;j++){
Data_in(0);
Data_in(1);
}
// Đưa ra thanh ghi dịch xong rồi, đưa data ra các chân của 74HC595
LatchData();
// PortC sẽ đưa ra các số từ 0 đến 7 ở các chân PORTC.0, PORTC.1,.PORTC.2,... Ta cộng
thêm 8 để muốn chân PORTC.3 sẽ luôn bằng 1. Con 74HC138 sẽ ở trạng thái tích cực để
giải mã từ 3 ra 8.
PORTC=i+8;
// Delay một chút để tạo hiện tượng lưu ảnh của mắt. Các bác hãy thay đổi giá trị này
để thấy rõ hiệu ứng quét hàng. Thay số 3 bằng 50 chẳng hạn.
delay_ms(3);
}
};
}

b.
Bài vừa rồi ta đã dùng cơ chế truyền dữ liệu SPI từ ATMEGA8515 ra các thanh ghi dịch bằng phần mềm. Tức là ta phải làm tuần
tự 2 việc: 1. đưa data vào ngõ vào của thanh ghi dịch, 2. Cấp cho nó một xung clock.

MCU ATMEGA8515 có sẵn phần cứng SPI, mỗi lần đưa ra ngoài được 8 bit. Có 4 chân được dành cho giao tiếp SPI là PORTB.7
(chân cấp xung clock). PORTB.6 (nhận data về). PORTB.5 (xuất data ra). PORTB.4 (tích cực mức thấp để chọn chip). Ở đây vì
chỉ xuất data ra và đám IC dịch luôn sẵn sàng để nhận dữ liệu nên ta chỉ cần 2 chân. PORTB.7 (chân clock) và PORTB.5 (chân
data out).
Chương trình đầu ta sẽ chỉnh sửa/bổ sung một chút như sau:

// SPI functions, khai báo thêm hàm spi.h


#include <spi.h>
//trong hàm main, khai báo thêm phần SPI
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 4000,000 kHz
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0x50;
SPSR=0x00;
while (1){
for (i=0;i<=7;i++){ //có 8 hàng
if (i&1){ //nếu là hàng lẻ 1,3,5,7 thì sáng trước, tắt sau
spi(0b10101010); //mỗi hàm spi đưa ra được 8 bit
spi(0b10101010); //do đó sẽ gọi 3 lần
spi(0b10101010);
} else {//nếu là hàng chẵn 0,2,4,6 thì sáng sau, tắt trước
spi(0b01010101);
spi(0b01010101);
spi(0b01010101);
}
LatchData();
PORTC=i+8;
delay_ms(2);
}
Vậy là xong bài 2, sử dụng spi bằng phần cứng của MCU.

Các bác có để ý em sửa lại delay là 2ms không? Các bác sẽ thấy hiện tượng hơi chớp ở bài 1 không còn nữa.
Bác nào tính cho em tần số quét ở bài 1 và bài 2 nào. Đây là công việc quan trọng trước khi ta vào bài 3. Thay vì dùng hàm delay,
ta sẽ dùng timer để quét led.
c.
Chưa có ai tính giúp em tần số quét nhỉ? em tính thử xem nhé. Nếu em delay 3ms, tính thêm các câu lệnh rườm rà nữa là khoảng
3.5 ms. Như vậy để quét hết 8 hàng ta sẽ cần 3.5 x 8 = 28ms. Như vậy tần số quét là 1s = 1000 ms / 28 = 35.7. Tức là 1 giây màn
hình led của ta sẽ được quét khoảng 36 lần. Ta sẽ cảm thấy hiện tượng chớp chớp trên màn hình led.

Nếu delay là 2 ms, các câu lệnh nữa là 2.5. Quét hết 8 hàng cần 2.5 x 8 =20 ms. Tần số quét sẽ là 1000 / 20 = 50 Hz. Hiện tượng
chớp không còn nữa.

Điều em muốn nói ở đây là các bác phải phân biệt tần số quét và khái niệm số hình trên giây ví dụ 24 hình /s. Tần số quét của ta
phải từ 50 Hz trở lên thì ta mới không thấy hiện tượng chớp tắt. Các bác có thể kiểm tra điều này bằng cách chuột phải lên destop
(màn hình nền windows) ->properties -> settings -> advanced -> Monitor -> Screen refresh rate bác sẽ thấy windows cho phép ta
chọn tốc độ quét của màn hình trong khoảng 60 đến 120 Hz. Các bác hãy để thử tốc độ quét thấp nhất 60Hz (hiện cao hơn tần số
50 Hz của ta) thì sẽ thấy màn hình máy tính rung rung...
Hôm nay ta bắt đầu bài 3: Thay thế hàm delay bằng ngắt Timer1. Sở dĩ ta phải dùng ngắt Timer thay cho hàm delay bởi trong khi
delay thì ta sẽ không làm được gì cả. Còn sử dụng Timer thì trong thời gian chờ đợi ta có thể chuẩn bị dữ liệu, tính toán hiệu ứng
cho hàng tiếp theo.
Em sẽ khai báo ngắt Timer1 như sau:

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15.625 kHz
// Mode: CTC top=OCR1A
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x0D;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x25; // Quyet dinh toc do quet
OCR1BH=0x00;
OCR1BL=0x00;

Timer1 có tần số hoạt động là 15625Hz tức là nó sẽ đếm 15625 lần trong vòng 1s. Ở đây, nó cứ đếm từ 0 đến 0x25 = 37 thì ngắt
Timer1 sẽ được gọi. Như vậy ngắt Timer1 sẽ được gọi với tần số là 15625/37=422 lần/s.
Chúng ta phải nhớ kích hoạt ngắt nhé:

// Timer(s)/Counter(s) Interrupt(s) initialization


TIMSK=0x40;
// Global enable interrupts
#asm("sei")

Chương trình ngắt Timer1 được viết như sau:

// Timer 1 output compare A interrupt service routine


interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{ if (r & 1){
spi(0b10101010);
spi(0b10101010);
spi(0b10101010);}
else {
spi(0b01010101);
spi(0b01010101);
spi(0b01010101);
}
LatchData();
PORTC=r+8;
r++;
if (r==8) r=0;
}

Như vậy mỗi khi ngắt Timer1 được gọi thì một hàng sẽ được quét. Ta có tất cả 8 hàng. Do đó tần số quét sẽ là: 422/8=53Hz. Với
tần số quét này màn hình led sẽ không bị chớp.

Các bác có thể thấy trong vòng lặp while (1) không còn câu lệnh nào cả. Việc quét led hoàn toàn thực hiện tự động nhờ Timer1.

while (1){
}

c. Thay delay bang ngat Timer 1


/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.8 Standard
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 7/27/2008
Author : Nguyen Hai Ha
Company : www.softviet.net
Comments:

Chip type : ATmega8515L


Program type : Application
Clock frequency : 16,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega8515.h>
#include <delay.h>
// SPI functions
#include <spi.h>

#define SCK PORTB.7


#define DATA PORTB.5
#define SCL PORTB.3

#define B PORTC.1;
#define C PORTC.2;
#define OE PORTC.3;
unsigned char r=0;
void LatchData(){
SCL=0;
SCL=1;
}
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{ if (r & 1){
spi(0b10101010);
spi(0b10101010);
spi(0b10101010);}
else {
spi(0b01010101);
spi(0b01010101);
spi(0b01010101);
}
LatchData();
PORTC=r+8;
r++;
if (r==8) r=0;
}

void main(void){
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 4000,000 kHz
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0x50;
SPSR=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15.625 kHz
// Mode: CTC top=OCR1A
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x0D;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x25; // Quyet dinh toc do quet
OCR1BH=0x00;
OCR1BL=0x00;

DDRB=0xFF;
DDRC=0xFF;
SCL=1;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;
// Global enable interrupts
#asm("sei")

while (1){
}
}
d. Tạo chữ
Bây giờ ta bắt đầu tạo chữ “CHAO” bằng chương trình Excel nhé.
Trước hết em nhắc lại một xíu về số nhị phân nhé. Một byte có 8 bit. Mỗi bit có thể biểu diễn được hai trạng thái 0 và 1. 0 ứng với
led tắt, 1 ứng với led sáng. Chúng ta đang làm một bảng led ma trận gồm 3 panels led 8x8. Như vậy, một hàng led ma trận của
chúng ta hiện nay có 24 cột. Rõ ràng ta sẽ tốn 3 bytes = 24 bits để biểu diễn dữ liệu cho một hàng. Ta sẽ truyền dữ liệu cho các IC
dịch 74HC595 của chúng ta như sau:
- Muốn cho các led của một hàng sáng hết ta sẽ truyền 3 bytes đều mang giá trị là 0b1111111 (hệ nhị phân) = 255 (hệ cơ số 10).
- Muốn cho một hàng không có led nào sáng ta sẽ truyền 3 bytes đều mang giá trị là 0b00000000 = 255.
- Muốn cho một cột sáng xong lại đến một cột tắt ta truyền 3 bytes là 0b10101010 = 2^7 + 2^5 + 2^3 + 2^1 = 128 + 32 + 8 + 2 =
178;
Bác nào con lăn tăn về việc chuyển đối số nhị phân thì xem lại sách vở một chút nhé. Các bác chỉ cần nhớ là một byte có 8 bits:
bit 7, bit 6, bit 5… và bit 0. Khi chuyển đổi từ nhị phân sang thập phân cứ hễ bit nào bằng 1 thì ta sẽ phải cộng thêm 2 lũy thừa
của bit đó. Như ở ví dụ trên số nhị phân 0b10101010 có các bit số 7, 5, 3 và 1 bằng 1 nên ta sẽ phải cộng 128, 32, 8 và 2 lại với
nhau.

Hàng đầu tiên nhập vào các giá trị của các trọng số 0 đến 7 của 3 bytes ứng với 24 cột. 1 tức là 2 mũ 0, 2 là 2 mũ 1, 4= 2^2 … và
128=2^7

Như vậy ta có được 24 bytes dùng để hiện chữ “CHAO” rồi. Các byte lần lượt là 156, 136, 112 (cho việc hiện hàng 1), 162, 72,
137 (hàng 2)… 156, 40, 114 (hàng 7), 0, 0, 0 (hàng 8).

Việc cuối cùng là ta đưa nó vào trong một mảng, mảng này sẽ được cất trên ROM của chú AVR khi nạp chương trình luôn.

Code:
XINCHAO[]={156,136,112,162,72,137,130,40,138,130,47,138,130,232,139,162,40,138,156,40,1
14,0,0,0};

e.
Qua bài trước các bác đã nắ m đươ ̣c phương pháp "ta ̣o hình" rồ i. Tức là nô ̣i dung sẽ hiể n thi ̣lên bảng led thế nào do ta thiế t kế . Nó
có thể là kí tự, bông hoa hay bấ t cứ cái gì. Và công viê ̣c bây giờ là hiể n thi ̣nó lên màn hình.

Data của chúng ta ban đầ u lưu ở trong Flash ROM. Do đó em đã khai báo
Code:
unsigned char flash
XINCHAO[]={156,136,112,162,72,137,130,40,138,130,47,138,130,232,139,162,40,138,156,40,1
14,0,0,0};

Em sẽ khai báo mô ̣t mảng trong RAM, mảng này sẽ là bô ̣ nhớ màn hình. Timer 1 của chúng ta sẽ liên tu ̣c đo ̣c mảng này và đưa ra
màn hình led. Sau này ta muố n làm hiê ̣u ứng hay bấ t cứ điề u gì thì ta chỉ viê ̣c thay đổ i cái mảng này

Code:
unsigned char DMem[24]; // Bo nho man hinh, 3 byte dau cho hang 1, 3 byte tiep theo cho
hang 2 ...
Ban đầ u em lấ y âm bản của data lưu trong flash. Các bác có thể không thèm lấ y âm bản và coi nó như là mô ̣t hiê ̣u ứng cũng đươ ̣c.
Lúc đó chữ "CHAO" sẽ không sáng nhưng background của nó thì la ̣i sáng.
Code:
for (i=0;i<=23;i++){
DMem[i]=~XINCHAO[i];
}
Trong chương trình ngắ t Timer1 ta đưa bô ̣ nhớ màn hình ra màn hình led. Lưu ý quét mỗ i hàng thì ta lấ y ra 3 bytes . Em không
muố n sử du ̣ng mảng 2 chiề u cho bô ̣ nhớ màn hình là có nguyên nhân. Các bác thử đoán xem nhé.

Code:
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void){
spi(DMem[r*3+2]); //byte thứ2 ởhà
ng thứr
spi(DMem[r*3+1]); // byte thứ1 ởhàng thứr
spi(DMem[r*3]); // byte thứ0 ởhàng thứr
LatchData();
PORTC=r+8; // đểEnable chú74138
r++;
if (r==8) r=0;
}

Đây là full source code của chúng ta cho đế n thời điể m này

f.
Hien chu CHAO (giong chuong trinh XINCHAO)
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.8 Standard
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 7/27/2008
Author : Nguyen Hai Ha
Company : www.softviet.net
Comments:

Chip type : ATmega8515L


Program type : Application
Clock frequency : 16,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega8515.h>
#include <delay.h>
// SPI functions
#include <spi.h>

#define SCK PORTB.7


#define DATA PORTB.5
#define SCL PORTB.3

#define B PORTC.1;
#define C PORTC.2;
#define OE PORTC.3;
char lenX=9;
char NoLed=3;
unsigned char flash
XINCHAO[]={156,136,112,162,72,137,130,40,138,130,47,138,130,232,139,162,40,138,156,40,1
14,0,0,0};
unsigned char DMem[24]; // Bo nho man hinh, 3 byte dau cho hang 1, 3 byte tiep theo cho
hang 2 ...
unsigned char r=0;
unsigned char i;
void LatchData(){
SCL=0;
SCL=1;
}
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void){
spi(DMem[r*3+2]);
spi(DMem[r*3+1]);
spi(DMem[r*3]);
LatchData();
PORTC=r+8;
r++;
if (r==8) r=0;
}

void main(void){
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15.625 kHz
// Mode: CTC top=OCR1A
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x0D;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x25; // Quyet dinh toc do quet
OCR1BH=0x00;
OCR1BL=0x00;

DDRB=0xFF;
DDRC=0xFF;
SCL=1;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;
// Global enable interrupts
#asm("sei")
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 4000,000 kHz
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0x50;
SPSR=0x00;
for (i=0;i<=23;i++){
DMem[i]=~XINCHAO[i];
}
while (1){

}
}

g. Chạy chữ CHAO từ trên xuống


Code:

/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.8 Standard
Automatic Program Generator
© Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version :
Date : 7/27/2008
Author : Nguyen Hai Ha
Company : www.softviet.net
Comments:

Chip type : ATmega8515L


Program type : Application
Clock frequency : 16,000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega8515.h>
#include <delay.h>
// SPI functions
#include <spi.h>

#define SCK PORTB.7


#define DATA PORTB.5
#define SCL PORTB.3

#define B PORTC.1;
#define C PORTC.2;
#define OE PORTC.3;
char lenX=9;
char NoLed=3;
unsigned char Pattern1[8]={0,1,2,3,4,5,6,7};
unsigned char flash
XINCHAO[]={156,136,112,162,72,137,130,40,138,130,47,138,130,232,139,162,40,138,156,40,1
14,0,0,0};
unsigned char DMem[24]; // Bo nho man hinh, 3 byte dau cho hang 1, 3 byte tiep theo cho
hang 2 ...
unsigned char r=0;
unsigned char i,k;
void LatchData(){
SCL=0;
SCL=1;
}
// Timer 1 output compare A interrupt service routine
interrupt [TIM1_COMPA] void timer1_compa_isr(void){
spi(DMem[r*3+2]);
spi(DMem[r*3+1]);
spi(DMem[r*3]);
LatchData();
PORTC=Pattern1[r]+8;
r++;
if (r==8) r=0;
}

void main(void){
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15.625 kHz
// Mode: CTC top=OCR1A
// OC1A output: Discon.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: Off
TCCR1A=0x00;
TCCR1B=0x0D;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x25; // Quyet dinh toc do quet
OCR1BH=0x00;
OCR1BL=0x00;

DDRB=0xFF;
DDRC=0xFF;
SCL=1;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x40;
// Global enable interrupts
#asm("sei")
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 4000,000 kHz
// SPI Clock Phase: Cycle Half
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
SPCR=0x50;
SPSR=0x00;
for (i=0;i<=23;i++){
DMem[i]=~XINCHAO[i];
}
while (1){
k=Pattern1[7];
for (i=7;i>=1;i--){
Pattern1[i]=Pattern1[i-1];
}
Pattern1[0]=k;
delay_ms(300);
}
}
6.sử dụng IC MAX7219

MAX7219 rất thuận tiện cho việc hiển thị LED ma trận nên người ta đã tạo sẵn thư viện. Các bạn có thể download tại
Trong thư viện có một số hàm thông dụng như: setLed (led sáng tại điểm); setRow (led sáng tại hàng), setColumn (led sáng tại
cột); clearDisplay (tất cả led đều bật/tắt). Do đó ta có thể điều khiển LED ma trận theo ý muốn một các khá dễ dàng.
Trong bài viết này, mình sẽ lập trình hiển thị ký tự và chạy chuỗi ký tự để các bạn có thể tham khảo.

#include "LedControl.h" // thêm thư viện


LedControl matrix = LedControl(2, 4, 3, 1);
// Chân 12 nối với chân DataIn
// Chân 11 nối với chân CLK
// Chân 10 nối với chân LOAD
// Sử dụng 1 IC MAX7219
void setup() {
matrix.shutdown(0, false); // Bật hiển thị
matrix.setIntensity(0, 15); // Đặt độ sáng lớn nhất
matrix.clearDisplay(0); // Tắt tất cả led
}
// Thiết lập mã cho các ký tự
byte A[56] = {
0x00,0x3F,0x7F,0xA4,0xA4,0x7F,0x3F,0x00, // A
0x00,0xFF,0xFF,0x98,0x94,0x92,0x61,0x00, // R
0x00,0xFF,0xFF,0x81,0x81,0x7E,0x3C,0x00, // D
0x00,0xFE,0xFF,0x01,0x01,0xFF,0xFE,0x00, // U
0x00,0x81,0x81,0xFF,0xFF,0x81,0x81,0x00, // I
0x00,0xFF,0xC0,0x30,0x0C,0x03,0xFF,0x00, // N
0x00,0x7E,0xFF,0x81,0x81,0xFF,0x7E,0x00 // O
};
// Chương trình con chạy chuỗi ký tự
void scroll() {
matrix.clearDisplay(0);
int pos = 8;
for (int j = pos; j > -56; j--) { // Vòng lặp thay đổi vị trí
for (int i = 0; i < 56; i++) { // Vòng lăp để hiển thị ký tự
matrix.setRow(0, i + j, A[i]);
}
delay(100);
}
}

// Chương trình con hiển thị từng ký tự


void show() {
matrix.clearDisplay(0);
for (int i = 0; i < 8; i++) matrix.setRow(0, i, A[i]); //Hiển thị từng hàng để được ký tự A
delay(200);
for (int i = 0; i < 8; i++) matrix.setRow(0, i, A[i + 8]);
delay(200);
for (int i = 0; i < 8; i++) matrix.setRow(0, i, A[i + 16]);
delay(200);
for (int i = 0; i < 8; i++) matrix.setRow(0, i, A[i + 24]);
delay(200);
for (int i = 0; i < 8; i++) matrix.setRow(0, i, A[i + 32]);
delay(200);
for (int i = 0; i < 8; i++) matrix.setRow(0, i, A[i + 40]);
delay(200);
for (int i = 0; i < 8; i++) matrix.setRow(0, i, A[i + 48]);
delay(200);
}
void loop() {
scroll();
show();
}

Potrebbero piacerti anche