LED-klocka, ej 7-segment eller LCD
-
- Inlägg: 7079
- Blev medlem: 31 augusti 2006, 16:42:43
- Ort: Jamtland
Re: LED-klocka, ej 7-segment eller LCD
Jag fattar det som att bara en punkt ska lysa. Förutom vid omslag till ny sekund.
Detta innebär att det blir en väldans massa skiftande för att få fadingen att fungera, när en ska lysa mer än den andra.
Själv har jag aldrig sett fram/back shiftregister.
Detta innebär att det blir en väldans massa skiftande för att få fadingen att fungera, när en ska lysa mer än den andra.
Själv har jag aldrig sett fram/back shiftregister.
- Swech
- EF Sponsor
- Inlägg: 4743
- Blev medlem: 6 november 2006, 21:43:35
- Ort: Munkedal, Sverige (Sweden)
- Kontakt:
Re: LED-klocka, ej 7-segment eller LCD
Om det nu skulle vara för mycket skiftande, vilket jg iofs inte tror så
kan man väl för tusan använda t.ex. en hel port och koppla individuella data out till
olika skiftreg. 8 ut till varsitt skiftreg -> 64 utgångar. kör 10 ut så har du 80
eller alt. sätt 2 skiftreg i serie. 8 ut -> 128 utgångar.
Då blir det inte så många skift för att fadea
Swech
kan man väl för tusan använda t.ex. en hel port och koppla individuella data out till
olika skiftreg. 8 ut till varsitt skiftreg -> 64 utgångar. kör 10 ut så har du 80
eller alt. sätt 2 skiftreg i serie. 8 ut -> 128 utgångar.
Då blir det inte så många skift för att fadea
Swech
-
- Inlägg: 7079
- Blev medlem: 31 augusti 2006, 16:42:43
- Ort: Jamtland
Re: LED-klocka, ej 7-segment eller LCD
Mycket shift blir det, men för mycket tror jag inte heller att det blir.
Vad är för mycket? Jo det må väl vara om man inte hinner med tidmässigt att shifta ut.
Rent utan att ha räknat på det bör man hinna skifta ut en kedja på så kort tid (<200us) att det inte hinner uppfattas av ögat.
Vad är för mycket? Jo det må väl vara om man inte hinner med tidmässigt att shifta ut.
Rent utan att ha räknat på det bör man hinna skifta ut en kedja på så kort tid (<200us) att det inte hinner uppfattas av ögat.
Re: LED-klocka, ej 7-segment eller LCD
Jag tror jag får förtydliga mig en smula. Ber om ursäkt om det har varit rörigt.
Vi tar det i steg:
1. Jag kommer ha 60 lysdioder i en cirkel, inte 180 eller något annat (förutom om vi börjar prata rgb).
2. Det enklaste fallet är ett enda "rinnande ljus" som stegar en diod per sekund. Då är exakt en diod tänd hela tiden (och jag skulle i princip kunna skifta ett steg per sekund). Detta är (förstås) löst. Samma principutseende kommer vi ha hela tiden - typ en diod tänd, inte halvcirklar eller något.
3. Men nu vill jag dessutom ha tim- och minut-visare, så att det blir en riktig klocka. (Vi kan anta att om två visare ligger på samma diod, så ser det bara ut som en enda.)
Det är ju ganska enkelt, jag kan till exempel göra ngt i stil med:
Här funkar ju inte lösningen med att bara skifta ett steg per sekund, utan jag måste tömma alla shift-register varje gång (vilket görs implicit eftersom jag skiftar ut nya).
Här skulle jag kunna vara klar och montera upp skiten. Nackdelar med denna är att det är svårt att se vad som är timme och minut, och att den inte är så fräck.
Här är 1,2 eller 3 tända samtidigt.
4. Ytterligare en intressant grej jag skulle vilja ha är att få mjuka övergångar. Om vi då går tillbaka till steg 2 (bara sekundvisare), och lägga till detta på sekundvisaren skulle man kunna göra så här, med en slags hemmasnickrad kod-PWM:
Detta har jag också löst, det är färdigt och funkar. Har alltså ett mjukt rinnande ljus. Här har vi då 1 eller 2 dioder tända samtidigt, beroende på iteration och tiondel.
Kan lägga upp video när jag kommer hem för att visa ungefär hur det ser ut.
5. Sen vill jag utöka detta till att även ha med timmar och minuter, och också de med mjuka övergångar. Då duger inte längre tenth_of_second, etc., det blir för rörigt. Principen jag tänkte mig då var att istället ha en array med 60 tal (med värden mellan 0->9).
Är det då så här:
Så betyder det att första dioden ska vara helt släckt, andra dioden bara ska vara tänd när iteration = 0 (dvs 10% av tiden), tredje dioden när iteration = 0 eller iteration = 1 (20% av tiden) osv.
Då blir principen istället:
I princip kan då alla dioder vara tända samtidigt, men i praktiken blir det max 6 st. (2 per visare)
Detta är också implementerat och funkar - så länge jag har 8 dioder istället för 60. När jag drar upp det till 60 tar varje iteration för lång tid, och det börjar flimra.
Min fråga är då helt enkelt: Kan man ta ovanstående lilla kodsnutt och skriva om den till en SPI-variant? Kommer det löna sig?
Vi tar det i steg:
1. Jag kommer ha 60 lysdioder i en cirkel, inte 180 eller något annat (förutom om vi börjar prata rgb).
2. Det enklaste fallet är ett enda "rinnande ljus" som stegar en diod per sekund. Då är exakt en diod tänd hela tiden (och jag skulle i princip kunna skifta ett steg per sekund). Detta är (förstås) löst. Samma principutseende kommer vi ha hela tiden - typ en diod tänd, inte halvcirklar eller något.
3. Men nu vill jag dessutom ha tim- och minut-visare, så att det blir en riktig klocka. (Vi kan anta att om två visare ligger på samma diod, så ser det bara ut som en enda.)
Det är ju ganska enkelt, jag kan till exempel göra ngt i stil med:
Kod: Markera allt
int sec_pos = ..., min_pos = ..., hour_pos=...;
for(i=0; i<60; i++){
if(i == sec_pos || i == min_pos || i == hur_pos)
set_data_high(); // slå på "serial input"-utgången
else
set_data_low(); // slå av "serial input"-utgången
next_output(); //slå på och av klockan
}
update_output(); // slå på och av latchen.
Här skulle jag kunna vara klar och montera upp skiten. Nackdelar med denna är att det är svårt att se vad som är timme och minut, och att den inte är så fräck.
Här är 1,2 eller 3 tända samtidigt.
4. Ytterligare en intressant grej jag skulle vilja ha är att få mjuka övergångar. Om vi då går tillbaka till steg 2 (bara sekundvisare), och lägga till detta på sekundvisaren skulle man kunna göra så här, med en slags hemmasnickrad kod-PWM:
Kod: Markera allt
iteration++; //denna räknas upp för varje iteration i main-loopen
if(iteration==10) iteration = 0;
int sec_pos = ..., tenth_of_second = ...;
for(i=0; i<60; i++){
if(i == sec_pos){
if(iteration > tenth_of_second)
set_data_high();
else
set_data_low();
}
else if(i == sec_pos + 1){
if(iteration <= tenth_of_second)
set_data_high();
else
set_data_low();
}
else{
set_data_low();
}
next_output();
}
update_output();
Detta har jag också löst, det är färdigt och funkar. Har alltså ett mjukt rinnande ljus. Här har vi då 1 eller 2 dioder tända samtidigt, beroende på iteration och tiondel.
Kan lägga upp video när jag kommer hem för att visa ungefär hur det ser ut.
5. Sen vill jag utöka detta till att även ha med timmar och minuter, och också de med mjuka övergångar. Då duger inte längre tenth_of_second, etc., det blir för rörigt. Principen jag tänkte mig då var att istället ha en array med 60 tal (med värden mellan 0->9).
Är det då så här:
Kod: Markera allt
array[0] = 0
array[1] = 1
array[2] = 2
...
array[10->60] = 0
Då blir principen istället:
Kod: Markera allt
iteration++;
if(iteration==10) iteration = 0;
int array[60] = ...;
for(i=0; i<60; i++){
if(iteration < array[i])
set_data_high();
else
set_data_low();
next_output();
}
update_output();
Detta är också implementerat och funkar - så länge jag har 8 dioder istället för 60. När jag drar upp det till 60 tar varje iteration för lång tid, och det börjar flimra.
Min fråga är då helt enkelt: Kan man ta ovanstående lilla kodsnutt och skriva om den till en SPI-variant? Kommer det löna sig?
Re: LED-klocka, ej 7-segment eller LCD
Rent spontant känns det ganska onödigt att blanda in SPI-funktionen. Din kod fungerar ju, så det finns väl ingen större anledning att börja göra om den.
Enda anledningen jag ser är om du vill befria processorn från arbete.
Men om du ändå vill syssla med SPI så bör det inte vara särskilt svårt:
60 bitar = 7,5 bytes. Ska du köra SPI måste du alltså skicka 8 bytes, och då är de första fyra bitarna i första byten "dummy"-bitar.
En variant är att du inne i loopen shiftar in bitar en och en i en "sänd-byte", med >> operatorn:
sendbyte = (sendbyte >> 1) | bit; // bit = 0x80 etta eller 0x00 nolla.
Om första biten är en etta och de andra är nollor kommer ettan att skiftas så att nät åtta bitar shiftats in får du talet 0b00000001 i sendbyte. (lägsta biten, dvs den till vänster , skickas ut först i SPI).
När du kommit till åtta, t.ex. genom att kolla if ( (i & 7) == 7) { } så skickar du byten. Det gör du enligt databladet:
(A) vänta till SPI ready (förra byten är klar) , dvs. while ( (SPSR & (1<<SPIF)) == 0);
(B) skicka ut data genom att skriva SPDR= sendbyte;
Nu ser du varför du måste skicka jämna åtta bytes. Annars skickas aldrig de sista. Och de fyra dummybytena måste komma först i slingan.
sedan måste funktionen update_output(); först kolla att SPI är 'ready' ... på samma sätt som innan du sänder en byte.
SPI enheten måste givetvis initieras i början av programmet.
EDIT: Du behöver ju inte skapa 64 bitar (8 bytes) i själva loopen. Det räcker att du skickar ut åtta bytes vid rätt tillfälle.
Om du sänder en byte varje gång då (i & 7) = 3 så kommer rätt bitar att skickas ut i rätt ordning.
Enda anledningen jag ser är om du vill befria processorn från arbete.
Men om du ändå vill syssla med SPI så bör det inte vara särskilt svårt:
60 bitar = 7,5 bytes. Ska du köra SPI måste du alltså skicka 8 bytes, och då är de första fyra bitarna i första byten "dummy"-bitar.
En variant är att du inne i loopen shiftar in bitar en och en i en "sänd-byte", med >> operatorn:
sendbyte = (sendbyte >> 1) | bit; // bit = 0x80 etta eller 0x00 nolla.
Om första biten är en etta och de andra är nollor kommer ettan att skiftas så att nät åtta bitar shiftats in får du talet 0b00000001 i sendbyte. (lägsta biten, dvs den till vänster , skickas ut först i SPI).
När du kommit till åtta, t.ex. genom att kolla if ( (i & 7) == 7) { } så skickar du byten. Det gör du enligt databladet:
(A) vänta till SPI ready (förra byten är klar) , dvs. while ( (SPSR & (1<<SPIF)) == 0);
(B) skicka ut data genom att skriva SPDR= sendbyte;
Nu ser du varför du måste skicka jämna åtta bytes. Annars skickas aldrig de sista. Och de fyra dummybytena måste komma först i slingan.
sedan måste funktionen update_output(); först kolla att SPI är 'ready' ... på samma sätt som innan du sänder en byte.
SPI enheten måste givetvis initieras i början av programmet.
EDIT: Du behöver ju inte skapa 64 bitar (8 bytes) i själva loopen. Det räcker att du skickar ut åtta bytes vid rätt tillfälle.
Om du sänder en byte varje gång då (i & 7) = 3 så kommer rätt bitar att skickas ut i rätt ordning.
Re: LED-klocka, ej 7-segment eller LCD
Okej, tack. Hela grejen är som sagt att jag vill befria processorn från arbete.
Varje iteration är för långsam, vilket gör att det blinkar istället för att fade:as (alltså: pwm-blinken blir plötsligt synliga, eftersom de är uppe i tiondelars sekunder).
Den stora frågan är egentligen om det är värt att lägga massa tid på att göra om det till SPI - hur mycket tjänar man på det för min sista loop?
Det blir ju massa nya bitoperationer och grejer.
Såvida man inte får lov att utföra annat arbete tills (SPSR & (1<<SPIF)) blir 1?
För då kan man ju multitaska lite iaf.
Varje iteration är för långsam, vilket gör att det blinkar istället för att fade:as (alltså: pwm-blinken blir plötsligt synliga, eftersom de är uppe i tiondelars sekunder).
Den stora frågan är egentligen om det är värt att lägga massa tid på att göra om det till SPI - hur mycket tjänar man på det för min sista loop?
Det blir ju massa nya bitoperationer och grejer.
Såvida man inte får lov att utföra annat arbete tills (SPSR & (1<<SPIF)) blir 1?
För då kan man ju multitaska lite iaf.
Re: LED-klocka, ej 7-segment eller LCD
Vad kör du på för klockfrekvens?
Jag tror att SPI går att köra på CPU/2, så om du kör 8 MHz kan du köra ut 4 miljoner bitar per sekund. Men det förutsätter ju att du hinner fiffla ihop en byte på 16 cykler.... och det är nog lite optimistiskt.
Det tar inte så lång tid att skriva ihop en SPI-drivrutin som du använder till detta.
Möjligtvis får du koppla om utgångarna - du måste ha klockan på SCK och data ut på MOSI.
Problemet är nog att det inte är SPI eller BITBANGANDE på porten som avgör hur fort det går här, utan hur du får fram bitarna.
Om du kör SPI och använder metoden jag nämnde ovan måste du ju fortfarande räkna ut varje enskild bit och pressa in dem i bytes...
Kanske går det att snabba upp om du har dina åtta bytes i ramminnet, och att du bara uppdaterar de bitar som måste ändras. De andra är kvar som de är i minnet.
I så fall får du ha tre slingor som håller reda på sina egna bitar (timme,minut och sekund).
för varje slinga måste du:
1) ha en räknare som vet var biten befinner sig.
2) ha en pwm räknare som vet i vilket stadie dimningen befinner sig i.
Dessa uppdaterar du smartast med interrupt 16 ggr per sekund. ( din "pwm" kan då ha 16 steg). Timme och minutbitarna uppdateras mycket sällan. (minutbiten 16 ggr/min eller var 3.75:e sekund) etc.
3) "vibrera" de tre bitarna fram och tillbaks enligt pwm...
ja.. det var bara delvis utvecklade idéer... jag orkar inte utveckla det mer (om det nu går...)
Jag tror att SPI går att köra på CPU/2, så om du kör 8 MHz kan du köra ut 4 miljoner bitar per sekund. Men det förutsätter ju att du hinner fiffla ihop en byte på 16 cykler.... och det är nog lite optimistiskt.
Det tar inte så lång tid att skriva ihop en SPI-drivrutin som du använder till detta.
Möjligtvis får du koppla om utgångarna - du måste ha klockan på SCK och data ut på MOSI.
Problemet är nog att det inte är SPI eller BITBANGANDE på porten som avgör hur fort det går här, utan hur du får fram bitarna.
Om du kör SPI och använder metoden jag nämnde ovan måste du ju fortfarande räkna ut varje enskild bit och pressa in dem i bytes...
Kanske går det att snabba upp om du har dina åtta bytes i ramminnet, och att du bara uppdaterar de bitar som måste ändras. De andra är kvar som de är i minnet.
I så fall får du ha tre slingor som håller reda på sina egna bitar (timme,minut och sekund).
för varje slinga måste du:
1) ha en räknare som vet var biten befinner sig.
2) ha en pwm räknare som vet i vilket stadie dimningen befinner sig i.
Dessa uppdaterar du smartast med interrupt 16 ggr per sekund. ( din "pwm" kan då ha 16 steg). Timme och minutbitarna uppdateras mycket sällan. (minutbiten 16 ggr/min eller var 3.75:e sekund) etc.
3) "vibrera" de tre bitarna fram och tillbaks enligt pwm...
ja.. det var bara delvis utvecklade idéer... jag orkar inte utveckla det mer (om det nu går...)

Re: LED-klocka, ej 7-segment eller LCD
Tack!
Smarta ideer, kikar på dem om jag ger mig på SPI. Dock blir jag lite tveksam på vad som händer när sekundvisaren går över en av de andra visarna, det borde kunna bli någon slags tokkonflikt mellan "vibrationerna" där känns det som. Smålurigt över bytegränserna också, men det känns som ett mindre problem.
Men du skickade mig nog i rätt riktning - tveksamt om SPI ger den riktiga boosten (nyttan är ju att jag slipper slå på och av en klocka, typ).
Ska göra lite andra mätningar och se vad det faktiskt är som tar mest tid (det här AVR studio är lite halvdant när det kommer till de bitarna, märker jag - den bryr sig inte om breakpoints och hoppar friskt när man kör med /O3).
Smarta ideer, kikar på dem om jag ger mig på SPI. Dock blir jag lite tveksam på vad som händer när sekundvisaren går över en av de andra visarna, det borde kunna bli någon slags tokkonflikt mellan "vibrationerna" där känns det som. Smålurigt över bytegränserna också, men det känns som ett mindre problem.
Men du skickade mig nog i rätt riktning - tveksamt om SPI ger den riktiga boosten (nyttan är ju att jag slipper slå på och av en klocka, typ).
Ska göra lite andra mätningar och se vad det faktiskt är som tar mest tid (det här AVR studio är lite halvdant när det kommer till de bitarna, märker jag - den bryr sig inte om breakpoints och hoppar friskt när man kör med /O3).
Re: LED-klocka, ej 7-segment eller LCD
Lite experiment visade tydligt att det är själva shift-delen som gör att det blinkar. I princip det enda som körs nu är (alltså, i princip på ett fast mönster):
Och det blinkar ordentligt. 1671 cycle steps, 0,5 ms per iteration. Tror jag ska minska antalet "styrkenivåer". Det är just nu 256, och det kanske är lite onödigt.
Kod: Markera allt
void UpdateFromPattern(unsigned char * pattern, unsigned char count, unsigned char step)
{
for(int i=count-1; i>=0; i--)
{
if(step<pattern[i])
PORTB |= (1<<PB0);
else
PORTB &= ~(1<<PB0);
PORTB ^= (1<<PB6);
PORTB ^= (1<<PB6);
}
show_all();
}
Re: LED-klocka, ej 7-segment eller LCD
Kanske det går fortare om du använder pekare istället för 'pattern' ?
dvs...
Fast med optimering på så kanske det bli samma?
dvs...
Kod: Markera allt
uint8_t * pekare;
pekare = &pattern[count];
while (pekare > 0) {
pekare--;
if (step < *pekare) { ... }
else { ... }
}
Re: LED-klocka, ej 7-segment eller LCD
Det tycker man ju att gcc ska klara?
Kan testa när jag kommer hem. Sen är det ju de facto "PWM" just nu, dvs pulsbredden moduleras.
Vad man skulle kunna försöka är typ:
Men beräkningarna blir rätt tuffa där. Kanske om man förspecar patterns.
Kan testa när jag kommer hem. Sen är det ju de facto "PWM" just nu, dvs pulsbredden moduleras.
Kod: Markera allt
||||||......
Kod: Markera allt
|.|.|.|.|.|
Re: LED-klocka, ej 7-segment eller LCD
Okej, har fått in en lite småoptimeringar. (Pekaren hjälpte inte är jag rädd.)
1. Sänkte det till 64 nivåer istället för 256. Det gör bara att det blir kortare perioder "svart" (snabbare blink).
2. Optimerade ner själva shiftkoden lite, (1677 cykler per iteration till 1016, hoppas bara registren klarar det...)
3. Drog ner hur ofta pattern-uppdateringen sker. Nu är det var 10:e ms, istället för varje ms.
Har nu jämna övergångar utan flimmer för 60 st. Det enda som stör lite är små extra blink som sker då och då. Har tre teorier:
- Det är när en ny pattern-beräkning sker, som något blir tänt lite för länge.
- Shiften är för snabb
- Det är i ett patternbyte som det blir något lurt.
Jag ska ta och montera på skiten med lite mer dioder för att se helhetsintrycket.
1. Sänkte det till 64 nivåer istället för 256. Det gör bara att det blir kortare perioder "svart" (snabbare blink).
2. Optimerade ner själva shiftkoden lite, (1677 cykler per iteration till 1016, hoppas bara registren klarar det...)
3. Drog ner hur ofta pattern-uppdateringen sker. Nu är det var 10:e ms, istället för varje ms.
Har nu jämna övergångar utan flimmer för 60 st. Det enda som stör lite är små extra blink som sker då och då. Har tre teorier:
- Det är när en ny pattern-beräkning sker, som något blir tänt lite för länge.
- Shiften är för snabb
- Det är i ett patternbyte som det blir något lurt.
Jag ska ta och montera på skiten med lite mer dioder för att se helhetsintrycket.
Re: LED-klocka, ej 7-segment eller LCD
Om du shiftar ut data med hjälp av interrupt och byter pattern i huvudprogrammet så kanske det blir jämnare (om den hinner med)... men man får nog räkna lite på det, om det lönar sig.