Ik heb een probleem met een stuk C-code geschreven in het programma MikroC. Het gaat hierbij om (alweer) een RGB-light die ik heb geprogrammeerd.
Hier is de gebruikte code:
http://www.nopaste.nl/?paste=1332
met als probleemgebied:
volatile signed char red = 0;
volatile signed char blue = 0;
volatile signed char green = 0;
volatile signed char counter = 0;
#define RED (2)
#define GREEN (1)
#define BLUE (16)
#define CONFIG_RED 100
#define CONFIG_GREEN 100
#define CONFIG_BLUE 100
void interrupt(void)
{
unsigned int temp;
INTCON &= ~0b00000100;
TMR0 = 0x20;
if(++counter > 100)
counter = 1;
if(red > 100) red = 100;
if(green > 100) green = 100;
if(blue > 100) blue = 100;
//temp = (red * CONFIG_RED) / 100;
temp = red;
if(temp >= counter)
PORTB |= RED;
else
PORTB &= ~RED;
//temp = (green * CONFIG_GREEN) / 100;
temp = green;
if(temp >= counter)
PORTB |= GREEN;
else
PORTB &= ~GREEN;
//temp = (blue * CONFIG_BLUE) / 100;
temp = blue;
if(temp >= counter)
PORTB |= BLUE;
else
PORTB &= ~BLUE;
}
Zoals de code hier staat doet deze het perfect. Maar zodra ik de regels die als commentaar staan zichtbaar maak, doet de code niets meer?
kan iemand mij helpen bij dit probleem?
Ik heb het geprobeerd op het forum van MikroC, helaas is hier tot nu toe niets uitgekomen:
http://www.mikroe.com/forum/viewtopic.php?t=18115
Los van eventuele problemen met de code (ik heb geen ervaring met C voor de PIC): waarom zou je iets willen vermenigvuldigen met 100 om het vervolgens weer door datzelfde getal te delen? 
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
red is een char.
Stel red is 8.
8 * 100 is 800, in een char is dat (768) + 32 De 768 past niet in een char en valt er buiten.
32/100 is ongeveer nul.
red=0.
Met je code zal red altijd 0, 1 of 2 worden.... Doet precies wat je wilt. Toch? Of wilde je dat niet?
Als het goed is, kan je met
red = ((int)temp * 100) / 100;hetzelfde bereiken als
red=temp;Waarom je het zo ingewikkeld wil doen, weet ik niet. Je bereikt er niks mee. Uit: "het doet niet wat ik verwacht" en de code die je geschreven had, kan ik niet destilleren wat je had willen bereiken. Het lijkt er op alsof je red=temp wil bereiken, en dat is veel simpeler te doen dan wat je aan het doen bent...
even iets van heel andere aard:
void interrupt void:
ga jij me zegen dat je dit allemaal in een interrupt routine doet???
good god...
Ik snap dat dit erg onligisch klinkt inderdaad;)
Ik wil alleen een mooie manier maken om kleuren bij te stellen. Zo is bij mijn RGB-light rood feller dan blauw. Ik had geen weerstanden meer liggen, dus dan maar in de software instellen;)
temp is een int, ik ging er vanuit dat dit goed ging. Helaas dus...
Deze reacties verklaren nu wel waarom de lichten af en toe gingen knipperen.. hmm..
Ik heb van red green en blue vervolgens wel een unsigned int gemaakt, en ook de optie die jij noemt heb ik geprobeerd. Zonder resultaat, of eigenlijk nu zelfs zonder af en toe knipperen.
Maar High met Henk, het kan dus waarschijnlijk zo zijn dat de code in de interrupt zo lang is, dat deze nog niet klaar is met uitvoeren, voordat de volgende interrupt al optreed?
Dat het in een ISR zit... ach... Als het beest niks anders te doen heeft... (ben er geen voorstander van, maar in deze context zie ik ook niet echt een probleem). Als het beest te 'traag' wordt, zou je normaal verwachten dat die IRQ gewoon niet gehandled wordt. Timing gaat compleet kapot, maar het blijft verder wel draaien. Worst-kaas scenario ontploft de stack.
Het geheel met 8/16 bits is reeds aangehaald. Ik zie echter ook dat je een read-modify-write doet. Kan dat op die port? Op een AVR zou het moeten werken, op een 8051 is het tricky en ik heb geen idee wat een pic-ding er van vindt.
Verder zit je met signed en unsigned door elkaar te harken. Dat *zou* goed moeten gaan in deze context (als die compiler z'n werk doet), maar ik zie geen enkele reden om signed te gebruiken. Niet moeilijker maken dan het is dus.
Naar mijn idee zou het verder gewoon moeten werken. Kijk evt. eens wat die compiler aan assembly genereert. Wellicht zit je gedachtenkronkel (?) ergens anders.
[edit]Waar knoop jij trouwens je ISR aan een IRQ? Hoef je in picding C niet op te geven dat iets een interrupthandler is? Iets met context op de stack mikken? Kan me zo voorstellen dat dat zonder die correctie per ongeluk min of meer goed gaat en met die correctie niet.
Verder zit er ook in je calc_change het 'char * 100' probleem.
[Bericht gewijzigd door Marco69 op (15%)]
"
for(i=0 ; i < (tottime / 100); i++)
Delay_us(1);
"
in een interrupt routine is niet zo netjes,
helemaal niet als die interrupt een timer overflow oid is
edit1: sorry, ik had verkeerd gekeken, komt idd niet in de interrupt.
[Bericht gewijzigd door Los kontakt op (19%)]
Dat zit ook niet in de interrupt routine? Verkeerd gekeken ben ik bang, of bedoel je dat ik de timer interrupt daar als timer moet gebruiken?
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Hoe vaak komt de irq voorbij eigenlijk? T'is wel veel voor irq code,maar zoals gezegd hoeft dat geen probleem te zijn tenzij je nested irq's krijgt.
Ik heb wel eens een applicatie gezien die _alleen_ uit ISR's bestond. Lege main loop. Hangt helemaal van je gekozen architectuur af.
Daan Timmer
Ik ben programmeur! geen electronicus! http://www.daantimmer.nl/ Er is een ontwerp! nu nog inhoud :-)
Ik zou zeggen, kijk eens naar de Assembly die de compiler genereert, dan kan je precies zien wat er zal gaan gebeuren...
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Al het voorwerk, zou ik trouwens buiten de IRQ doen. Binnen de IRQ zou ik iets doen van:
tr += red;
if (tr < max)
LEDR_OFF ();
else {
LEDR_OFF ();
tr -= max;
}
tb += blue;
if (tb < max)
LEDB_OFF ();
else {
LEDB_ON ();
tb -= max;
}
... enz
}(het ziet er een beetje wollig uit, maar met een beetje mazzel, wordt het maar 1 of twee assembly instructies per regel).
Vervolgens kan je voor de variablen chars nemen, en max 256 maken. De -= max ; gaat dan vanzelf. Maar je moet dan wel
tt = tb + blue;
if (tt > tb)
... OFFdoen.
De kleurcorrectie doe je m.i. door in main er voor te zorgen dat maxrood geschaald wordt....
Ik ben er inderdaad achter door de ASM code door te kijken.
Door dit in de interrupt routine te berekenen, is de interrupt code: +- 200 regels lang.
anders slechts! : +- 100regels lang.
Aangezien mijn interrupt al om de 200 instructies verschijnt, werkt dit inderdaad niet!
Probleem gevonden en opgelost, dan jullie wel!
wel nog even een reactie op Rew:
8 * 100 is 800, in een char is dat (768) + 32 De 768 past niet in een char en valt er buiten.
Dit klopt niet. Het wordt wel degelijk als een int gerekend. (in iedergeval in MikroC, en ik heb er geen problemen mee gehad)
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Elke 200 instructiecycles een irq? wow, da's wel heel erg vaak hoor! Ik zou nog eens goed naar m'n gekozen oplossing kijken.
Jochem
If you want to succeed, double your failure rate.
Op 29 januari 2009 11:50:33 schreef Marco69:
Ik zie echter ook dat je een read-modify-write doet. Kan dat op die port? Op een AVR zou het moeten werken, op een 8051 is het tricky en ik heb geen idee wat een pic-ding er van vindt.
Kan zeker problemen geven! Even aandacht aan besteden, ook als het nu toevallig wel werkt.
ik draai op 4MHz, ik wil een duty cycle van 0-100 hebben.
verder wil ik dat het zo hebben dat je de led niet ziet knipperen, dus een frequentie van 50hz is prettig.
dan zit je al op de 5khz.
4MHz / 4 = 1MHz, / 5khz = 200. vandaar!
Ik heb een pic 16f628 gebruikt trouwens.
Inmiddels heb ik het nodige veranderd aan de code.
Voor degene die geïnteresseerd zijn:
http://www.nopaste.nl/?paste=1334
Op 30 januari 2009 21:32:29 schreef Shorttracker:
[....]
Aangezien mijn interrupt al om de 200 instructies verschijnt, werkt dit inderdaad niet!
Da's niet leuk in een hogere programmeertaal. Veel te weinig controle over de code voor zo veel interrupts. Wellicht inderdaad eens naar je implementatie in combinatie met je taal kijken.
flipflop
"We cannot solve our problems with the same thinking we used when we created them" - Albert Einstein
Op 31 januari 2009 00:26:10 schreef Shorttracker:
4MHz / 4 = 1MHz, / 5khz = 200. vandaar!
Maar met 50Hz zit je nu wel met de gebakken peren. Als je nu eens naar 25Hz gaat, scheelt al de helft. En heeft de 628 een PWM aan boord? Dan hoeft het niet eens via software. Even checken misschien.
Wat doet die pic nog meer dan een ledje dimmen?
Daan Timmer
Ik ben programmeur! geen electronicus! http://www.daantimmer.nl/ Er is een ontwerp! nu nog inhoud :-)
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Ik vond ergens:
the rule in C is that all expressions must be evaluated as if all operands of size smaller than int were converted to signed int.
Dus je hebt gelijk, ik dacht dat de compiler in princiepe het grootste datatype van wat ie tot dan toe tegengekomen is gebruikte... Maar dat geldt dus niet voor alles kleiner dan int.
Dat levert dus voor kleine 8bit processoren waarbij je nadenkt over wat in een 8bit variabele past, en je realiseert dat je nooit over de 256 zal gaan met tussenresultaten dus minder optimale code op:
c = (a * b) % 10;heeft als a*b groter dan 256 uit kan komen andere resultaten als je met ints rekent dan als je met 8bit variabelen rekent. De compiler zal nu dus een moeilijke 16 of 32bits deling moeten doen, terwijl mischien een 8bit voldoende was geweest.
Je zult dus
c = a * b;
c= c % 10;moeten schrijven als je de compiler wilt vertellen dat een 8 bit deling voldoende is.
[Bericht gewijzigd door rew op (47%)]
Op 29 januari 2009 11:50:33 schreef Marco69:[edit]Waar knoop jij trouwens je ISR aan een IRQ? Hoef je in picding C niet op te geven dat iets een interrupthandler is? Iets met context op de stack mikken?
Nope, als je isr de juiste naam geeft knoopt hij hem automatisch aan de interrupt, regelt mikroC allemaal.
Ander puntje wat ik wel zou doen is de vlaggen pas helemaal aan het einde van de routine resetten, kans dat je dan nested interrupts krijgt is dan nihil. Wat wel kan gebeuren is dat je interrupts niet meer op de timer lopen maar elkaar steeds opvolgen, dan moet je gewoon je code eens goed nakijken
.
rew
four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/
Is het niet zo, dat ie een 'return-from-interrupt' in plaats van een return-from-subroutine aan het end plaatst? Dus de interrupt kan pas overnieuw zodra ie uit de interrupt routine retourneert.
Wel is het zo dat als je het bitje van "timer overflow" aan het begin cleared, dan staat die al weer te zeuren, tegen de tijd dat je klaar bent. Maar doe je dat pas aan het end, dan loop je het risico om de helft van de interrupts te missen.. hierdoor draait de boel wel, maar zie je rare effecten....
(oh trouwens, als je mijn voorstel van de bresenham PWM volgt, dan kan je door de waarde "1" te verbieden op de helft van de frequentie draaien).
[Bericht gewijzigd door rew op (13%)]
Daan Timmer
Ik ben programmeur! geen electronicus! http://www.daantimmer.nl/ Er is een ontwerp! nu nog inhoud :-)
rtfie, klopt gedeeltelijk wat je zegt, rew. in een PIC wordt zodra een interrupt gegenereerd word de interrupts disabled door de InterruptEnable flag uit te zetten.
Dit kan vervolgens in software weer aangezet worden of via rtfie.
Echter heb ik een keer een probleem gevalletje gehad... waarbij de compiler (C18) geen rtfie instructie genereerde, maar een normale return.. En ik me maar afvragen waarom mijn knopje maar 1x werkte!!
Jochem
If you want to succeed, double your failure rate.
De C18-compiler van microchip zelf? Ongelooflijk... Is dat met een patch wel opgelost later?
Je zoekt je een ongeluk na zoiets. Ik had ooit een bug in de IAR-compiler voor de MSP430 van TI. Die maakte een zooitje van een switch-statement. Daar ga je niet vanuit, dus daar zoek je het niet in. Zeker omdat het bij een hoog optimalisatie-level pas mis ging, dacht ik dat ik zelf ergens een denkfout in had zitten, of een volatile vergeten ofzo. 
Daan Timmer
Ik ben programmeur! geen electronicus! http://www.daantimmer.nl/ Er is een ontwerp! nu nog inhoud :-)
't was mijn interrupt functie die verkeerd was, maar de compiler gaf er geen warning over. Hij zag de interrupt routine als een normale routine ipv interrupt vector zeg maar. Dus hij genereerde een return. Maar de interrupt werkte namelijk wel, en dát was het rare. Dat is idd opgelost door een latere versie van C18 te installeren. (Was ondertussen weer een jaartje geleden, dus het kan zijn dat ik iets beetje verkeerd onthouden heb hoor
)