Ovládání RGB LED - připomínky k programu začátečníka

Zdravím.

Začínám se pomalu učit C na mikrokontrolérech AVR. Po pár pokusech s ledkami a “Hello World” na LCD jsem si pohrál se změnou barev RGB LEDky. Dalo by se tomu nadneseně říkat “můj první program”. Co na to říkáte? Jistě by se to dalo nějak optimalizovat, tak prosím klidně poučte začátečníka :blush:

Použil jsem Atmegu 16, anody jsem připojil na piny portu A takto: 4,5 - modrá, 6 - zelená, 7 - červená. Krystal běží na 16 MHz.

Definoval jsem tyto proměnné.

char to_red=0x01; // priznak cervene - 0=inkrementace, 1= po inkrementaci, 2= dekerementace, 3= po dekrementaci char to_green=0x03; // priznak zelene char to_blue=0x02; // priznak modre int tmp_red=0xFF; // toto pricti k cervene int tmp_green=0x00; // toto pricti k zelene int tmp_blue=0xFF; // toto pricti k modre int cnt_red=0; // citac cervene int cnt_green=0; // citac zelene int cnt_blue=0; // citac modre unsigned int cnt_pgm=0; //citac cyklu

Pro řízení barev jsem vycházel z následujícího: Použil jsem 8 bitový model RGB, kde má každá složka intenzitu 0 - 255. Požadovanou intenzitu barvy zapisuji do proměnné tmp_color. Tuto proměnnou přičítám k cnt_color a potom, co přesáhne hodnotu 255 nastavím příslušný bit portu na 1 (ledka svítí). V dalším cyklu nastavím bit opět na nulu.

Barvy chci měnit napříč spektrem postupně od červené k zelené, modré a zpět k červené.

// Vlastni rizeni casu svitu. Kazda barva sviti v rozmezi 1 - 255 cyklu { cnt_red=cnt_red + tmp_red; // citani cervene if (cnt_red >=255) {PORTA=PORTA |0b10000000; cnt_red=0; } else {PORTA=PORTA &0b01111111; }; cnt_green=cnt_green + tmp_green; // citani zelene if (cnt_green >=255) {PORTA=PORTA |0b01000000; cnt_green=0; } else {PORTA=PORTA &0b10111111; }; cnt_blue=cnt_blue + tmp_blue; // citani modre if (cnt_blue >=255) {PORTA=PORTA |0b00110000; cnt_blue=0; } else {PORTA=PORTA &0b11001111; };

Zde si nastavuji příznaky, aby se mi barvy měnily postupně tak, jak jsem si určil.

[code] /* Výchozí barvou je po zapnutí je purpurová. Barvy se mění postupně takto:
1. krok - dekrementace modre
2. krok - inkrementace zelene
3. krok - dekrementace cervene
4. krok - inkrementace modre
5. krok - dekrementace zelene
6. krok - inkrementace cervene

Nastaveni priznaku: 0=inkrementace, 1= po inkrementaci, 2= dekerementace, 3= po dekrementaci
*/

   // cervena
    if (to_red == 0 && tmp_red >=255) { // barva inkrementovala na vrchol
        to_red = 1;                     // nastav priznak barva po inkrementaci
        to_blue = 2;                    // dekrementuj predchozi barvu
        };
    if (to_red == 2 && tmp_red <=0) {   // barva dekrementovala na dno
        to_red = 3;                     // nastav priznak barva po dekrementaci
        to_blue = 0;                    // inkrementuj dalsi barvu
        }; 
          
  //zelena              
    if (to_green == 0 && tmp_green >=255) { // barva inkrementovala na vrchol
        to_green = 1;                     // nastav priznak barva po inkrementaci
        to_red = 2;                    // dekrementuj predchozi barvu
        };
    if (to_green == 2 && tmp_green <=0) {   // barva dekrementovala na dno
        to_green = 3;                     // nastav priznak barva po dekrementaci
        to_red = 0;                    // inkrementuj dalsi barvu
        };
          
  //modra        
    if (to_blue == 0 && tmp_blue >=255) { // barva inkrementovala na vrchol
        to_blue = 1;                     // nastav priznak barva po inkrementaci
        to_green = 2;                    // dekrementuj predchozi barvu
        };
    if (to_blue == 2 && tmp_blue <=0) {   // barva dekrementovala na dno
        to_blue = 3;                     // nastav priznak barva po dekrementaci
        to_green = 0;                    // inkrementuj dalsi barvu
        }; [/code]

Aby se barvy měnily pomalu, inkrementuji nebo dekrementuji obsah tmp_color vždy až po 8000 cyklech.

cnt_pgm ++; // citani cyklu, po kazdem preteceni vynuluj a podle priznaku nastav hodnoty tmp_color if (cnt_pgm >=8000) {cnt_pgm=0; if (to_red == 0) {tmp_red ++; } if (to_red == 2) {tmp_red --; } if (to_green == 0) {tmp_green ++; } if (to_green == 2) {tmp_green --; } if (to_blue == 0) {tmp_blue ++; } if (to_blue == 2) {tmp_blue --; }

Programuji pomocí CodevisionAVR a AVR Dragon přes JTAG.

Zdar,
nikde jsem si nevšim, že bys využíval záporná čísla -> proměnné stačí “unsigned” = bez znaménka, program bude o něco rychlejší.
S většinou proměnných se pracuje v rozsahu 0-255, to se vejde do unsigned char. Ušetříš paměť a opět zrychlíš program.
Aby ses neupsal k smrti, můžeš využívat složené operátory:
PORTA=PORTA | 0b10000000; lze napsat jako PORTA |= 0b10000000;
Za zavírací složenou závorkou se nepíše středník.
V posledním bloku by místo hejna ifů byl lepší switch.
If s 1 příkazem lze zjednodušeně napsat jako “if (to_blue == 2) tmp_blue --;”

Pokud pro tebe mají čísla konkrétní význam, usnadňuje orientaci použití enumu.

[code]//Nastaveni priznaku: 0=inkrementace, 1= po inkrementaci, 2= dekerementace, 3= po dekrementaci

typedef enum
{
plus,
po_plus,
minus,
po_minus
}state;
//Vytvořil jsi datový typ “state”, nyní deklaruješ proměnnou toho typu:
state promenna;
promenna = plus;[/code]
Normálně to lze používat v podmínkách a switchích.

Pokud ti bude ležet na srdci efektivita výtvorů, pár tipů najdeš v aplikční poznámce AVR035 Efficient C Coding :wink:.

Díky za podněty, myslím, že mě posunou zase kousek dál :wink:

Teď jsem si ještě všim - nepojmenováváš si piny. Když pak budeš chtít ledku dát jinam, budeš muset upravovat celej program. Využitím preprocesoru se tomu vyhneš. Za hlavičkovejma souborama nebo v samostatným souboru si definuješ:

[code]#define LED_RED PA7
#define LED_PORT PORTA
// pokud je dioda proti vcc, rozsveci se nulou
#define LED_RED_ON LED_PORT &= ~(1<<LED_RED)
#define LED_RED_OFF LED_PORT |= (1<<LED_RED)

// a pak v programu jen voláš
LED_RED_ON;
LED_RED_OFF;[/code]

Chvíli jsem neměl čas …

Díky za rady. Pomalu se rozhlížím po fóru a zjistil jsem, že jsem s učením začal někde uprostřed. Že existuje switch jsem vůbec netušil, hledal jsem to snad po všech knihovnách (snad to nazývám správně, myslím tím ty soubory, které přidávám funkcí #include) a potom jsem v zoufalství hodil dotaz do googlu a ejhle, ono to patří mezi řídící příkazy :confused:

Program jsem napsal tak, že jsem prošel několik tutorialů a zkoušel jsem. Mám tu i knihu od Váni, tam jsem listoval, když mi něco nebylo jasné, ale switch tam snad nikde nepoužívá.

Takže před dalším programováním budu asi dost číst :smiley: