Files
2024-07-20 22:09:06 +08:00

266 lines
7.0 KiB
C++

/******************************************************************
A library for controling a set of 8x8 LEDs with a MAX7219 or
MAX7221 displays.
This is a plugin for Adafruit's core graphics library, providing
basic graphics primitives (points, lines, circles, etc.).
You need to download and install Adafruit_GFX to use this library.
Adafruit invests time and resources providing this open
source code, please support Adafruit and open-source hardware
by purchasing products from Adafruit!
Written by Mark Ruys.
BSD license, check license.txt for more information.
All text above must be included in any redistribution.
******************************************************************/
#include <Adafruit_GFX.h>
#include "Max72xxPanel.h"
#include <SPI.h>
// The opcodes for the MAX7221 and MAX7219
#define OP_NOOP 0
#define OP_DIGIT0 1
#define OP_DIGIT1 2
#define OP_DIGIT2 3
#define OP_DIGIT3 4
#define OP_DIGIT4 5
#define OP_DIGIT5 6
#define OP_DIGIT6 7
#define OP_DIGIT7 8
#define OP_DECODEMODE 9
#define OP_INTENSITY 10
#define OP_SCANLIMIT 11
#define OP_SHUTDOWN 12
#define OP_DISPLAYTEST 15
Max72xxPanel::Max72xxPanel(byte csPin, byte hDisplays, byte vDisplays) : Adafruit_GFX(hDisplays << 3, vDisplays << 3) {
Max72xxPanel::SPI_CS = csPin;
byte displays = hDisplays * vDisplays;
Max72xxPanel::hDisplays = hDisplays;
Max72xxPanel::bitmapSize = displays << 3;
Max72xxPanel::bitmap = (byte*)malloc(bitmapSize);
Max72xxPanel::matrixRotation = (byte*)malloc(displays);
Max72xxPanel::matrixPosition = (byte*)malloc(displays);
for ( byte display = 0; display < displays; display++ ) {
matrixPosition[display] = display;
matrixRotation[display] = 0;
}
SPI.begin();
//SPI.setBitOrder(MSBFIRST);
//SPI.setDataMode(SPI_MODE0);
pinMode(SPI_CS, OUTPUT);
// Clear the screen
fillScreen(0);
// Make sure we are not in test mode
spiTransfer(OP_DISPLAYTEST, 0);
// We need the multiplexer to scan all segments
spiTransfer(OP_SCANLIMIT, 7);
// We don't want the multiplexer to decode segments for us
spiTransfer(OP_DECODEMODE, 0);
// Enable display
shutdown(false);
// Set the brightness to a medium value
setIntensity(7);
}
void Max72xxPanel::setPosition(byte display, byte x, byte y) {
matrixPosition[x + hDisplays * y] = display;
}
void Max72xxPanel::setRotation(byte display, byte rotation) {
matrixRotation[display] = rotation;
}
void Max72xxPanel::setRotation(uint8_t rotation) {
Adafruit_GFX::setRotation(rotation);
}
void Max72xxPanel::shutdown(boolean b) {
spiTransfer(OP_SHUTDOWN, b ? 0 : 1);
}
void Max72xxPanel::setIntensity(byte intensity) {
spiTransfer(OP_INTENSITY, intensity);
}
void Max72xxPanel::fillScreen(uint16_t color) {
memset(bitmap, color ? 0xff : 0, bitmapSize);
}
void Max72xxPanel::drawPixel(int16_t xx, int16_t yy, uint16_t color) {
// Operating in bytes is faster and takes less code to run. We don't
// need values above 200, so switch from 16 bit ints to 8 bit unsigned
// ints (bytes).
// Keep xx as int16_t so fix 16 panel limit
int16_t x = xx;
byte y = yy;
byte tmp;
if ( rotation ) {
// Implement Adafruit's rotation.
if ( rotation >= 2 ) { // rotation == 2 || rotation == 3
x = _width - 1 - x;
}
if ( rotation == 1 || rotation == 2 ) { // rotation == 1 || rotation == 2
y = _height - 1 - y;
}
if ( rotation & 1 ) { // rotation == 1 || rotation == 3
tmp = x; x = y; y = tmp;
}
}
if ( x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT ) {
// Ignore pixels outside the canvas.
return;
}
// Translate the x, y coordinate according to the layout of the
// displays. They can be ordered and rotated (0, 90, 180, 270).
byte display = matrixPosition[(x >> 3) + hDisplays * (y >> 3)];
x &= 0b111;
y &= 0b111;
byte r = matrixRotation[display];
if ( r >= 2 ) { // 180 or 270 degrees
x = 7 - x;
}
if ( r == 1 || r == 2 ) { // 90 or 180 degrees
y = 7 - y;
}
if ( r & 1 ) { // 90 or 270 degrees
tmp = x; x = y; y = tmp;
}
byte d = display / hDisplays;
x += (display - d * hDisplays) << 3; // x += (display % hDisplays) * 8
y += d << 3; // y += (display / hDisplays) * 8
// Update the color bit in our bitmap buffer.
byte *ptr = bitmap + x + WIDTH * (y >> 3);
byte val = 1 << (y & 0b111);
if ( color ) {
*ptr |= val;
}
else {
*ptr &= ~val;
}
}
void Max72xxPanel::write() {
// Send the bitmap buffer to the displays.
for ( byte row = OP_DIGIT7; row >= OP_DIGIT0; row-- ) {
spiTransfer(row);
}
}
void Max72xxPanel::spiTransfer(byte opcode, byte data) {
// If opcode > OP_DIGIT7, send the opcode and data to all displays.
// If opcode <= OP_DIGIT7, display the column with data in our buffer for all displays.
// We do not support (nor need) to use the OP_NOOP opcode.
// Enable the line
digitalWrite(SPI_CS, LOW);
// Now shift out the data, two bytes per display. The first byte is the opcode,
// the second byte the data.
byte end = opcode - OP_DIGIT0;
byte start = bitmapSize + end;
do {
start -= 8;
SPI.transfer(opcode);
SPI.transfer(opcode <= OP_DIGIT7 ? bitmap[start] : data);
}
while ( start > end );
// Latch the data onto the display(s)
digitalWrite(SPI_CS, HIGH);
}
void Max72xxPanel::scrollMessage(String msg,int displayScrollSpeed) {//滚动显示文本
msg += "";
int refresh=1;
for ( int i = 0 ; i < 6 * msg.length() + WIDTH- 2; i++ ) {
if (refresh == 1)
i = 0;
refresh = 0;
fillScreen(0);
int letter = i / 6;
int x = (WIDTH - 1) - i % 6;
int y = (HEIGHT- 8) / 2; // center the text vertically
while ( x + 6 - 1 >= 0 && letter >= 0 ) {
if ( letter < msg.length() ) {
drawChar(x, y, msg[letter], HIGH, LOW, 1);
}
letter--;
x -= 6;
}
write();
delay(displayScrollSpeed);
}
//matrix.setCursor(0, 0);
}
void Max72xxPanel::scrollMessage(int num,int displayScrollSpeed) {//滚动显示整数
String msg = String("") + num;
msg += "";
int refresh=1;
for ( int i = 0 ; i < 6 * msg.length() + WIDTH- 2; i++ ) {
if (refresh == 1)
i = 0;
refresh = 0;
fillScreen(0);
int letter = i / 6;
int x = (WIDTH - 1) - i % 6;
int y = (HEIGHT- 8) / 2; // center the text vertically
while ( x + 6 - 1 >= 0 && letter >= 0 ) {
if ( letter < msg.length() ) {
drawChar(x, y, msg[letter], HIGH, LOW, 1);
}
letter--;
x -= 6;
}
write();
delay(displayScrollSpeed);
}
//matrix.setCursor(0, 0);
}
void Max72xxPanel::scrollMessage(float num,int displayScrollSpeed) {//滚动显示小数
String msg = String("") + num;
msg += "";
int refresh=1;
for ( int i = 0 ; i < 6 * msg.length() + WIDTH- 2; i++ ) {
if (refresh == 1)
i = 0;
refresh = 0;
fillScreen(0);
int letter = i / 6;
int x = (WIDTH - 1) - i % 6;
int y = (HEIGHT- 8) / 2; // center the text vertically
while ( x + 6 - 1 >= 0 && letter >= 0 ) {
if ( letter < msg.length() ) {
drawChar(x, y, msg[letter], HIGH, LOW, 1);
}
letter--;
x -= 6;
}
write();
delay(displayScrollSpeed);
}
//matrix.setCursor(0, 0);
}