Étape 5: Écrire le code
Tout d’abord, vous devez la Bibliothèque Aduino TLC5940. Les instructions d’installation sont obsolètes. Télécharger la bibliothèque et le décompresser dans un répertoire temporaire. Ouvrez l’éditeur de l’Arduino et aller à Esquisse -> Bibliothèque d’importation et ajout de la bibliothèque. L’éditeur fera le reste.
Modifiez le fichier tlc_config.h pour modifier le nombre de TLC5940 vous utilisez. Ce projet va te TLCs afin que la ligne est
#define NUM_TLCS 3
Le code est assez simple d’ici et est commenté. J’ai aussi quelques commentaires à la fin.
LEDController.ino
#include "Arduino.h" #include <Tlc5940.h> #include <tlc_config.h> #include "LedController.h" // Root List for all LEDs List *lightList = NULL; // various values for iterating through the RGBs int rgbIndex = 0; int rgbLastStart = 0; boolean firstRGBIndex; int maxRGB = 252; // Handy for steping through all the LEDs // Each LED will flash, which helps find missing or incorrect connections void diag() { for(uint8_t x= 0; x < 40; x++) { if ( x > 0) { Tlc.set(x-1,0); } Tlc.set(x,1000); while(Tlc.update()); delay(500); } } /* Pause for 5 seconds so that you can pull up any diagnostic you may need. Initialize the TLC chain. Create the complete light list */ void setup() { delay(5000); Tlc.init(); Tlc.clear(); lightList = createList(); addNode(lightList, createRGBCluster1()); addNode(lightList, createLEDCluster1a()); addNode(lightList, createLEDCluster2()); } /* Increment the RGB value so it slowly moves through the list of color transitions. Keep the current time so you know when to turn on and off lights. Run through the list. */ void loop() { //diag(); rgbIndex = rgbLastStart + 1; firstRGBIndex = true; long time = millis(); iterateList(time,lightList); /* The update finishes asynchronously on the TLC's. You must wait till everything updates or your lights will display incorrect values. */ while(Tlc.update()); } /* Single link list. Most of the following functions create a node of some type and attach it to the end of a list. This system creates lists of lists for each LED array. This exposed some memory challenges as the list is using some statically allocated values and shares some of those values. Pointers would have been a wiser choice. */ List* createList(void) { List *list = (List*)malloc(sizeof(List)); list->head = NULL; list->tail = NULL; return list; } List* addNode(List* list, Node* node) { if (list != NULL && node != NULL) { if (list->head == NULL) { list->head = node; list->tail = list->head; } else { list->tail->next = node; list->tail = node; } } } Node* createNode(NodeType type, uint8_t pin) { Node *result = (Node*)malloc(sizeof(Node)); result->next = NULL; result->type = type; switch(type) { case LIST: result->value = createList(); break; case LED_RGB: result->value = createRGB(pin); break; case LED_NORMAL: result->value = createLED(pin); break; } return result; } Node* createRGBNode(List* list, uint8_t pin, Runtimes runtimes, RGB *useSettings) { Node *results = createNode(LED_RGB, pin); RGB* rgb = (RGB*)results->value; configureRGB(rgb, runtimes, useSettings); addNode(list, results); return results; } void configureRGB(RGB* rgb, Runtimes runtimes, RGB *useSettings) { if ( useSettings != NULL) { rgb->useSettings = useSettings; rgb->color = useSettings->color; rgb->runtimes = useSettings->runtimes; } else { rgb->runtimes = runtimes; } } RGB* createRGB(uint8_t pin) { RGB *result = (RGB*)malloc(sizeof(RGB)); result->pin = pin; result->color.r = 0; result->color.g = 0; result->color.b = 0; result->useSettings = NULL; return result; } Node* createLEDNode(List* list, uint8_t pin, Runtimes runtimes, uint8_t level) { Node *results = createNode(LED_NORMAL, pin); LED* led = (LED*)results->value; led->level = level; led->runtimes = runtimes; addNode(list, results); return results; } LED* createLED(uint8_t pin) { LED *result = (LED*)malloc(sizeof(LED)); result->pin = pin; result->level=0; result->runtimes.startTime=0; result->runtimes.runTime=0; result->runtimes.on=false; return result; } void setRGBLed(RGB *led) { Tlc.set(led->pin,led->color.r); Tlc.set(led->pin+1,led->color.g); Tlc.set(led->pin+2,led->color.b); } /* iterate through the list and determine the correct way to execute each node. */ void iterateList(long time, List* list) { if(list != NULL) { Node* node = list->head; while(node != NULL) { executeNode(time, node); node = node->next; } } } void executeNode(long time, Node* node) { if(node != NULL) { switch(node->type) { case LIST: iterateList(time, (List*)node->value); break; case LED_RGB: setRGB(time,(RGB*)node->value); break; case LED_NORMAL: setLED(time,(LED*)node->value); break; default: Tlc.set(1,200); Tlc.update(); break; } } else { } } /* Horrible cheating going on here. There is only one RGB list so we're going to keep some extra state and apply it to just this rgb list. blech. However, this array runs much faster by iterating through precalculated values than trying to calculate and display those values. */ void setRGB(long time, RGB* rgb) { if (rgb != NULL) { boolean cycle = time > rgb->runtimes.startTime + rgb->runtimes.wait; if ( cycle ) { if ( rgb->useSettings != NULL ) { rgb->color = rgb->useSettings->color; rgb->runtimes = rgb->useSettings->runtimes; } else { if ( firstRGBIndex ) { firstRGBIndex = false; rgbLastStart++; if ( rgbLastStart > maxRGB) { rgbLastStart = 0; } rgbIndex = rgbLastStart; } rgb->color = rgbPattern[rgbIndex++]; if ( rgbIndex > maxRGB) { rgbIndex = 0; } } rgb->runtimes.startTime = time; } setRGBLed(rgb); } } void setLED(long time, LED* led) { if (led != NULL) { long execWindow = led->runtimes.startTime + led->runtimes.runTime; if(led->runtimes.runTime == -1 || (time > led->runtimes.startTime && time < execWindow)) { led->runtimes.on = true; Tlc.set(led->pin, led->level); } else if ( time > execWindow && led->runtimes.on == true ) { led->runtimes.startTime = time + led->runtimes.wait; led->runtimes.on = false; Tlc.set(led->pin, 0); } } } /* The various LED array factory methods */ Node* createRGBCluster1(void) { int i = 0; int wait = 50; Runtimes rt = (Runtimes) { 0, 0, wait, false }; Node* rgbList = createNode(LIST, 0); List* rgbCluster1 = (List*)rgbList->value; Node* a = createRGBNode( rgbCluster1, i, rt, NULL); Node* b = createRGBNode( rgbCluster1, i+=3, rt, NULL); Node* c = createRGBNode( rgbCluster1, i+=3, rt, NULL); Node* d = createRGBNode( rgbCluster1, i+=3, rt, NULL); Node* e = createRGBNode( rgbCluster1, i+=3, rt, NULL); // Let them share values which creates a kind of cool looking // fountain effect. createRGBNode( rgbCluster1, i+=3, rt, (RGB*)e->value); createRGBNode( rgbCluster1, i+=3, rt, (RGB*)d->value); createRGBNode( rgbCluster1, i+=3, rt, (RGB*)c->value); createRGBNode( rgbCluster1, i+=3, rt, (RGB*)b->value); createRGBNode( rgbCluster1, i+=3, rt, (RGB*)a->value); return rgbList; } Node* createLEDCluster1a(void) { int i = 30; Node* ledList = createNode(LIST, 0); List* ledCluster = (List*)ledList->value; createLEDNode( ledCluster, i++, (Runtimes) { -1, -1, -1, true }, 300); createLEDNode( ledCluster, i++, (Runtimes) { -1, -1, -1, true }, 300); createLEDNode( ledCluster, i++, (Runtimes) { -1, -1, -1, true }, 300); createLEDNode( ledCluster, i++, (Runtimes) { -1, -1, -1, true }, 300); createLEDNode( ledCluster, i++, (Runtimes) { -1, -1, -1, true }, 300); createLEDNode( ledCluster, i++, (Runtimes) { -1, -1, -1, true }, 300); return ledList; } Node* createLEDCluster2(void) { int i = 36; Node* ledList = createNode(LIST, 0); List* ledCluster = (List*)ledList->value; createLEDNode( ledCluster, i++, (Runtimes) { 10000, 30000, 25000, true }, 3000); createLEDNode( ledCluster, i++, (Runtimes) { 10000, 30000, 25000, true }, 3000); createLEDNode( ledCluster, i++, (Runtimes) { 3000, 90000, 45000, true }, 3000); createLEDNode( ledCluster, i++, (Runtimes) { 3000, 90000, 45000, true }, 3000); return ledList; } /* This is some old code that did the sine wave calculation. It works but is very slow. I wrote some code to capture the values and write them out the serial console instead and then copied the values into the header void setRGBFreq(RGB *led, uint8_t i, uint8_t max) { float frequency = .3; led->r = sin(frequency*(i) + 0) * 127 + 128; led->g = sin(frequency*(i) + 2) * 127 + 128; led->b = sin(frequency*(i) + 4) * 127 + 128; uint8_t total = led->r + led->g + led->b; if ( total > max ) { led->r -= led->r/total * 100.0; led->g -= led->g/total * 100.0; led->b -= led->b/total * 100.0; } //printList(led); }*/
LEDController.h
<code> #ifndef LEDController #define LEDController #define RGB_LEDS 10 typedef enum { LIST, LED_RGB, LED_NORMAL } NodeType; typedef struct { long startTime; long runTime; long wait; boolean on; } Runtimes; typedef struct { uint8_t r; uint8_t g; uint8_t b; } Colors; typedef struct rgb { Colors color; uint8_t pin; Runtimes runtimes; struct rgb *useSettings; } RGB; typedef struct { uint8_t pin; uint8_t level; Runtimes runtimes; } LED; typedef struct node { NodeType type; void* value; struct node* next; } Node; typedef struct { Node* head; Node* tail; } List; static Colors rgbPattern[] = { {128, 243, 31},{165, 222, 11},{199, 193, 1},{227, 158, 3}, {246, 120, 15},{254, 83, 38},{251, 50, 68},{237, 24, 104}, {213, 7, 142},{182, 1, 179},{145, 6, 211},{107, 22, 236}, {71, 47, 250},{40, 80, 254},{17, 117, 247},{3, 155, 229}, {1, 190, 202},{10, 220, 168},{29, 242, 131},{58, 253, 93}, {92, 253, 58},{130, 242, 30},{167, 221, 10},{201, 191, 1}, {228, 156, 3},{247, 118, 16},{254, 81, 39},{251, 48, 70}, {236, 22, 106},{212, 6, 144},{180, 1, 181},{143, 6, 213}, {105, 23, 237},{69, 49, 251},{39, 82, 254},{16, 119, 246}, {3, 157, 228},{1, 192, 200},{11, 222, 166},{31, 243, 129}, {59, 253, 91},{94, 253, 57},{132, 241, 29},{169, 219, 10}, {203, 189, 1},{230, 154, 4},{247, 116, 17},{254, 79, 41}, {250, 46, 72},{235, 21, 109},{210, 5, 147},{178, 1, 183}, {141, 7, 214},{103, 24, 238},{68, 51, 251},{37, 84, 254}, {15, 121, 245},{3, 159, 226},{1, 194, 198},{12, 223, 164}, {32, 243, 126},{61, 254, 89},{96, 252, 55},{134, 240, 27}, {171, 218, 9},{204, 187, 1},{231, 152, 4},{248, 114, 18}, {254, 77, 43},{250, 45, 74},{234, 20, 111},{208, 5, 149}, {176, 1, 185},{139, 8, 216},{101, 25, 239},{66, 52, 252}, {36, 86, 254},{14, 123, 245},{2, 161, 225},{2, 196, 196}, {12, 224, 162},{34, 244, 124},{63, 254, 87},{98, 252, 53}, {136, 239, 26},{173, 216, 8},{206, 186, 1},{232, 150, 5}, {249, 112, 20},{254, 75, 44},{249, 43, 76},{233, 19, 113}, {207, 4, 151},{174, 1, 187},{137, 8, 217},{99, 27, 240}, {64, 54, 252},{34, 88, 254},{13, 125, 244},{2, 163, 224}, {2, 198, 195},{13, 226, 160},{35, 245, 122},{65, 254, 85}, {100, 252, 51},{138, 238, 25},{175, 215, 7},{208, 184, 1}, {233, 147, 5},{249, 109, 21},{254, 73, 46},{248, 42, 78}, {231, 18, 115},{205, 4, 153},{172, 1, 188},{135, 9, 219}, {97, 28, 241},{62, 56, 253},{33, 90, 253},{12, 128, 243}, {2, 165, 222},{2, 199, 193},{14, 227, 158},{36, 246, 120}, {67, 254, 83},{102, 251, 50},{140, 237, 24},{177, 213, 7}, {128, 243, 31},{165, 222, 11},{199, 193, 1},{227, 158, 3}, {246, 120, 15},{254, 83, 38},{251, 50, 68},{237, 24, 104}, {213, 7, 142},{182, 1, 179},{145, 6, 211},{107, 22, 236}, {71, 47, 250},{40, 80, 254},{17, 117, 247},{3, 155, 229}, {1, 190, 202},{10, 220, 168},{29, 242, 131},{58, 253, 93}, {92, 253, 58},{130, 242, 30},{167, 221, 10},{201, 191, 1}, {228, 156, 3},{247, 118, 16},{254, 81, 39},{251, 48, 70}, {236, 22, 106},{212, 6, 144},{180, 1, 181},{143, 6, 213}, {105, 23, 237},{69, 49, 251},{39, 82, 254},{16, 119, 246}, {3, 157, 228},{1, 192, 200},{11, 222, 166},{31, 243, 129}, {59, 253, 91},{94, 253, 57},{132, 241, 29},{169, 219, 10}, {203, 189, 1},{230, 154, 4},{247, 116, 17},{254, 79, 41}, {250, 46, 72},{235, 21, 109},{210, 5, 147},{178, 1, 183}, {141, 7, 214},{103, 24, 238},{68, 51, 251},{37, 84, 254}, {15, 121, 245},{3, 159, 226},{1, 194, 198},{12, 223, 164}, {32, 243, 126},{61, 254, 89},{96, 252, 55},{134, 240, 27}, {171, 218, 9},{204, 187, 1},{231, 152, 4},{248, 114, 18}, {254, 77, 43},{250, 45, 74},{234, 20, 111},{208, 5, 149}, {176, 1, 185},{139, 8, 216},{101, 25, 239},{66, 52, 252}, {36, 86, 254},{14, 123, 245},{2, 161, 225},{2, 196, 196}, {12, 224, 162},{34, 244, 124},{63, 254, 87},{98, 252, 53}, {136, 239, 26},{173, 216, 8},{206, 186, 1},{232, 150, 5}, {249, 112, 20},{254, 75, 44},{249, 43, 76},{233, 19, 113}, {207, 4, 151},{174, 1, 187},{137, 8, 217},{99, 27, 240}, {64, 54, 252},{34, 88, 254},{13, 125, 244},{2, 163, 224}, {2, 198, 195},{13, 226, 160},{35, 245, 122},{65, 254, 85}, {100, 252, 51},{138, 238, 25},{175, 215, 7},{208, 184, 1}, {233, 147, 5},{249, 109, 21},{254, 73, 46},{248, 42, 78}, {231, 18, 115},{205, 4, 153},{172, 1, 188},{135, 9, 219}, {97, 28, 241},{62, 56, 253},{33, 90, 253},{12, 128, 243}, {2, 165, 222},{2, 199, 193},{14, 227, 158},{36, 246, 120}, {67, 254, 83},{102, 251, 50},{140, 237, 24},{177, 213, 7} }; // Basic Double Linked-List functions for LEDs List* createList(void); List* addNode(List* list, Node* node); Node* createNode(NodeType type, uint8_t pin); RGB* createRGB(uint8_t pin); LED* createLED(uint8_t pin); Node* createRGB(List* list, uint8_t pin, Runtimes runtimes, RGB *useSettings); Node* createLEDNode(uint8_t pin, Runtimes runTimes, uint8_t level); void iterateList(long time, List* list); void setRGBLED(long time, RGB *led); void setLED(long time, LED* led); //Cluster factories Node* createRGBCluster1(void); Node* createRGBCluster1a(void); Node* createLEDCluster2(void); void configureRGB(RGB* rgb, Runtimes runtimes, RGB *useSettings); #endif
Le code utilise un plusieurs listes liées unique pour gérer toutes les LEDs, leurs couleurs, luminosité, durées et autres paramètres. À l’aide d’une liste chaînée est une erreur et j’ai gérerait la mémoire d’une manière différente. Pourquoi ? Le rgbPattern alloué statiquement utilise beaucoup de mémoire, mais toute la mémoire est contigue. Les listes liées ne sont pas contiguës par intention, plutôt par hasard. Le résultat est que vous pouvez avoir des petits blocs de mémoire alloués pour chaque nœud dans la liste. L’allocateur saisira le premier bloc de mémoire qui peut se loger dans le nœud. Il en résulte l’allocateur laissant de larges vides mémoire partielle entre les listes et les nœuds. Ces lacunes ne sont souvent pas utilisables et l’application peut ne plus allouer la quantité maximale de mémoire.
Manquer de mémoire est un peu bizarre : l’Arduino redémarre. Vous attendez quelques secondes et ensuite regarder redémarrer encore et encore, et vous voyez l’idée. J’ai écrit une fonction rapide, non incluse dans le code, qui écrirait un nombre de bits avec un intervalle défini pour un code pin pour me donner une idée jusqu’où l’application a obtenu. J’ai accroché un oscilloscope sur la broche et regardé les bits. Sachant que j’ai redémarrer, a été le premier tour. L’écrivain de la broche a écrit six bits à l’intérieur de la fonction setup() et puis écrira cinq bits dans la fonction loop(). Les cinq bits n’étaient jamais affichés. Juste les six bits toutes 15 ou si les secondes.
C’est alors qu’une question de jouer avec quelques petites choses. J’ai découvert que commentant la valeur du bâtiment de LEDs permettre l’avancement de l’application à la loop() et continuer à s’exécuter. J’ai réduit le nombre de couleurs du rgbPattern pédalé à travers et puis décommenté le bâtiment. L’exécution de l’application normalement à nouveau.
Chaque objet de couleur est seulement de 24 octets, pourtant il y a 64 lignes avec 4 objets de couleur chaque. Un peu plus de 6k dépensés sur la rotation de couleur.
La prochaine chose aurait été d’allouer un tableau simple pour tous les nœuds. Puis il aurait été un bloc de mémoire emballés pour tous les LEDs et libérées de beaucoup plus de mémoire pour le reste de l’application.
Toutefois, la solution plus susceptible de travailler pour un plus grand réseau de LED est un damier avec davantage de mémoire. Un méga serait de gérer facilement un grand nombre de bâtiments.