[Matrix LED] Bài 15: Điều chế độ rộng xung trên LED ma trận FULL

pwm hub75

Chú ý: Các bạn đọc hiểu tất cả các bài trước thì đọc bài này mới hiểu nhé

Từ đầu tutorial tới giờ, chúng ta đã điều khiển led matrix ở dạng mono ( tức 1 bit màu – chỉ có trạng thái bật hoặc tắt các pixel) để điều khiển được nhiều màu sắc hơn chúng ta phải điều chế độ rộng xung trên từng con led, để làm được việc này, về cơ bản phải liên tục bơm 1 lượng rất lớn dữ liệu vào ma trận led

Thông thường, người ta sử dụng số bit pwm để mô tả số mức sáng khác nhau của đèn led. Ví dụ 1bit là chỉ có 2 mức ON OFF, 2 bit thì sẽ tạo ra 4 mức sáng, n bít thì tạo ra 2 mũ n mức sáng

Với phương pháp điều chế độ rộng xung thông thường việc tạo ra nhiều hơn 5 bit pwm là bất khả thi do số lượng dữ liệu cần bơm vào led matrix là rất lớn, do vậy mình đã giới thiệu phương pháp điều chế mã nhị phân để có thể giảm đi rất nhiều data cần gửi

Thực hành trên KIT Clock STM32F103 và led ma trận FULL P5

Bạn nào không có KIT clock P5 mà mình giới thiệu thì có thể tự mua kit stm32 blue pill rồi nối dây tương tự nhé

STM32F103C8HUB75D
A2R1
A3G1
A4B1
A5R2
A6G2
A7B2
B0CLK
B1A
B2D
B10C
B11OE
B12LAT
B14B

Module led P5 FULL hoạt động tương tự như P10 FULL, chỉ là hệ số quét sẽ là 1/16 chứ không phải 1/8 nữa ( có thêm chân D)

Khởi tạo code với cube mx

Enable thạch anh ngoài trong RCC và chọn tốc độ tối đa 72Mhz nhé

Kích hoạt timer 2 chanel 4 PWM Generation để tạo xung PWM vào chân OE, Cài đặt Perscaler là 0 hoặc 1 để có tần số pwm lớn nhất, Counter Period chính là giải độ sáng lớn nhất của chúng ta, mình để là 400

Tiếp tục bật thêm Timer 4 để phục vụ quét LED, kích hoạt chi phép ngắt, còn 2 thông số Perscaler và Counter Period lát nữa tính toán rồi sửa trong code sau

Viết chương trình

Theo nguyên tắc của B.A.M chúng ta cần 1 mảng lưu giá trị thời gian chênh lệch giữa mỗi lần ngắt quét led, khác với các chip AVR,PIC, dòng stm32 hỗ trợ rất nhiều hệ số chia cho timer nên chúng ta có thể căn thời gian ngắt của timer qua 2 cách :

  • Thay đổi hệ số chia qua thanh ghi PSC
  • Thay đổi giá trị tràn ở thanh ghi ARR

Mình sẽ thay đổi thời gian xảy ra ngắt bằng cách nạp lại hệ số chia vào thanh ghi PSC, do vậy mình sẽ tạo 1 mảng chứa 5 hệ số chia cho 5 bit pwm

Nếu các bạn giảm nhỏ hệ số chia này xuống để thời gian xảy ra ngắt diễn ra nhanh hơn, tần số quét led của led sẽ tăng và khi chiếu camera điện thoại sẽ càng giảm nhấp nháy, nhưng điều đó sẽ làm hao phí thời gian xử lí của vi điều khiển hơn vì phải ngắt quét led nhiều hơn

Đối với led ma trận bị điều khiển bởi pwm, tần số quét để mắt người nhìn ổn là 60Hz, nhưng để camera điện thoại quay không bị nháy thì phải đảm bảo > 1Khz

Bây giờ chúng ta cần 1 bộ đệm để lưu giá trị màu sắc, như đã nói ở trên mình sẽ tạo ra 5bit màu cho mỗi thành phần màu, tức số mà tối đa trên lí thuyết có thể tạo ra được là 2 mũ 5 mũ 3 = 32768 màu. Module led ma trận P5 có độ phân giải 64×32, vậy mình sẽ tạo ra buffer 3 chiều như sau:

Với 64 led chiều ngang và 32 led chiều dọc cùng với 3 thành phần màu RGB, mỗi pixel sẽ chiếm 3byte, mỗi byte tương ứng 1 thành phần màu ( thực ra bắn 5bit pwm nên chỉ có 5 bit có ích trên mỗi byte thôi, mà kệ RAM nhiều mà :v)

Với 5 bit màu và tỉ số scan là 16s, chúng ta cần 5×16 = 80 lần ngắt để quét hết 1 bảng led

Cách quét

Có 2 cách quét bảng led

  • Mỗi khi bật sáng 1 hàng thì chúng ta quét hết 5 bit pwm rồi mới chuyển hàng
  • Chúng ta chuyển hết 16 hàng rồi mới chuyển sang quét bit pwm mới

Cách 1 màu sắc sẽ chuẩn hơn, nhưng khi quay camera sẽ nhấp nháy hơn
Cách 2 quay camera đỡ nháy hơn nhưng màu sắc bị sai đi chút

Ở đây mình dùng cách 1, đi qua hết 5 bit pwm rồi mới chuyển hàng mới

Cách gửi data ra các chân R1 R2 B1 B2 G1 G2

Với các dòng led 1 màu, chỉ có 1 chân data, chúng ta có thể dùng bộ SPI cứng để đẩy data cho nhanh, nhưng với ledd full thì có tận 6 chân data nên không có bộ SPI cứng nào đủ đáp ứng, vì vậy chúng ta phải gửi data bằng cách ghi mức logic vào các chân GPIO.

bài 10 mình ghi data như này

Nếu làm như này thì mỗi lần ngắt truyền thì vi điều khiển phải thực hiện rất nhiều phép tính và phải ghi vào từng chân GPIO rất mất thời gian. Để đẩy nhanh tốc độ ghi data ra thì mình sẽ tính sẵn các dữ liệu đó rồi bỏ vào 1 buffer, khi ngắt xảy ra chỉ cần truyền dữ liệu đã được tính toán sẵn đi thôi. Mình cũng cố tình nối các chân RGB của led matrix vào chung 1 port, đẩy data 1 phát ra cả PORT thì nhanh hơn là ghi từng pin nhiều

Vậy, buff để lưu các dữ liệu này tạm gọi là bufferGPIO

Giải thích: Do 1 lần xuất vào 6 chân data mà 1 byte có 8bit nên cứ 1 byte dữ liệu chỉ có 6bit có ích ( 2byte dư), chiều thứ 1 [5] đại diện cho 5 bit PWM, chiều thứ 2 [16] đại diện cho hệ số scan là 16 và [64] tức chiều ngang của bảng led 64

Chúng ta sẽ cần 1 hàm để chuyển đổi dữ liệu từ dạng RGB sang buffer cho GPIO

Như vậy mỗi lần có vẽ gì lên màn hình thì phải gọi hàm này để update hiển thị

Chương trình chọn hàng được sáng

Mẹo nhỏ: Các bạn không nên quét từ hàng 0 đến hàng 15 mà quét theo thứ tự như này sẽ đỡ nháy hơn 0,8,4,12, 2,10,6,14, 1,9,5,13, 3,11,7,15,

Chương trình ngắt quét led

Nhiệm vụ của chương trình ngắt là bắn data ra theo pwm và chuyển hàng mới ( gọi hàm này trong callback của timer)

Giải thích: Đầu chương trình mình sẽ nạp hệ số chia mới để căn chỉnh pwm, trước khi gửi data LED mình tắt hết led để đảm bảo không bị nhiễu ( hiện tượng bóng ma) sau đó gửi data trong bộ đệm GPIO ra PORT, bật sáng hàng và chốt data, trả độ sáng màn hình về ban đầu,

1 số định nghĩa và khai báo biến

Để căn chỉnh tần số quét, các bạn nạp giá trị phù hợp vào Counter Period của TIM4 ( ngắt quét led). Như trong demo này mình để Period là 40

DEMO hiện ảnh màu 5 bit

Dùng phần mềm chuyển ảnh thành mã hex dạng RGB tại đây

Dùng photoshop hoặc pain cắt bớt ảnh xuống còn 64×32 pixel

Copy dữ liệu đưa vào bô đệm RGB và gọi hàm update để chuyển đổi sang bộ đệm GPIO

 

Từ tác giả:

Nếu có bất kì thắc mắc nào trong bài viết, vui lòng để lại comment dưới mỗi bài ! Mình sẽ không trả lời thắc mắc của các bạn ở facebook hay email !

Nếu trong phần code bạn nhìn thấy nhưng thứ kiểu như &amp; thì đó là lỗi hiển thị, cụ thể 3 kí tự < > & bị biến đổi thành như thế
&amp; là &
&lt;  là <
&gt; là >

Giới thiệu Đào Nguyện 80 bài viết
DIY,chế cháo, viết blog chia sẽ kiến thức về lập trình,điện tử - IoT. Rất mong được giao lưu, kết bạn với các bạn cùng đam mê. Địa chỉ Facebook: https://www.facebook.com/nguyendao207

5 bình luận

  1. Trong hàm update có dòng: if((BufferRGB[1][16+hang] [i] & (1<<ts)) != 0 ){bufferGPIO[bit_pos][hang][i]|=(0x0001<<G2);}, vậy cái "ts" là gì vậy ạ?

    Với lại trong hàm ngatquetled, có lệnh: for(int i=0;iODR=bufferGPIO[vitri_bit][i];clk_P->BSRR=(1<BSRR=(1<<clk);}, vì sao mảng bufferGPIO[][][] có 3 chiều nhưng trong này a chỉ truyền vào 2 chiều thôi ạ?

Đã đóng bình luận.