Ich habe folgenden Arduino:
Dann verwende ich diese Multiplexer:
Pullups-Widerstände auf dem I2C Bus: keine Ahnung was das bedeutet. Ich habe nichts angepasst oder geändert.
Klar könnt ihr gern den Sketch sehen:
#include "Wire.h"
#include <U8glib.h>
#include "glyphs.h"
#include "LinkedList.h"
#define DISP_COUNT 11
typedef struct _DISP {
uint8_t id; // arbitrary numeric ID of display
uint8_t MUXAddress; // TCA9548A MUX address to which display is conneted
uint8_t I2CChannel; // i2c channel of display
byte g; // Integer value for Glyph loop
} DISP;
typedef struct _TASK {
uint8_t displayId;
uint8_t glyphNum;
unsigned long startedAt;
unsigned long startAt;
unsigned long finishAt;
} TASK;
LinkedList<TASK*> tasksList = LinkedList<TASK*>();
DISP displays[DISP_COUNT];
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_FAST); // Fast I2C / TWI
U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_FAST);
#define GLYPH_WIDTH 128
#define GLYPH_HEIGHT 64
// Array of Glyphs to show
unsigned char* glyphs[] = {glyph1, glyph2, glyph3};
const int glyphCount = 3;
void drawGlyph(uint8_t ind) {
if(ind > glyphCount) return;
u8g.firstPage();
do {
u8g.drawBitmapP( 0, 0, 16, 64, glyphs[ind]);
} while( u8g.nextPage() );
//u8g.drawXBMP(0, 0, 128, 64, glyphs[ind]);
}
// Disable all i2c channels
void disableMUX(uint8_t MUXAddress) {
Wire.beginTransmission(MUXAddress);
Wire.write(0);
Wire.endTransmission();
}
// Initialize I2C buses using TCA9548A I2C Multiplexer
/**
* _display - used to get DISP pointer in return. If it is not needed, set this param to NULL
*/
boolean tcaselect(uint8_t displayId, DISP** _display) {
if(displayId == 0)
return false;
// Stop propagating i2c stream to displays
disableMUX(0x70);
disableMUX(0x72);
for(int i=0; i<DISP_COUNT; i++) {
if(displays[i].id == displayId) {
if(_display != NULL)
*_display = &displays[i];
Wire.beginTransmission(displays[i].MUXAddress);
Wire.write(1 << displays[i].I2CChannel);
Wire.endTransmission();
return true;
}
}
return false;
}
// Get DISP pointer by device ID
DISP* getDisp(uint8_t displayId) {
if(displayId == 0)
return NULL;
for(int i=0; i<DISP_COUNT; i++) {
if(displays[i].id == displayId) {
return &displays[displayId];
}
}
return NULL;
}
void setup() {
Serial.begin(115200);
DisplayInit(); // Initialize the displays
Serial.println(String("Data Size check: ") + sizeof(unsigned long));
}
// Add new display to 'displays' array
/**
* index - array index [0 .. DISP_COUNT]
* id - any numeric value
* MUXAddress - TCA9548A i2c address
* I2CChannel - channel for display [0 .. 7]
*/
void addDisplay(uint8_t index, uint8_t id, uint8_t MUXAddress, uint8_t I2CChannel) {
displays[index].id = id;
displays[index].MUXAddress = MUXAddress;
displays[index].I2CChannel = I2CChannel;
}
// Initialize the displays
void DisplayInit() {
memset(&displays, 0, sizeof(displays));
addDisplay(0, 101, 0x70, 0);
addDisplay(1, 102, 0x70, 1);
addDisplay(2, 103, 0x70, 2);
addDisplay(3, 104, 0x70, 3);
addDisplay(4, 105, 0x70, 4);
addDisplay(5, 106, 0x70, 5);
addDisplay(6, 107, 0x70, 6);
addDisplay(7, 108, 0x70, 7);
addDisplay(8, 109, 0x72, 0);
addDisplay(9, 110, 0x72, 1);
addDisplay(10, 111, 0x72, 2);
//addDisplay(11, 112, 0x72, 4);
int initCount = 0;
for(int i=0; i<DISP_COUNT; i++) {
if(tcaselect(displays[i].id, NULL)) {
u8g.firstPage();
do {
u8g.begin(); // Initialize display
} while( u8g.nextPage() );
initCount++;
}
}
Serial.print("Displays init: OK (");
Serial.print(initCount);
Serial.println(")");
}
void clearDisplay(){
u8g.firstPage();
do {
} while( u8g.nextPage() );
}
/**
* Add display task to list
*
* displayId - id of display, i.e. 100, 200,..
* glyphNum - index of Glyph in glyphs[] array
* startIn - time should pass before start showing glyph(in milliseconds), i.e. 1000 - start showing in 1 second
* duration - thime to show glyph(in milliseconds), display will be cleared after it pass
*/
void addTask(uint8_t displayId, uint8_t glyphNum, uint16_t startIn, uint16_t duration) {
TASK* task = (TASK*)malloc(sizeof(TASK));
memset(task, 0, sizeof(TASK));
task->displayId = displayId;
task->glyphNum = glyphNum;
task->startAt = startIn + millis();
task->finishAt = task->startAt + duration;
//Serial.println("ADD TASK");
//Serial.println(String("displayId:") + task->displayId);
//Serial.println(String("glyphNum:") + task->glyphNum);
//Serial.println(String("startAt:") + task->startAt);
//Serial.println(String("finishAt:") + task->finishAt);
//Serial.println("--------");
tasksList.add(task);
}
/**
* Go through tasks list, execute tasks and remove finished from list
*/
void loopTasks() {
unsigned long currentTime = millis();
for(int i=0; i<tasksList.size(); i++) {
TASK* task = tasksList.get(i);
if(task->startAt <= currentTime && task->startedAt == 0) {
task->startedAt = currentTime;
// TODO display action
if(tcaselect(task->displayId, NULL)) {
drawGlyph(task->glyphNum);
} else {
// display not found. Maybe it is mistake. Removing from tasks list
// removing from tasks list
TASK* t = tasksList.remove(i);
free(t);
i--;
}
} else if(task->startedAt != 0 && task->finishAt <= currentTime) {
if(tcaselect(task->displayId, NULL)) {
clearDisplay();
}
// removing from tasks list
TASK* t = tasksList.remove(i);
free(t);
i--;
}
}
}
void fillDemoTasks() {
addTask(101, 0, 0, 5000);
addTask(102, 0, 0, 5000);
addTask(103, 0, 0, 5000);
addTask(104, 0, 0, 5000);
addTask(105, 0, 0, 5000);
addTask(106, 0, 0, 5000);
addTask(107, 0, 0, 5000);
addTask(108, 0, 0, 5000);
addTask(109, 0, 1000, 5000);
addTask(110, 0, 1000, 5000);
addTask(111, 0, 1000, 5000);
//addTask(112, 0, 1000, 5000);
}
void setupTasks() {
}
void loop() {
loopTasks();
if(tasksList.size() == 0) {
delay(2000);
fillDemoTasks();
}
setupTasks();
}
Die Displays werden ab Zeile 117 “angemeldet” und die Aufgaben (also was welches Display wann wie lang zeigt), wird ab Zeile 219 eingestellt.
Zusätzlich muss ich die aktuelle Anzahl der Displays noch in Zeile 6 definieren.