Code Led Matrix
Code Led Matrix
#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}
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 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++;
}
}
}
}
void loop() {
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
}
#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}
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++;
}
}
}
}
void loop() {
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
}
//kéo lên HIGH để cháy đèn LED, xài chung cho ROW và COL
const byte LATCH = 2;
//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};
//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}//!
};
//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ự
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);
}
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));
}
}
}
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");
}
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()
=> 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.
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;
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:
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é:
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){
}
Project :
Version :
Date : 7/27/2008
Author : Nguyen Hai Ha
Company : www.softviet.net
Comments:
#include <mega8515.h>
#include <delay.h>
// SPI functions
#include <spi.h>
#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:
#include <mega8515.h>
#include <delay.h>
// SPI functions
#include <spi.h>
#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){
}
}
/*****************************************************
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:
#include <mega8515.h>
#include <delay.h>
// SPI functions
#include <spi.h>
#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.