banner_2__resize
Giỏ hàng

Điện thoại cố định028.6264.1482
Bán hàng
: 0965.605.840 - 0868.532.813

Địa chỉ: 565/19 Bình Thới, P.10, Q.11, TP.HCM

+ Bán hàng trực tiếp: Từ Thứ 2 - Thứ 7: 8h00' sáng - 6h00' tối
                                    Riêng Chủ nhật: 8h00' sáng - 2h00' chiều
+ Bán hàng online: từ Thứ 2 - Thứ 7: 8h00' sáng - 5h00' chiều
+ Hỗ trợ kỹ thuật: từ Thứ 2 - Thứ 7: 8h00' sáng - 5h00' chiều

DANH MỤC SẢN PHẨM
Thống kê truy cập
Đang truy cập: 248
Trong ngày: 1405
Trong tuần: 1405
Lượt truy cập: 2648026

Bài 4: Hướng dẫn lập trình Led ma trận, hoàn chỉnh

Qua bài trước các bác đã nắm được phương pháp "tạo hình" rồi. Tức là nội dung sẽ hiển thị 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 thị 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,114,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 tục đọ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ì lạ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ử dụ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;
}

Vậy là xong, các bác hãy biên dịch và nạp vào AVR. Kết quả sẽ như bài viết đầu tiên của em



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

 

Code:
6. 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 
#include 
// SPI functions
#include 

#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,114,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){

    }
}

Bài này đã xong, các bác hãy tùy biến flash data để tạo ra các hình ảnh

Thay đổi độ sáng màn hình led

Một bảng led chuyên nghiệp sẽ có thêm phần điều chỉnh độ sáng. Ban ngày thì cần sáng hơn nhưng buổi tối thì giảm xuống để không gây cảm giác chói mắt khó chịu. Việc điều khiển được độ sáng có thể dùng để tạo hiệu ứng chữ hiện ra từ từ hoặc biến mất từ từ. Có các IC chuyên dụng cho phép thay đổi dòng cấp cho led để thay đổi độ sáng. Còn ở đây chúng ta sẽ dùng phần mềm.
Nguyên lý thay đổi độ sáng như sau:



Giả sử tần số quét của ta là 50Hz, tức là 1s ta sẽ quét 50 lần do đó 1 lần quét của chúng ta sẽ mất T =20 ms và 50T=1s.

Trong thời gian T ta sẽ phải sáng lần lượt tất cả các hàng, ở đây số hàng của ta là 8. Do đó mỗi hàng sẽ sàng trong thời gian là t=T/8 = 2.5 ms. Đây sẽ là mức sáng nhất ta có thể cấp cho màn hình led.

Vậy nếu chúng ta có thể chỉ cho mỗi hàng sáng trong một thời gian ít hơn t=2.5ms (nhưng vẫn giữ nguyên tần số quét 50Hz) thì độ sáng sẽ giảm.

Hình trên mô tả việc thay đổi độ sáng bằng 3/4 hay 1/4 so với ban đầu.

Đây là bài tập nên em không có source code cho phần này mà chỉ mô tả nguyên tắc làm. Các bác hãy sửa lại chương trình theo ý tưởng thay đổi độ sáng này nhé.

Từ trước đến nay khi quét thì khi quét đến hàng 1 thì ta sẽ đưa data của hàng 1 ra, quét đến hàng 2 thì data của hàng 2.... và quét đến hàng cuối cùng thì ta sẽ đưa data của hàng cuối cùng. 

Đọc đến chỗ này có bác lại bảo em lẩm cẩm. Quét đến hàng 1 thì không đưa data của hàng 1 ra thì đưa cái gì không lẽ đưa ra hàng 8. Ấy, chính là ở chỗ đó. Nếu quét đến hàng 1 ta đưa data của hàng thứ 8, đến hàng 2 ta đưa data của hàng thứ 7... đến hàng thứ 8 ta lại đưa data của hàng thứ 1. Vậy ta được cái gì nhỉ? 

Hihihi, ta được cái chữ "CHAO" bị lộn ngược đúng không. Mấu chốt là ở chỗ đó. Ta muốn dịch chuyển cái chữ "CHAO" từ dưới lên trên ta cũng sẽ làm tương tự. Lúc quét hàng 1 ta đưa data hàng 2, quét hàng 2 lại đưa data hàng 3.... Rõ ràng như vậy thì chữ "CHAO" của ta bị xích lên trên....

Và đây là source code:

Code:
7. Chạy chữ CHAO từ trên xuống
/*****************************************************
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 
#include 
// SPI functions
#include 

#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,114,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);
    }
}

Vậy còn hiệu ứng gì nữa không nhỉ? Thêm một vài cái nếu sử dụng nguyên tắc này. Xóa chữ "CHAO" từ trên xuống hay dưới lên này, Hiện chữ từ trên xuống, dưới lên, trong ra ngoài, ngoài vào trong... Nói chung tùy vào óc tưởng tượng của các bác.

 

(Nguồn: dientuvietnam.net)

In bài viết
LIÊN HỆ

Địa chỉ: 565/19 Bình Thới, P.10, Q.11, TP.HCM

Giờ làm việc:
+ Bán hàng trực tiếp: Từ Thứ 2 - Thứ 7 (8h00' sáng - 6h00' tối) - Chủ nhật (8h00' sáng - 2h00' chiều)
+ Bán hàng online: từ Thứ 2 - Thứ 7 (8h00' sáng - 5h00' chiều)

☎ Điện thoại cố định: 028.6264.1482
☎ 
Bán hàng:
0965.605.840 (Zalo) - 0868.532.813 (Zalo)

✉ Email: sale@chipn24.com

Design by Thiết kế WEB