Sida 16 av 23
Re: Val av microprocessor, RGB LED styrning
Postat: 17 december 2010, 20:27:41
av sodjan
> Det kan bli väldigt fel (processorn slutar fungera för alltid) om du gör fel här!
"För alltid" är en liten överdrift. Den kan inte fixas via ISP utan man måste
ha en högvolts parallell programmerare. Man har man inte det så är det
kanske "för alltid"...

Den nyfikna kan googla på "Bricked AVR"...
Re: Val av microprocessor, RGB LED styrning
Postat: 17 januari 2011, 11:12:19
av dragon9226
Hej igen. Har tyvärr inte skrivit här på ett tag. Men nu har jag en fungerande produkt.
Jag har programmerat och fått fram en fungerande lösning.
Dock lyckas jag inte komma fram till hur jag ska göra med dimmningen.
Någon som har ett förslag?
(Då som den aktuella biten som gör jobbet. Hur denna anropas kan jag troligen lösa själv.)
PS.
Borde kunna göra en video snart.
Re: Val av microprocessor, RGB LED styrning
Postat: 17 januari 2011, 12:33:08
av jesse
Det beror väl lite på hur övriga programmet ser ut, speciellt hur du skickar ut signalerna till LED-matrisen. Antagligen går det att lägga in dimningen där nånstans, att man begränsar tiderna som varje rad är tänd, t.ex. Det går säkert att fixa med någon timer eller liknande.
Berätta gärna lite hur du har löst uppgiften - det är ju liksom lite av tanken med forumet att man får se hur andra har gjort.

Re: Val av microprocessor, RGB LED styrning
Postat: 17 januari 2011, 13:50:48
av dragon9226
Så här ser det ut:
Kod: Markera allt
//---------------- standardbibliotek ------------------
// #define F_CPU 8000000 för att använda intern 8 MHz osilator, men använder utomstående 16MHz
#include <avr/io.h>
#include <util/delay.h>
#include <util/delay_basic.h>
#define CLOCK (1<<PB1)
#define ROW PORTF
#define RED PORTA
#define GREEN PORTC
#define BLUE PORTD
char ROWNR;
char x = 1;
char xway = 1;
char y = 1;
char yway = 1;
void skicka_data(char red, char green, char blue) { // SKRIV ALGORITM HÄR
if (ROWNR != 0){ //Kan användas vid vissa mönster, om man t.ex. vill stega i raderna med en repetitionssats. Då bestämmer man ROWNR innan man skickar färgerna.
if(ROWNR == 1){
ROW = 0b00100000;
}
if(ROWNR == 2){
ROW = 0b00010000;
}
if(ROWNR == 3){
ROW = 0b00001000;
}
if(ROWNR == 4){
ROW = 0b00000100;
}
if(ROWNR == 5){
ROW = 0b00000010;
}
if(ROWNR == 6){
ROW = 0b00000001;
}
ROWNR = 0;
}
RED = red; //Röda portarna tilldelas
GREEN = green; //Gröna portarna tilldelas
BLUE = blue; //Blåa portarna tilldelas
}
/**** huvudprogrammet ****/
int main(void) {
// initiering av portar (se kapitel 12 i databladet - särskilt 12.2.1)
DDRF = 0b00000000; // alla pinnar på port F ska vara utgångar rad
DDRA = 0b11111111; // alla pinnar på port A ska vara utgångar röd
DDRC = 0b11111111; // alla pinnar på port C ska vara utgångar grön
DDRD = 0b11111111; // alla pinnar på port D ska vara utgångar blå
PORTF = 0b11111111; //aktiverar alla rader
while(1) { // ...loopa för evigt...
ROW = 0b00111111; //Ställer in vilka rader som ska aktiveras
skicka_data(0b11111111, 0b00000000, 0b00000000 );// red, green, blue //Skickar data om vilka kolumner (3x8, tre färger) som ska aktiveras
}
Så ser det ut (tog bort mönsterprogrammen).
Det är inte jättebra men jag kom inte på om man t.ex. kan skicka alla tre färgerna samtidigt.
Ni får gärna ha åsikter och tankar/ idéer om programmet.
Re: Val av microprocessor, RGB LED styrning
Postat: 17 januari 2011, 15:00:27
av jesse
En detalj bara:
Kod: Markera allt
if(ROWNR == 1){
ROW = 0b00100000;
}
if(ROWNR == 2){
ROW = 0b00010000;
... osv...
Alla dom där IF-satserna kan ersättas med
<< operanden flyttar nämligen "ettan" till den plats i byten som anges till höger om "<<". så (1<<1) blir 0b00000010, (1<<2) blir 0b00000100, (1<<5) blir 0b00100000 etc. Det kallas bit-shift. Eftersom du nästan bara jobbar på bitnivå här så kan det vara en fördel att kunna allt om bitoperatorer i C.
Här finns t.ex. en tutorial om det.
Angående programmet och dimmning:
Du har inte skickat med särskilt mycket av programmet direkt.
Det lilla du har med här visar inte hur du "bygger upp" ett mönster.
Kan du få fram vilka mönster som helst, eller har du några begränsningar?
Har du gjort nån slags rutin som stegar igenom rad för rad och tänder de lysdioder som ska lysa på *just den* raden?
Det är nämligen här du kan lägga in timingen (hur länge varje rad ska lysa) och använda detta dör dimning.
Vad är t.ex. ROWNR för en variabel, och var i programmet får den sitt värde?
Re: Val av microprocessor, RGB LED styrning
Postat: 17 januari 2011, 15:39:54
av dragon9226
ROWNR används ibland, t.ex. när man stegar mellan raderna. jag använde den när jag gjorde en prick som hoppade; först från 1-8 på rada ett, sedan 2 osv.
Då kan man med en repetitionssatts lätt stega fram radnummret.
Angående hur jag bygger upp mönstret så har jag ingen "smart" lösning. Utan jag använder mig av repetitionssatser mm. och skickar med skicka_data
ex:
Kod: Markera allt
for(int i = 1; i < 7; i++){ //En prick som går pixel för pixel, rad 1 sedan 2 osv...
ROWNR = i;
skicka_data(0b00000001, 0b00000000, 0b00000001 );// red, green, blue
_delay_ms(400);
skicka_data(0b00000010, 0b00000000, 0b00000010 );// red, green, blue
_delay_ms(400);
skicka_data(0b00000100, 0b00000000, 0b00000100 );// red, green, blue
_delay_ms(400);
skicka_data(0b00001000, 0b00000000, 0b00001000 );// red, green, blue
_delay_ms(400);
skicka_data(0b00010000, 0b00000000, 0b00010000 );// red, green, blue
_delay_ms(400);
skicka_data(0b00100000, 0b00000000, 0b00100000 );// red, green, blue
_delay_ms(400);
skicka_data(0b01000000, 0b00000000, 0b01000000 );// red, green, blue
_delay_ms(400);
skicka_data(0b10000000, 0b00000000, 0b10000000 );// red, green, blue
_delay_ms(400);
}
(Den ovanstående koden är till exemplet nämnt ovan.)
Om jag förstår vad du menar med rutin, så har jag ingen sådan.
Vad jag vet kan jag göra vilka mönster jag vill, men det beror nog på att jag får göra allt "manuelt", alltså tända "en" led i taget, och hoppa vidare om det ska vara oregelbundna skillnader som inte passar in med; ROW och RED, GREEN och BLUE.
(Det blir tyvärr ganska omständigt att ta fram nya mönster, då man nu måste bygga det från grunden.)
Jag gjorde även en programsnutt som får en "boll"/pixel att studsa runt på skärmen.
Det du skrev om bit-shift var ju riktigt smidigt.
Re: Val av microprocessor, RGB LED styrning
Postat: 17 januari 2011, 17:11:01
av jesse
Du har mycket att lära om programmering... men det är bara att kämpa på.
Just för att slippa skriva ett nytt program varje gång du ska göra ett nytt mönster så använder man t.ex. en funktion som skickar ut ett helt mönster bara genom att man pekar på en matris i t.ex. programminnet som innehåller mönstret.
Och nu när du har lärt dig det smarta << så kan du lätt göra funktionen som flyttar pricken lite smartare:
Kod: Markera allt
for(int i = 1; i < 7; i++){ //En prick som går pixel för pixel, rad 1 sedan 2 osv...
ROWNR = i;
uint8_t red=0b00000001;
uint8_t green=0b00000000;
uint8_t blue=0b00000001;
for (int j=0; j<8; j++) {
skicka_data(red, green, blue );// red, green, blue
red = (red << 1);
green = (green << 1);
blue = (blue << 1);
_delay_ms(400);
}
}
Ju mer man automatiserar i ett program desto lättare är det att återanvända koden i andra situationer.
Om du ska dimma i det här fallet så behöver du på något vis låta t.ex. rad-utgångarna "blinka" i hög hastighet - så snabbt att ögat inte uppfattar det.
Kod: Markera allt
dimma_rad(uint8_r rader, uint dimm) {
RAD = rader;
_delay_us(dimm); // dimm värde mellan 0 och 999
RAD = 0;
_delay_us(1000-dimm);
}
(exemplet ovan hade fungerat om delay_us() hade klarat 1000µS. Men nu gör det inte det: i AVR-libc:<util/delay.h> står det: "The maximal possible delay is 768 us / F_CPU in MHz." . och din CPU-frekvens är väl ganska hög, eller hur var det??? Så du kanske får göra en egen delay-rutin som kan vänta upp till t.ex 10 mS, och som kan ändras i 256 steg... Men ännu smartare är att använda en inbyggd timer i processorn.)
Och detta måste du hålla på med hela tiden, annars upphör dimningen.
Därför är det bättre att göra sådant i en interruptrutin. Då sköter detta sig självt och man behöver inte tänka på det i övriga programkoden. Interrupten kan då skötas av en timer som programmeras som PWM-generator (pulse width modulation). Det finns mycket att läsa om detta i ATmega-databladet som jag antar att du har uppe på skärmen hela tiden och läser i?
En länk om AVR-timers:
PWM in AVR
och om AVR-interrupt:
AVR-libc: <avr/interrupt.h>
Re: Val av microprocessor, RGB LED styrning
Postat: 18 januari 2011, 16:51:02
av dragon9226
Hej hopp.
Nu får jag väll ta och försöka hitta lite mer tid, till att gräva ned sig i dessa nya grejer.
Har inte det just nu..., men jag tror jag förstår vad du menar med att använda en funktion för ett mönster.
Alltså:
Att man skriver varje mönsteravsnitt i en egen programmdel, som sedan anropas från main programmet när man önskar använda detta?
Re: Val av microprocessor, RGB LED styrning
Postat: 18 januari 2011, 18:25:41
av jesse
Så kan man också göra, men det var inte så jag menade.
Jag tänkte att man skriver
en enda funktion som man anropar när man ska ändra mönster. Som
argument till funktionen anger man adressen till en en- eller tvådimensionell
array som innehåller data om hur mönstret ska se ut.
Funktionen kanske bara gör en enda sak: sparar adressen i en annan variabel.
Sedan har man en
timer som ger
interrupt t.ex. 10.000 ggr/sek.
Vid varje interrupt anropas en rutin som skriver ut en rad i mönstret.
För varje gång interruptrutinen anropas går den ett steg till nästa rad. Vid sista raden börjar den om från början.
På så vis kommer ett helt mönster att visas helt automatiskt utan avbrott utan att man behöver gör något i main.
Då kan du använda main till att koncentrera dig på t.ex. vad klockan är, när du ska byta mönster och hur de ska dimmas. (även dimningen upp eller ner kan göras som en del i interruptrutinen, om man sätter en variabel som säger hur mycket den ska dimmas och hur snabbt).
(En pdf-fil om AVR-timers som sammanfattar hu de används finns här. Det är nog meningen att någon ska stå och prata också, men det får du föreställa dig.)
(edit: stavfel)
Re: Val av microprocessor, RGB LED styrning
Postat: 18 januari 2011, 19:52:47
av dragon9226
Det där var ju ännu smidigare än mitt förslag.
Det ska jag ta och testa. Kanske tillsammans med min ide också. Får se, det beror ju på hur man lägger upp saker och ting.
Re: Val av microprocessor, RGB LED styrning
Postat: 21 januari 2011, 08:29:45
av dragon9226
Jag har funderat lite över hur jag skulle kunna ändra mönsterbytet.
Ett förslag:
I main anropar man funktionen som gör själva ändringen.
Denna anropas typ såhär:
skicka_data(100 ; 1,2 ; 2,4 ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; //Skicka data är funktionen som behandlar datan.
X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ;
X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ;
X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ;
X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ;
X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X)
Skicka_data tar emot en tvådimensionell array. Det första talet bestämmer hur länge hela "bilden" ska visas (100), ex. i mikrosekunder.
Sedan följer 48 decimaltal. Heltalet står för vilken färg som ska visas (0-7, 0-svart, 1-röd, 2-grön, 3-blå osv.) Decimalen står för hur ljus den pixeln ska vara. Då t.ex. i 10 steg, ex. 9 = "full" styrka, och 0 svag styrka. (Kan ju göras med fler decimaler om så önskas.)
Skicka_data har en repetitionssatts som med hjälp av det första talet bestämmer hur länge bilden ska visas (hur många varv). Sedan börjar programmet att gå från [1] i arrayen i stället för [0].
Den plockar ut [1] och tänder den/ de färger som siffran står för. ( if (tal >= 3 && tal < 4){ } ) Så bestämmer den att färgen är blå och tänder denna. Sedan plockar den ut decimalen och med denna bestämmer (antingen själv eller med en funktion) hur länge denna led ska lysa själv.
(Detta är så kort att hela skärmen uppdateras utan blink, men ändå så att olika leds kan lysa olika länge /starkt.
Vad tror ni om denna "skiss"?
Är jag ute och cyklar?
Re: Val av microprocessor, RGB LED styrning
Postat: 21 januari 2011, 11:04:21
av jesse
Det går säkert att göra så, men med vissa ändringar kanske (särskilt decimaltalen och dimningen).
Själv hade jag gjort på ett annat sätt (så som jag beskrev i förra inlägget), men för att du ska utveckla ditt sinne för programmering så är det ju mycket bättre att du utvecklar dina egna idéer än att du gör något som jag har hittat på.
Några detaljer som kan vara viktiga att tänka på:
A:Skicka array (=fält) som argument i en funktion:
man brukar inte göra så att man anger alla variabler i fältet en och en i funktionsanropet, utan man skickar bara arrayens namn, så kan du använda den i funktionen sedan.
Om du inte redan har en bok om C-programmering bör du skaffa en. Jag har en bra bok hemma som heter "Vägen till C" av Ulf Bitling och Jan Skansholm. Den innehåller bra förklaringar på sådana här saker. Kolla om du kan låna den på biblioteket.
exempel:
Kod: Markera allt
// definierar ett fält med 100 st (nr 0-99) 8-bitars positiva heltal
uint8_t monster[100] = { 3,8,7,4,4,23,65,67,4,23,2,1,45,7,7 .......... }; // (mönster)
... längre ner i koden...
skicka_data(monster); // "monster" pekar nu på den första av de 100 heltalen
... funktionen:
void skicka_data(uint8_t data[]) {
uint8_t a;
a = data[0]; // läs av data från fält
}
Men nu är det speciellt med just microcontrollers att de har olika minnen för program (=flashminne) och för data (RAM-minne) , och de brukar inte ha så mycket RAM-minne. Därför behöver man ofta spara på utrymmet i RAM (Alla variabler ligger i RAM-minnet). Du får du inte plats med så många mönster i minnet om du ska lagra allt i varabler). Därför brukar man lagra data som är statisk (= behöver aldrig ändras) i flashminnet. Där finns gott om utrymme, vanligtvis.
Då måste man göra på ett annat vis:
Kod: Markera allt
#include <avr/io.h>
#include <avr/pgmspace.h>
// definierar tre mönster med 10 heltal i varje... siffrorna lagras i programminnet (PROGMEM)
uint8_t PROGMEM monster[3,10] = {
{ 0,1,2,3,4,5,6,7,8,9 } , // mönster nr 0
{ 4,7,8,3,2,9,8,7,0,1,6 } , // mönster nr 1
{ 0,1,2,7,4,5,6,3,8,9 } // mönster nr 2
};
int main() {
visa_monster(2); // visa mönster nummer två
visa_monster(1); // visa mönster nummer ett
}
void visa_monster(int nummer) {
for (i=0; i<10; i++) { // loopa igenom alla element i mönstret
// läs data från programminnet och skicka ut till PORTB:
PORTB = pgm_read_byte(monster[nummer,i]);
_delay_ms(400);
}
}
ovanstående exempel kan du nästan sätta in direkt i ditt program bara för att testa hur det fungerar att läsa data från programminnet. I det här fallet är den tvådimensionella arrayen en global variabel och de två dimensionerna är (1) vilket mönster (2) siffrorna i mönstret.
B:Dimning:
Det kan vara väldigt svårt att kunna dimma varje LED för sig. Det kan vara enklare till en början om du försöker dimma hela mönstret. Har du räknat på hur fort det måste gå om varje lysdiod ska dimmas för sig och om det är möjligt? Du tänder ju inte lysdioderna en och en (då blir det lite mycket ljus), utan du tänder en rad åt gången. Om du då ska dimma enskilda lysdioder får du först tända alla dioder i raden för att sedan släcka dem med olika tidsfördröjning. Ganska avancerat!
Ett annat problem med att du bestämmer i själva mönstret hur mycket en diod ska lysa är att då måste du sedan multiplicera den ljusnivån för varje diod med den globala dimningsnivån. För tanken är väl att du ska kunna dimma ett helt mönster från mörkt till ljust och sedan mörkt igen?
Så för enkelhetens skull borde du inte ha med siffror om dimning för varje enskild diod i dina data (det får i så fall bli en specialöverkurs sen när allt annat fungerar)
C:Fundera på hur data är organiserat.
Det finns tre saker att tänka på när man bestämmer hur data ska lagras:
1) effektivitet: är det enkelt att få fram den "rådata" som behövs för att kunna visa mönstret, eller krävs det matematiska beräkningar eller krånglig omsortering av data för det? Försök få datan i din array att likna så mycket som möjligt den utdata du ska skicka, och att data kommer i den ordning som den ska användas.
2) begriplighet / lätthet att skapa mönstren: organisera data så att du kan förstå vad innehållet betyder. (det verkar vara denna punkt du har
3) Minnesutrymme: försök packa data om det inte blir för krångligt, för att spara minnesutrymme. T.ex. istället för att ha åtta 16-bitars heltal som innehåller en bit var, så använd ett 8-bitars heltal som innehåller alla åtta bitarna. Exempel:
Kod: Markera allt
int array [3,10] { {0,0,0,0,1,0,1,0},
{1,0,0,0,1,0,0,1},
{0,0,1,1,0,1,0,0} ; // inte smart!
uint8_t array[3] = {0b00001010,0b10001001,0b00110100} // smart!
Punkt (1) är nog det viktigaste här - annars kan man köra fast helt sen när man ska försöka skriva rutinen som visar mönstret.
Punkt (3) kanske inte är lika viktig om du har gott om programminne över. Men det är bra att tänka på om man vill kunna utöka programmet/antal mönster senare.
Punkt (2) kanske man inte alltid kan göra så mycket åt eftersom man måste kompromissa med de andra punkterna.
Så innan du bestämmer hur du ska lagra din data får du försöka tänka igenom om din "visa_mönster"-rutin verkligen kan hantera siffrorna i den ordning de kommer. Gör gärna ett flödesschema på visa-mönster-rutinen så du har koll på exakt vad du ska göra.
D:ALDRIG, ALDRIG använda decimaltal i sådana här sammanhang (och helst aldrig annars heller). Använd heltal! Hellre flera heltal än ett decimaltal!
PS: decimaltal skrivs med decimalpunkt, inte med komma. Och argumenten i ett funktionsanrop separeras med komma, inte med semikolon, därför skulle ditt exempel
skicka_data(100 ; 1,2 ; 2,4 ; X,X ; X,X ; X,X ; X,X ; X,X ; X,X egentligen skrivas som
skicka_data(100 , 1.2 , 2.4 , X.X, X.X , X.X ..., men nu ska man ju inte använda decimaltal. Om du använder flera heltal istället blir det
skicka_data(100 , 1,2 , 2,4 , X,X , X,X , X,X , X,X , X,X , X,X men det är
inte bra med så många argument till en funktion!
Re: Val av microprocessor, RGB LED styrning
Postat: 22 januari 2011, 22:58:27
av jesse
Gör gärna ett enkelt flödesschema för din funktion som ska läsa data från ditt fält (=array) och hur du skickar ut det till lysdioderna, så får vi se om det är något bra att bygga vidare på och till slut skapa en bra kod.
Kanske lite allmänt grundläggande programmering i C vore bra att jobba med så att du får mer grepp om hur du använder funktioner , fält osv... gärna direkt i din PC så du slipper gå omvägen via AVR-processorn. Ladda ner något gratis C-programmeringsverktyg som t.ex.
Bloodshedeller Quincy och börja göra små enkla program från nån bok (t.ex. den jag nämnde i förra inlägget!)
Är det nån annan här som har några tips hur man kommer vidare på den här nivån utan att servera färdiga lösningar?
Re: Val av microprocessor, RGB LED styrning
Postat: 23 januari 2011, 00:12:46
av dragon9226
Jag får ta och göra ett flödesschema snart.
Så jag kan komma vidare=)
Re: Val av microprocessor, RGB LED styrning
Postat: 23 januari 2011, 17:00:33
av dragon9226
Main:
I "main" ska man på ett smidigt och överskådligt sätt anropa lämplig funktion för att skicka ut mönster.
I en array lagras vilka pixlar som ska tändas. Denna array är tillgänglig för hela programmet (alla funktioner), och tilldelas innan anropet.
I anropet skickas ljusstyrka och tid, (eventuellt skickar man här också data för dimning, om man lyckas få till en automation för detta i funktionen. Då behövs om den ska upp/ner dimmas, tiden avgörs av hur länge den bilden ska visas.).
Har man mönster som används ofta, t.ex. om man skulle vilja ha siffror till något, så kan dessa sparas i PROGMEM.
Skicka_data tar arrayen, 1:dimensionell eller 2:dimensionell (enligt mig så skulle detta ha marginell skillnad för effektiviteten), skicka_data skulle kunna se ut ungefär såhär:
For-satts nr 1 används för att stega igenom pixlarna radvis. (En rad i taget skickas ut, vilket ger 6 steg.) I denna avgörs också hur länge mönstret ska visas.
Den plockar ut åtta nummer för att avgöra vilka färger på respektive plats som ska tändas. (Här kommer troligen for-sats 2, och eventuellt for-sats 3.)
I huvud for-satsen borde man också kunna ha en if-sats eller liknande, som reagerar om dimnings-talet inte är noll. Denna stegar då upp eller ned hur mycket svart paus det ska vara emellan raderna.
Den bör nog också samtidigt stega hur länge färgen ska vara tänd.
Detta borde kunna fungera som dimning för hela skärmen samtidigt.
Vad tror ni?
(Kanske inte gjorde detta helt som Jesse tänkte, men jag tyckte det funkade bra att göra såhär. För att tänka steg för steg.)