pic multithreading

Beste co'ers

Ik probeer een kaart te maken van het IJsselmeer met op de plaats van elke lichtboei een ledje. Dit ledje moet precies hetzelfde knipperen als de echte boei, bv 4sec aan 4sec uit enz. of 1 sec aan 2 sec uit. Dat is niet zo'n groot probleem maar het probleem is dat het om ongeveer 40 boeien/ledjes gaat. Het is ondoenlijk om alle 40 verschillende! lichtkarakters in 1 programma te zetten of zie ik iets over het hoofd? Kan ik multithreaden of voor elke boei een klein picje nemen? Of is er iets makkelijkers

Maakt het veel uit of een LED knippert op 4 seconden, of op 4,0001 seconde? Neen? Gewoon timertje doen dan...

Moet de tijd van elke led apart ingesteld kunnen worden, of hoort het globaal, voor elke led hetzelfde?

- - big bang - -

Niets is zo eerlijk verdeeld als verstand: iedereen denkt er genoeg van te bezitten

idd anders is het wel mogelijk alleen dan EEEEEEERG veel type werk :)

hoezo kan dit niet in een programma? dus je wil in een uc. anders zou iets met twee ne555 jes ook kunnen maar

maar digitaal. in dit geval per boei een schakeling lijkt me het simpelst

1 8 voudige dip switch aan 8 ingangen. waarbij bit 0 tot 3 de aantijd word. je hebt hier 16 mogelijkheden. en 4 tot 7 de uit tijd.

en een ledje aan een uitgang

bij opstarten de switches inlezen en dan een loopje
wat pseudo code

code:


aan_tijd = in[0..3]
uit-tijd = in[4..7] 

loopje:
led_uit = hoog //led dus aan
wacht (aan_tijd * 1 seconde)
led_uit = laag //led dus uit
wacht (uit_tijd * 1 seconde)
ga_naar loopje

het kan ook in iets met minder poten maar dan zul je ergens in wat eeprom de tijd moeten zetten

1 uC per LED?? Van overkill gesproken!
Zo moeilijk is het toch echt niet?
Neem een paar schuifregisters en een uC met een timer die elke seconde omvalt.
Eerst controleer je, via een lookuptabel, in welke positie elke LED moet staan, en stuur je die uit naar schuifregisters.
Als de timer valt, zet je de output op de pinnen van de registers en begin je de nieuwe waardes er in te schuiven.
Simpel toch?

Indien ze allemaal tegelijk moeten werken is het heel simpel, een µC, met 1 uitgangspen dewelke een MOSFET bestuurt die de leds aanspreekt.

Bij allemaal verschillende tijden kan het ook nog met 1 µC op volgende manier:
Je laat een timer lopen die bvb. om de 1ms overloopt en een interrupt genereert. In die interruptroutine zet je alle tellers van je verschillende leds. Je zet per led dus een teller die je bij interrupt verhoogt, is deze gelijk aan een waarde die je per led kan instellen, dan gaat de led aan, je schakelt om naar aftellen, zodanig als je volgende interrupt hierdoor komt je aftelt. Is deze waarde van teller gelijk gekomen aan een onderste ingestelde waarde, schakel je de led uit, en zet terug op optellen.
Dat kan je voor alle leds apart onder elkaar uitschrijven (het grootste deel van de code is gewoon copiërbaar). Die blok code moet je elke timerinterrupt doorlopen.

De controller heeft dus tussen elke timerirterrupt nog redelijk wat tijd om andere zaken te vervullen.

Bij gebrek aan genoeg poortpennen kan je misschien nog gaan multiplexen zoals bij lichtkranten en dotmatrixdisplays. maar de code wordt dan wel ingewikkelder.

- - big bang - -

Niets is zo eerlijk verdeeld als verstand: iedereen denkt er genoeg van te bezitten

Elke led heeft aan andere aan en uit tijd. ook minder dan 1 sec

kan ook natuurlijk. wellicht is een uc met een hoop poten ook een idee. look-up tabel en de led uitgangen in een array

of een seqeunser met eeprom. puls generator op 1 seconden (of minder, kleinste eenheid) --> teller --> paar eeprom met een tabel op de goede volgorde --> ledjes...

EDIT: ik moet sneller typen. Dit lijkt een beetje op wat Big bang schetst, maar met veel minder code en de data in een constante array (data hoort niet in de code!)

Als je nou een paar arrays maakt in de microcontroller; de eerste bevat, voor elke boei, de aan/uit tijden, elke keer een byte, in stappen van 100ms. Voor 1 sec aan, 2 sec uit, 4 sec aan, 4 sec uit (bijvoorbeeld) staat daar 10, 20, 40, 40. Die array is dus het aantal boeien * het aantal stappen groot, en kun je in het flash geheugen zetten.

In het werkgeheugen heb je ook een array, met voor elke boei 2 bytes. De eerste is de huidige stap, en de tweede het aantal tikken dat de boei nog in deze stap moet blijven. Als de tweede op 0 staat, ga je een stap verder.

Je begint dus voor deze boei met het kopiëren van de waarde 10 naar het tweede byte, en elke 100ms, op een timer interrupt, trek je daar 1 van af. zodra je op 0 komt, hoog je het eerste byte met 1 op (volgende stap), en kopieer je de overeenkomstige waarde uit de constanten array, en schakel je het LEDje om. Zo loop je steeds, in de timer interrupt, de hele lijst boeien af.

Je zou een waarde 0 in de constante array kunnen gebruiken om aan te geven dat je weer terug moet naar het begin, of alle boeien hetzelfde aantal stappen geven.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Kan iemand een klein voorbeeldje posten? voor bijvoorbeeld 2 boeien

Je zou een lus kunnen maken die bijvoorbeeld continu telt van 0 tot 65535.
Voor elke LED geef je dan een eigen knippertijd op.

Voorbeeld in PIC Basic.

code:


DIM x AS WORD

WHILE 1 = 1
  FOR x = 0 TO 65535
    PORTA.0 = x / 100
    PORTA.1 = x / 90
    PORTA.2 = x / 233
    PORTA.3 = x / 310
    enz.
    DELAYUS 100           ;Eventueel de lus iets vertragen
  NEXT
WEND

Eigenlijk aanpassen zodat je een paar 74HC595 IC's met de PIC aanstuurt (PICBasic instructie SHOUT, dan heb je maar een eenvoudige PIC nodig.

Ohm sweet Ohm | www.picbasic.nl

Dat gaat, op die manier, natuurlijk niet werken als de tijd aan/uit niet gelijk is, en ze gaan altijd allemaal tegelijk aan op het moment dat de teller terug gaat naar 0. Ook zijn codes van meerdere pulsen, zoals volgens mij in de praktijk gebruikt worden, niet mogelijk.

Het volgende stukje code doet wat je (denk ik) wilt, maar dit is gewoon C voor een console applicatie. Als je geen C compiler hebt voor windows, zou je devcpp kunnen downloaden, die is gratis en werkt erg gemakkelijk, vindt ik.

code:


#include <cstdlib>
#include <iostream>
#include <stdio.h>

#define NrLights 4
#define NrSteps 4

const char Delays[ NrLights ][ NrSteps ] = { { 10, 20, 40, 40 }, { 20, 20, 10, 10 }, { 10, 10, 0, 0 }, { 10, 10, 10, 10 } };
char LightStep[ NrLights ];
char LightDelay[ NrLights ];

char LightStatus[ NrLights ];

int main( void )
{
    while( 1 )
    {
           for( char Count = 0; Count < NrLights; Count++ )
           {
                if( !( LightDelay[ Count ]-- ) )
                {
                  if( ( ++LightStep[ Count ] >= NrSteps ) || !Delays[ LightStep[ Count ] ] )
                    LightStep[ Count ] = 0;
                  LightDelay[ Count ] = Delays[ Count ][ LightStep[ Count ] ];
                  LightStatus[ Count ] = !LightStatus[ Count ];
                }
                printf( "#%d %d %d %d ", Count, LightStatus[ Count ], LightStep[ Count ], LightDelay[ Count ] );
           }
           printf( "\n" );
           system( "pause" );
    }
    return 0;
}

Nu aan jouw de taak om te begrijpen hoe dit werkt, en dit geschikt te maken voor een interrupt routine in een microcontroller (je moet er nog wel iets van leren he).

EDIT: LightStatus is in de microcontroller natuurlijk de status van de uitgangen.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

Op 25 augustus 2008 21:14:48 schreef SparkyGSX:
Dat gaat, op die manier, natuurlijk niet werken als de tijd aan/uit niet gelijk is, en ze gaan altijd allemaal tegelijk aan op het moment dat de teller terug gaat naar 0.

Allemaal tegelijk uit heb je gelijk in, heb ik over het hoofd gezien |:( .

Ohm sweet Ohm | www.picbasic.nl

Nu aan jouw de taak om te begrijpen hoe dit werkt, en dit geschikt te maken voor een interrupt routine in een microcontroller (je moet er nog wel iets van leren he).

Tja... Daar ben ik wel even zoet mee, ben wel eens aan c begonnen maar...

Ga denk ik eerst wat in q basic maken, en dan omzetten naar picbasic. picbasic test zo moeilijk.

[Bericht gewijzigd door pientertje op maandag 25 augustus 2008 21:29:07 (16%)

Hm, het kost meer inspanning om
a. te begrijpen wat de bovenstaande C-code doet en
b. te controleren of het klopt :-(

PICBasic voorbeeld.
LET op: nog wel zelf de interrupt instellen en bepalen hoe je de LEDs wilt aansturen.
Is uiteraard niet getest, maar je kunt met een stuk of 3 leds beginnen. Dan hoef je niet met qbasic te rommelen...

code:

    Device 16F648A
    Config HS_OSC, WDT_OFF, PWRTE_ON, LVP_OFF, MCLRE_OFF
    
    ALL_DIGITAL = true
    PORTB_PULLUPS = On
    XTAL = 20 
    
    'Aantal leds dat we hebben
    Symbol AantalLeds 5
    
    'Vaste aan- en uittijden
    Dim tijdAan[AantalLeds] As Byte
    Dim tijdUit[AantalLeds] As Byte
    
    'Teller per LED hoe lang het nog duurt voor we gaan schakelen
    Dim vertraging[AantalLeds] As Byte
    
    'Per LED of ze aan of uit staan
    Dim isAan[AantalLeds] As Byte
    
    Dim i As Byte
    Dim SecondeFlag As Bit

'------------------------------------------------------------------------------------
    on_hardware_interrupt InterruptHandler
    GoTo Main
    
'------------------------------------------------------------------------------------
InterruptHandler:
    ' Doe timer-spul.
    ' Als 1 seconde voorbij is, zet de SecondeFlag
    Context Restore
    
'------------------------------------------------------------------------------------
' Definitie van alle tijden
'
'   Voorbeeldje: 1e 5 LED's
'
    Data 3,1, 4,2, 2,3, 3,2, 1,4
    'etc...
    
Main:            
    'Alle data wissen.
    'LEDS staan dus default uit.
    Clear
    
    ' Timer configureren op 1 interrupt per seconde.
    ' Dit is een combi van een zo lang mogelijke timer, + een tellertje
    ' in de ISR
    '...
    
    'Initialiseren van alle tijden
    For i = 0 To AantalLeds - 1
        Read tijdAan[i]
        Read tijdUit[i]
        'Door alle 'vertragingen' op 1 te zetten, gaan straks binnen een
        'seconde alle LEDs aan.
        vertraging[i] = 1
    Next i
    
    '
Seconde:
    'Wacht tot een seconde voorbij is
    If SecondeFlag = 0 Then GoTo Seconde
    
    'Yes: 1 seconde voorbij. Update alle tellers van de LEDjes
    For i = 0 To AantalLeds - 1
    
        'Tellertje voor deze LED 1 aflagen
        Dec vertraging[i]
        
        'Als voor deze LED de tijd nu op 0 staat, dan uit- of aanzetten
        If vertraging[i] = 0 Then
        
            'Stond de LED aan? Dan gaan we nu dus de uit-tijd aftellen
            If isAan[i] = 1 Then
                vertraging[i] = tijdUit[i]
            Else
                'De LED stond uit, dus nu weer de aan-tijd aftellen
                vertraging[i] = tijdAan[i]            
            End If
            
            'Vlaggetje voor uit of aan omzetten
            isAan[i] = isAan[i] ^ 1
        End If
    Next i
    
    'Alle LEDS aan- of uitzetten, afhankelijk van de vlaggen isAan[]
    'SHOUT of iets dergelijks
    '...
    
    'En weer wachten op de volgende seconde
    SecondeFlag = 0
    GoTo Seconde

    End
Volgend project: funcgen met ad9833 afmaken...

Vat dit niet verkeerd op, maar hoe lang ben je al met PICs bezig en wat heb je al gemaakt?
Het lijkt me, op basis van je vorige posts, een beetje veel hooi op je vork... Ik kan me altijd vergissen natuurlijk, dan mag je deze post gerust negeren!
Maar het is misschien beter om eerst een stevige basis op te bouwen en steeds moeilijker te gaan, dan meteen zoiets proberen te maken.

Op 25 augustus 2008 18:06:58 schreef SparkyGSX:
EDIT: ik moet sneller typen. Dit lijkt een beetje op wat Big bang schetst, maar met veel minder code en de data in een constante array (data hoort niet in de code!)

Je kan daar natuurlijk varianten op schrijven en de code effectiever maken, maar ik schetste een beetje de invallende gedachte bij mij. C ken ik jammer genoeg (nog) niet, de basicversie kan ik wel volgen. (ik schrijf altijd in assembly)
Dit is het grote verschil tussen µC programmeren en PLCs programmeren. In µC code kan je op een bepaalde plaats blijven hangen, lussen zoveel je wil zonder dat er nog verdere code wordt uitgevoerd. Bij PLC wordt er cyclisch geschreven, de PLC doorloopt telkemale het programma binnen een maximaal vastgelegde tijd, anders spreekt de cyclustijdbewaking aan, dit ter veiligheid van onbewaakte ingangen/uitgangen.

Hier moet je dus cyclisch schrijven bij een µC; programmacode blijven doorlopen en statussen veranderen indien de tijd daarvoor is aangebroken.
Picsels heeft een soortgelijk voorbeeld uitgewerkt in Basic, alleen zou ik de hele tijdtellerdinges in een timerinterruptroutine duwen zoals in m'n eerste post. Nu staat de µC rondjes te draaien in de lus rond Seconde: zolang de secondeflag 0 blijft. Als je het geheel stuurt vanuit een timerinterrupt en alles in die interruptroutine afhandelt, komt je controller vrij voor nog eventuele andere taken, totdat er terug weer een timerinterrupt komt.

- - big bang - -

Niets is zo eerlijk verdeeld als verstand: iedereen denkt er genoeg van te bezitten

@bb: het is inderdaad de praktische uitwerking die je al kort beschreef (niet al te ingewikkeld).

Alleen is het m.i. niet zo handig om teveel code in de interrupt te stoppen (lees: de afhandeling van alle vlaggen).

Terwijl de uC staat te 'loopen', kun je alles doen wat je in de tussentijd nog wilt doen tussen.
Alleen als door de interrupt het 1-seconde vlaggetje wordt gezet, weet je dat je met de LEDs aan de slag moet.
In essentie is dat je ISR-afhandeling, maar dan gewoon in de main loop van je programma (simpele finite state machine met maar 2 states).

Volgend project: funcgen met ad9833 afmaken...

Tis wel zo dat je niet teveel code in een interrupt afhandelingsroutine moet proppen, opkomende interrupts van lagere prioriteit komen daardoor vertraagt, maar in dit geval is het toch niet zo tijdskritisch. Een iets of wat controllertje dat op 8Mhz draait (of meer) vliegt daardoor om snel wat tellertjes te incrementeren of decrementeren en te zien wat er omgeschakeld moet worden.
Tzal wel lukken.

Er zijn vele wegen naar Rome, maar ik hoop dat de TS nu weet waar Rome ligt, dat hij principes snapt, daar draait het om, en dan gaat de rest vanzelf.

- - big bang - -

Niets is zo eerlijk verdeeld als verstand: iedereen denkt er genoeg van te bezitten
Volgend project: funcgen met ad9833 afmaken...

Ik zou ook voor de array gaan zoals Sparky al aangaf, alleen dan een array met slechts 1 waarde en dan daar dus de knipperfrequentie in plaatsen.
Dan in een loop/interrupt een globale teller ophogen en zodra de globale teller % (modulo) de knipperfrequentie 0 is, dan XOR je de led met 1, dus hij gaat knipperen.
De teller zul je ook een keer moeten resetten, dit om niet een overflow te krijgen.
Dit kun je berekenen.
Stel je hebt 3 leds die op 1,2 en 4 sec moeten knipperen, dan is de teller modulo ook 4, immers 4 is deelbaar door alle mogelijke waardes.
Is het 2,3,4 dan zou de tellermodulo 12 zijn, immers is 12 deelbaar door alle waardes en blijt de loop mooi doorgaan.

Just my 2 cents.

Het hele idee was, dat je op die manier ook ingewikklde patronen kunt genereren, wat bij mijn weten in de praktijk ook wordt gebruikt (kort-kort-lang bijvoorbeeld). Alle andere systemen die ik hier heb gezien, kunnen alleen verschillende frequenties genereren. Het is natuurlijk de vraag wat de TS nu precies wil.

Een manager is iemand die denkt dat negen vrouwen in één maand een kind kunnen maken

IK heb nu dit qbasic prgramma, alleen kan ik in qbasic geen interval van kleiner dan een seconde gebruiken.

code:


CLS
DIM ao(3)
DIM uo(3)
DIM ko(3)
DIM nu(3)
ao(1) = 0
ao(2) = 0
ao(3) = 0
uo(1) = 2
uo(2) = 1
uo(3) = 1
ko(1) = 4
ko(2) = 2
ko(3) = 3
x = 3
begin:
FOR a = 1 TO x
IF ao(a) = nu(a) THEN PRINT "#", a, " aan"
IF uo(a) = nu(a) THEN PRINT "#", a, " uit"
IF ko(a) = nu(a) THEN nu(a) = -1
NEXT a
FOR b = 1 TO x
nu(b) = nu(b) + 1
NEXT b
SLEEP 1
GOTO begin
END

Omgezet naar picbasic en het werkt perfect. Alleen hoe kan ik de array waardes op 1 regel invoeren zodat ik niet te veel regels krijg. Ik heb nu de array waardes zo ingesteld:

code:


DIM ao[3] AS BYTE
DIM uo[3] AS BYTE
DIM ko[3] AS BYTE
DIM nu[3] AS BYTE
ao[0] = 0
ao[1] = 0
ao[2] = 0
uo[0] = 20
uo[1] = 10
uo[2] = 10
ko[0] = 30
ko[1] = 10
ko[2] = 20