EEPROM lezen/schrijven

Beste allemaal,

Het is weer eens raak, ik heb een wazig probleem met een PIC en ik ben intussen echt door mijn ideeën heen.

Ik ben bezig met een Battery Management System. Ja ze zijn ook kant en klaar te krijgen maar die doen niet precies wat ik wil, daarbij vind ik zelf maken leuker ;).

Het probleem: Ik heb het onboard eeprom in PIC's al in meerdere projecten zonder veel uitdaging gebruikt. Je geeft het adres en je leest of schrijft dat adres. Niet veel bijzonders... Nu ben ik bezig om tijdens het gebruik van de accu de capaciteit te bepalen, dwz: de actuele state of charge wordt berekend op basis van de beste gegevens die op dat moment aanwezig zijn. Het is infeite een zelf lerend systeem dat gaandeweg de capaciteit meet en telkens bij stelt als deze veranderd is of voor bijvoorbeeld zelfontlading compenseert. Om deze gegevens niet kwijt te raken zodra de accu (tijdelijk) helemaal uitgeschakeld wordt schrijf ik de belangrijkste gegevens naar EEPROM en lees deze weer terug tijdens het opstarten van de PIC. De hele code is vrij veel dus heb ik het hieronder samen gevat tot de interessante stukken.

Het vreemde is nu dat als ik de EREAD in de initialisatie boven de CLEAR zet, de berekening werkt zoals bedoeld, behalve dat (natuurlijk) het terug lezen van de gevens niet werkt. Deze worden tenslotte vrijwel direct daarna weer uit het RAM gewist door de clear.

Zet ik de EREAD net onder de clear werkt de berekening niet meer en blijven de waardes constant op 0 staan. Mijn vermoeden is dat dat de waarde is die vanuit het eeprom gelezen wordt en telkens overschreven wordt door die 0. Maak ik van die regels even een comment dan werkt de berekening gewoon weer.

Het lijkt dus haast alsof de PIC elke keer de hele software doorloopt IPV alleen het stuk tussen "hoofdlus" en "goto hoofdlus" met de bijbehorende subroutines. Terwijl de "INITIALISATIE START" niet telkens opnieuw voorbij komt op de seriele poort.Ik kan alleen niet ontdekken wat er dan voor zorgt dat de pic weer helemaal bovenaan begint.

De twee tellers in de interrupt dienen alleen maar om bepaalde berekeningen niet al te vaak te doen omdat ik hier veel met floats reken en dat relatief veel tijd kost. En om het aantal writes naar het EEPROM een beetje te beperken. Het EEPROM zal op z'n hoogst elke 5 min geschreven worden, als de waarde in EEPROM en RAM gelijk is wordt het niet geschreven.

Alle hulp of zelfs maar een zetje in de goede richting wordt zeer op prijs gesteld!!!

Alvast bedankt.

Vriendelijke groet,

Daan Steeman

pic basic code:


Device = 16F1938

Config1 FOSC_HS, WDTE_OFF, PWRTE_OFF, MCLRE_OFF, CP_OFF, CPD_OFF, BOREN_OFF, CLKOUTEN_OFF, IESO_OFF, FCMEN_OFF
Config2 WRT_OFF, VCAPEN_OFF, PLLEN_OFF, STVREN_OFF, BORV_19, LVP_OFF

All_Digital false             ;Alle ingangen digitaal
Xtal = 20
Declare Hserial_Baud = 38400                                        ; Set baud rate to 38400  
Declare Hserial_RCSTA = %10010000                                     ; Enable serial port and continuous receive
Declare Hserial_TXSTA = %00100000                                     ; Enable transmit and asynchronous mode 
Declare Hserial_Clear = On                                            ; Optionally clear the buffer before receiving
Declare Adin_Res 10                                                   ; an/dig converter resolutie van 10 bits
Declare Adin_Stime 500                                                 ; sampletime van 1000us

            
OPTION_REG.7 = 0 
       ;76543210
ADCON1 = %10000000
ANSELA = %00001111                                                    ; van A0, A1, A2 ANologe ingang maken
ANSELB = %00100000                                                    ; Poortb uitgangen digitale uitgangen maken
INTCON =%01100010 
T1CON = %00110101                                         
PIE1 =  %00000001
T1GCON =%00000000
T2CON.2 = 1
APFCON = %01000000                                                    ; CCP3 op pin b.5 zetten
CCPTMRS0 = %00000000    ; timer 2 word gebruikt voor alle ccpmodules
CCPTMRS1 = %00000000    ; timer 2 word gebruikt voor alle ccpmodules
PR2 = %11111011         ; timer2 instellen op ongeveer 2000Hz
CCP1CON = %00001100     ;alleen PxA word gemoduleerd. de overige worden als portpins geset
CCP2CON = %00001100     ;alleen PxA word gemoduleerd. de overige worden als portpins geset
CCP5CON = %00001100     ;alleen PxA word gemoduleerd. de overige worden als portpins geset

On_Hardware_Interrupt GoTo Interrupthandler 

Symbol EElaagstesom = 0;1,2,3
Symbol EEhoogstesom = 4;5,6,7
Symbol EEsom        = 8;9,10,11
Symbol EESOC        = 12;13,14,15

Dim Som As Float           ; elke seconde word hierbij de capaciteit in Wh bij opgeteld/afgetrokken om het netto van in en uitgaande stroom te krijgen 
Dim Hoogstesom As Float    ; de hoogste waarde die "SOM" ooit gehad heeft
Dim Laagstesom As Float    ; de laagste waarde die "SOM" ooit gehad heeft
Dim SOC As Float           ; actuele state of charge in procenten

Clear

HSerOut ["INITIALISATIE start", $0D] 


Som = ERead EEsom
Hoogstesom = ERead EEhoogstesom
Laagstesom = ERead EElaagstesom
SOC = ERead EESOC 

; Overige initialisatie van overige componenten en berekeningen

INTCON.7 = 1 ;alle intterupts inschakelen

Hoofdprogramma:

;een hele berg aan berekeningen voor dingen als cellen balancen, actuele stroom en spanningen bepalen

SerIn BUSRX, 84, 1000, Timeout1, [Wait("SIG"),Str RXbuffer];wachten op de vraag van de master voor gegevens

Verder:     

Select RXbuffer[0]
  Case 1 
    Output BUSTX 
    SerOut BUSTX, I9600, ["SIG",Dec3 Vcell1, ",", Dec3 Vcell2, ",", Dec3 Vcell3, ",", Dec3 ActueleStroom, $0D, "xxxxxxxxx"]  ; die gegevens terug sturen
    Input BUSTX             
EndSelect

GoTo Hoofdprogramma
End

Timeout1:

GoTo Hoofdprogramma

Interrupthandler:

Context Save
INC Secondeteller
INTCON.7 = 0
;metingen verrichten
;bepalen (zonder al te veel berekeningen) of alle waardes (voornamelijk de celvoltages) binnen de veilige marges liggen

If Secondeteller > 10 Then
  ; actuele State Of Charge berekenen
  Som = Som + (ActueleStroom * Vtot/3600)
  If Som > Hoogstesom Then Hoogstesom = Som
  If Som < Laagstesom Then Laagstesom = Som
  SOC = ((Som - Laagstesom) / (Hoogstesom - Laagstesom))*100 
  If Vtot > 12.3 And ActueleStroom < 0.5 Then Hoogstesom = Som
  If Vtot < 9 Then Laagstesom = Som
  HSerOut [Dec5 Som, $09, Dec5 Laagstesom, $09, Dec5 Hoogstesom, $09, Dec5 SOC, $0D]
  Secondeteller = 0
  Inc Vijfminteller
EndIf

If Vijfminteller > 300 Then
  If Hoogstesom != ERead EEhoogstesom Then EWrite EEhoogstesom, [Hoogstesom]
  If Laagstesom != ERead EElaagstesom Then EWrite EElaagstesom, [Laagstesom]
  If Som != ERead EEsom Then EWrite EEsom, [Som]
  If SOC != ERead EESOC Then EWrite EESOC, [SOC]
  Vijfminteller = 0 
EndIf

  INTCON.7 = 1
Context Restore

End


KGE

Golden Member

Moeten die vierkante haken wel om de variabelen Hoogtesom, Laagstesom, Som en SOC bij die Ewrite ?

Hoi KGE, dank voor je reactie

Op 12 november 2018 00:14:22 schreef KGE:
Moeten die vierkante haken wel om de variabelen Hoogtesom, Laagstesom, Som en SOC bij die Ewrite ?

Voor zover ik weet wel. In de manual van de compiler staat de syntax:
Ewrite Address, [Variable{, Variable...etc}]

En ze staan ook in de software die ik een tijd eerder geschreven heb en waar het ook prima werkt.

Daarbij komt de software eigenlijk nieteens zo ver. Als ik die 5 minuten laat aflopen schrijft hij gegevens naar het EEPROM, dat kan ik zien via de pickit die ik gebruik om te programeren, die kan ook het EEPROM uitlezen namelijk. Het is het lezen waar iets mis gaat... ik realiseerde me net ineens dat het eeprom ook geen $00 is als het niet geschreven is maar $FF. Dus hij leest het eeprom uberhaupt niet goed terug...

De syntax met vierkante haken in documentatie is om aan te geven dat die elementen optioneel zijn.

code:

Ewrite Address, [Variable{, Variable...etc}]

betekent dus dat:

code:

Ewrite Address, 
Ewrite Address, Variable1
Ewrite Address, Variable1, Variable2
Ewrite Address, Variable1, Variable2, Variable3

allemaal geldig zijn.

(dat is wat er STAAT, niet wat ze bedoelen!)

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

Parameters tussen vierkante haakjes zijn in de meeste talen optionele (niet verplichte) parameters.
Uitzondering zijn o.a. arrays... (sommige talen gebruiken 'gewone' haakjes, andere gebruiken vierkante...)

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Ja de volgende variabele (dwz variabele 2 enz) zijn optioneel maar bij een Ewrite zal ik toch minstens 1 variabele op moeten geven die geschreven wordt naar het opgegeven adres?

Maar begrijp ik goed dat jullie denken dat die haken weg moeten? De Ewrite is het probleem niet die doet het wel, of de inhoud van het eeprom veranderd in elk geval op het moment dat ik dat verwacht. De EREAD doet het niet (goed) want ik zou verwachten dat als ik het eeprom uitlees zonder dat daar ooit iets in geschreven is dat ik $FF terug krijg. Terwijl mijn float 0,000 blijft.

Overgens staan die haken ook in de software die al jaren probleemloos draait, inclusief gebruik van het eeprom... HSEROUT gebruik ik ook altijd met haken. Dus volgensmij mogen die haken er wel omheen staan (En is het msischien niet verplicht?)

pic basic code:


Hserout ["Hello ", "world", $0D]
Hserout ["Dit wordt de tweede regel", $0D]

Die haken horen er niet. Wat de compiler ermee doet is onbekend. (hij kan ze negeren of er iets onbekends mee doen...)

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Misschien is dingen tussen vierkante haken ineens een array.
Een array van variabelen naar eeprom schrijven is een zinnige actie. In het kader van dim stuff as byte; en dim otherstuff as float; en dat je die alletwee naar eeprom kan schrijven hint er naar dat "eewrite" stiekum naar de grootte van de argumenten zit te kijken.

In Hserout ["Hello ", "world", $0D] is een "array van bytes" ook wel een zinnig argument. In C zou je hier 2x een pointer naar een string en dan een getal 13 krijgen, maar dat zou in dit taaltje zomaar anders kunnen zijn.

Het argument: "het werkt al jaren prima" ben ik minder gevoellig voor. Mogelijk werkt het "toevallig". Dus als je er achter komt dat het anders hoort, dan moet je het fixen.

Als /ik/ hier op CO om hulp vraag, dan gaan alle, "dat kan het niet zijn" argumenten de deur uit. Gewoon proberen wat men voorstelt. Jij hebt op de een of andere manier een blinde vlek voor wat er mis is, dus roept ook vanzelf: 'maar dat kan het niet zijn' als men de juiste suggestie heeft.

En omdat jij mogelijk beter in de materie zit dan de "hulpverleners" hier, kan het zijn dat jij gewoon in 90% van de gevallen gelijk hebt. Dus dan antwoord je: "dat heb ik op jou aanraden geprobeerd, maar het werkt niet". Maar die 10% of 1% waarbij jij NIET gelijk hebt, daar doe je het om.

Als je dingen probeert die anderen voorstellen kan het ook zijn dat de suggesties er toe lijden dat je ander gedrag krijgt wat je niet had verwacht, maar wat wel hint naar waar het probleem zit.

Ik krijg ook een beetje het gevoel dat je eea gewoon moet debuggen. Als een ingewikkeld programma (en wat ingewikkeld is hangt van de persoon af!) het niet in 1x wil doen, dan moet je kleinere stukjes proberen en checken.

four NANDS do make a NOR . Kijk ook eens in onze shop: http://www.bitwizard.nl/shop/

'Ik laat het maar staan want het werkt toch?' is inderdaad niet de juiste manier. Vroeger of later wordt je daar door 'gebeten'... ;)
Gewoon de manual volgen. Wat nu werkt, hoeft in een toekomstige versie van de compiler (die misschien wat strikter is) niet te werken...

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Arco en Rew,

Ik heb van jullie beide al meer dan eens hulp gehad dus ik weet zeker dat jullie weten waar jullie het over hebben.

Als /ik/ hier op CO om hulp vraag, dan gaan alle, "dat kan het niet zijn" argumenten de deur uit. Gewoon proberen wat men voorstelt. Jij hebt op de een of andere manier een blinde vlek voor wat er mis is, dus roept ook vanzelf: 'maar dat kan het niet zijn' als men de juiste suggestie heeft.

Hier ben ik het hartgrondig mee eens. Om wat voor reden dan ook werkt het niet zoals ik bedacht had dus blijkbaar denk ik ergens iets verkeerd. Dat is precies de reden dat ik hier een vraag stel. En zoals je al zegt kan dingen uitproberen die andere opperen ook weer andere inzichten op.

Ik schrijf mijn programma's altijd regel voor regel, dwz voor zover mogelijk schrijf ik 1 klein stukje, test dat, en als dat werkt ga ik door naar het volgende. Het grootste deel van de code bestond al en het berekenen van de SOC samen met het EEPROM verhaal daarbij is de nieuwste toevoeging die ik aan het testen was en niet bleek te werken.

Als ik een tip krijg probeer ik die (vrijwel) altijd uit. Ik was vanmiddag op mijn werk en kon het dus niet testen anders had ik dat al gedaan. Mijn voornaamste punt is ook niet dat die haken daar vaker staan en het altijd gewerkt heeft. Maar dat het probleem niet in dat stuk van de code zit. Het is de EREAD die rare dingen doet. De EWRITE schrijft op het moment dat ik dat verwacht iets in het EEPROM.

Buiten dit hele verhaal ben ik toch even in de manual gaan kijken omdat er vaak ook voorbeelden bij staan. Het volgende komt rechtstreeks uit de manual:

pic basic code:


Device = 16F628       ' A device with on-board eeprom   
Dim Var1 as Byte
Dim Wrd1 as Word
Dim Address as Byte

Var1 = 200
Wrd1= 2456
Address = 0         ' Point to address 0 within the eeprom
Ewrite Address, [Wrd, Var1]  ' Write a 16-bit then an 8-bit value 

Dim MyFloat as Float  
MyFloat = 3.145  
Hserout [Dec2 MyFloat]  ' Send 2 values after the decimal point 

De haken horen er dus wel omheen. Het lijkt er op dat de {} haken optioneel zijn. Vandaar ook dat variabele 1 tussen blokhaken staat en variabele 2 enz tussen {}. Blokhaken gebruik je inderdaad ook voor een array (Number[index])

In het kader van "toch even proberen" even de blokhaken weg gehaald... Direct komt de compiler met :
ERROR[Line 517]: Square opening bracket '[' missing!

Dus de haken moeten er toch echt omheen...

Zal niet zo spannend zijn, maar je gebruikt 2 keer End in je programma.... Alleen op t einde gebruiken.

Hoi Diebob,

Klopt, maar beide worden nooit bereikt door de goto en Context Restore respectievelijk... Ik heb de eerste er uit gehaald maar helaas, geen effect...

Ik zet altijd een END onder de subroutines voor het geval er een fout in de stack zit. Dan stopt de software gewoon ipv rare dingen te gaan doen.

[Bericht gewijzigd door DaanSteeman op 12 november 2018 19:36:07 (31%)]

@Daan,

De secondeteller

If Secondeteller > 10 Then

Telt dat secondes of 0,1 secondes?

Verderop zie ik namelijk staan

If Secondeteller > 10 Then
Secondeteller = 0
Inc Vijfminteller
EndIf

If Vijfminteller > 300 Then

PS:
Moet zijn:

If Secondeteller > 10 9 Then

[Bericht gewijzigd door ohm pi op 12 november 2018 20:19:00 (14%)]

Bezoek mijn neefjes' site: www.tinuselectronics.nl

Zonder detailkennis van picbasic, zie ik de volgende issues:

In die interrupt handler zit waarschijnlijk veel te veel code.
-> Je behoort in een interrupt handler zo weinig mogelijk te doen, alleen je device/hardware lezen en bijvoorbeeld in een (ring)buffer zetten.
In de main loop reken je alles door.

Ik zie bijvoorbeeld een zwik floating point code in de interrupt handler zitten.
Het ligt eraan of picbasic ook de floating point context goed saved of alle registers die erbij horen.
-> Een dingetje niet goed restored en de mainloop hangt zich op.

Verder een hserout, lijkt me niet zo handig zo'n routine aan te roepen vanuit een interrupt context.
-> Dit kan zomaar een stack overflow opleveren (wat vaak een reset gedrag geeft) of een deadlock in interrupts.
(PS hetzelfde geld voor de eewrite).

Kortom je zult de structuur van je programma zodanig moeten veranderen dat je de meer tijdrovende zaken (eewrite/hserout etc) in je main afhandelt.

Klopt het dat je stukken uit het programma hebt weggelaten?
Zoals ";metingen verrichten"

Henri's Law 1: De wet van behoud van ellende. Law 2: Ellende komt nooit alleen.

Op 12 november 2018 20:12:53 schreef ohm pi:
@Daan,

De secondeteller [...] Telt dat secondes of 0,1 secondes?

Verderop zie ik namelijk staan[...]

PS:
Moet zijn: [...]

Ohm pi. De intterupt gebeurt elke 0,1 seconde dus ik tel tot 10 9 inderdaad! om die berekening 1 keer per seconde te doen

De vijfminutenteller telt verhoog ik elke seconde met 1 en door dat 300 299 keer te doen schrijf ik hooguit elke 5 minuten het eeprom (om het eeprom niet maar eindeloos vaak te schrijven wat relatief beperkt kan)

@Henri62:

In de interupthandler zit inderdaad veel code. Aanzienlijk meer dan ik eigenlijk zou willen. Ik had in de eerste instantie het zo gemaakt dat ik in de intterupthandler eigenlijk alleen de analoge ingangen las, dan dat met een hex waarde vergeleek om te bepalen of de voltages nog in binnen de marges valt. Om zo te voorkomen dat ik in de interrupthandler moet gaan zitten rekenen met floats. Het stomme is alleen als ik verder alleen een bitje set (of een teller verhoog en in de hoofdlus zeg IF teller > whatever then....) kwam de timing heel vreemd uit. Omdat ik hier Wh wil uitrekenen moet ik me wel aan de "echte" tijd houden, een seconde moet ook wel echt een seconde zijn.

De hserout in de interupt. Ik snap niet helemaal wat je hier bedoeld... Waarom zou dat een stackoverflow opleveren? Het is geen functie die ik aanroep, de code verlaat die lus niet en kan dus ook niet op de verkeerde plek terecht komen. Dat is tenminste wat ik meestal assosieer met stackoverflow. Routines aanroepen en vervolgens verkeerd weer terug springen naar de hoofdlus. (de hserout is daar overgens tijdelijk... ik gebruik het veel om te debuggen. Neemt niet weg dat als dat het probleem veroorzaakt ik het natuurlijk aanpas ;))

Omdat ik behoorlijk tijdrovende zaken in de interupthandler doe heb ik wel de interrupts uit staan zodra ik aan de interupthandler begin en zet ik die weer aan vlak voor ik daar uit spring. Anders kreeg ik inderdaad vreemde dingen omdat de interrupt werd aangeroepen terwijl hij nog bezig was met de vorige. Sinds ik de interupts uit zet en weer aanzet is dat opgelost.

Ik heb inderdaad hele lappen code weg gelaten (Er staat nog meer in de interrupt dat ik hier gepost heb) om te voorkomen dat jullie 600 regels code moeten doorspitten. Ik zal eerst eens even gaan proberen om toch alles behalve het meten en die ruwe waardes vergelijken met de veilige grenzen te doen in de hoofdlus. Eens kijken wat dat oplevert en of ik dan toch de timing uiteindelijk goed kan krijgen

Overigens blijf ik wel vreemd vinden dat stel het is inderdaad een stackoverflow (of iets willekeurig anders) wat een complete reset oplevert... Dan zou ik verwachten dat hij het hele programma vanaf regel 0 doorfietst en dus ook weer opnieuw de regels

HSerOut ["INITIALISATIE start", $0D]
HSerOut ["INITIALISATIE klaar", $0D]

Tegen komt die ik dus op mijn pc zou moeten zien verschijnen....

Hoe dan ook, ik ga de code aanpassen om zo veel mogelijk uit die interrupthandler te krijgen, ik weet niet of dat vanavond nog lukt en ik zit de laatste tijd met vrij veel overuren. Maar zodra ik meer weet laat ik het weten!!

Alvast bedankt voor de hulp in elk geval!

PS: Even voor de zekerheid... Zolang ik/de software niks in het EEPROM geschreven heeft is dat helemaal vol met $FF. Met andere woorden, als ik een byte terug lees zou dat $FF opleveren. Maar ik lees het 4 bytes eeprom als float en krijg als decimale waarde 0,000 te zien.... Dan is het lezen dus per definitie niet goed gegaan of mis ik hier even iets grandioos?

Omdat deze instructie

HSerOut ["INITIALISATIE start", $0D]

maar éénmaal uitgevoerd wordt denk ik dat de waarden in de eprom altijd nul zijn.
Hoe weet jij dat de goede waarden telkens na 5 minuten goed in de eprom geschreven worden?

Bezoek mijn neefjes' site: www.tinuselectronics.nl

Blijft dat een 'blocking' iets als HSerout absoluut niet in een interrupt thuishoort.
Zoals gezegd alleen het hoognodige doen daar, en de rest (zoals Hserout) in main doen...

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Ik heb even geprobeerd een andere chip te pakken (wie weet was het eeprom in deze gewoon kaduuk) helaas zelfde verhaal.

Ik ben dus even helemaal back to basics gegaan. Een chip op een breadboardje. niks schrijven geen berg code, gewoon alleen even byte 0 eeprom uitlezen. Resultaat 255 zoals verwacht.

Dat zelfde geld voor byte 1,2,3. dus het is inderdaad $FF, $FF, $FF, enz

Lees ik nu een float van 4 bytes terug vanaf adres 0 krijg ik hexadecimaal dus $FFFFFFFF. Wat een float van ....NaN oplevert. Stuur ik die over de hserout naar de pc komt daar 0,000 te staan. Oke, tot zover dus redelijk wat ik verwacht. Alleen moet ik dus nog even zien uit te vissen waarom die eread uitgevoerd wordt zonder dat ik die code aanroep.

EDIT: @ohm pi: Nee de waardes zijn dus echt 255, kon me vaag herrinneren dat ik dat een keer in de cursus van Fritz gelezen heb en ik heb het net (zoals hierboven beschreven) even getest. het is echt $FF.

Die 5 minuten is de tweede teller die meeloopt. Als de actuele waarde van SOC (en de andere 3 varriabele) niet overeen komt met die in het eeprom schrijf ik die naar het eeprom. Dan ben ik in het ergste geval 5 minuten aan metingen kwijt wat totaal insignificant is. Zeker als het systeem zich ingeregeld heeft en er dus alleen maar gecorrigeerd hoeft te worden voor zelfontlading en degradatie van de accu.

@Arco en Henry62:
Ik heb de interrupt even helemaal uitgekleed. Ook een aantal functies die ik eigenlijk er wel in wil houden heb ik er tijdelijk even uit gehaald. De complete interupt is nu :

pic basic code:

;--------------------------------------------------------interupthandler---------------------------------------------------------------------
Interrupthandler:   

Context Save
INTCON.7 = 0  
Inc Secondeteller
;WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW analoge signalen binnenhalenWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW
DworddummyA1 = ADIn 3 
DworddummyV1 = ADIn 2
DworddummyV2 = ADIn 1
DworddummyV3 = ADIn 0
   
  
  If DworddummyV1 > MaxcelvoltageADCwaardeV1 Or DworddummyV2 > MaxcelvoltageADCwaardeV2 Or DworddummyV3 > MaxcelvoltageADCwaardeV3 Then
    OvervoltOUT = 1
  Else
    OvervoltOUT = 0
  EndIf 
 
 ;als de stroom te groot word accu loskoppelen
  If DworddummyA1 > 600 Or DworddummyA1 < 400 Then           ; bij een laad of ontlaadstroom van meer dan 5A accu loskoppelen
    MOSFETS = 0
    DelayMS 1000     
    For Temp = 0 To 100
      Servo Servo1, 1740
      Servo Servo2, 1650
      DelayMS 20
    Next
  EndIf
  ; klaarmaken voor de volgende interrupt
  TMR1H = $35          ; preset voor nieuwe telling om exact elke 100ms een interupt te krijgen 
  TMR1L = $52          ; preset voor nieuwe telling om exact elke 100ms een interupt te krijgen  
  pir1bits_tmr1if = 0  ;interuptflag reseten  
  INTCON.7 = 1
Context Restore

Het enige wat nu nog afschuwelijk veel tijd kost is de servoaansturing. Maar dat gebeurt alleen als de accu buiten de veilige marges valt en dan zal de timing me een zorg zijn. Dan word eerst de stroom onderbroken door de mosfets uit te gooien en dan de accu galvanisch gescheiden van alles wat er aan hangt door 2 servos die 6 microswitches los laten. De rest van de instructies zijn voor zover ik weet vrij snel... De traagste zal nog de AD conversie zijn denk ik

PS: ik heb behoorlijk hardhandig zitten knippen, dus remarks kunnen niet meer helemaal kloppen...

Die delayms(1000) is natuurlijk ook een absolute no-no... :)
Servo aansturing kun je simpel maken met pwm of timer, dus niet met die ingebakken rommel... (of gewoon in main() doen anders.)

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

Op 12 november 2018 22:14:02 schreef Arco:
Die delayms(1000) is natuurlijk ook een absolute no-no... :)
Servo aansturing kun je simpel maken met pwm of timer, dus niet met die ingebakken rommel... (of gewoon in main() doen anders.)

Ja maar de code wordt dus alleen maar gebruikt als de stroom te hoog wordt. dat is tot nu toe wel geteld 0 keer gebruikt (ik heb een extern knopje er tijdelijk aan geknutseld om die te testen). Maar die code waaronder de delay (die uiteraard inderdaad uit de boze is in een interupt) wordt nu niet aangeroepen. Als dat wel zo zou zijn zou hij zijn eigen voeding uit gooien dus dat zou ik wel merken ;)

Ik heb intussen eens de interupt helemaal uitgeschakeld. De enkele dingen die ik alleen daar even ook in de hoofdlus gegooit en de interupt gewoon er helemaal uit gegooit.... het zelfde probleem is nog altijd aanwezig. Het lijkt dus niet vanut de interupt te komen...

[Bericht gewijzigd door DaanSteeman op 12 november 2018 22:23:02 (16%)]

hadv

Golden Member

Allereerst: je gebruik van de teksthaken is correct. Andere talen, andere gebruiken.
Als mensen die commentaar leveren niet op de hoogte zijn van de PicBasic syntax moet je dat commentaar met een korreltje zout nemen. In dit geval betreft het het commentaar van rew en Arco.

Even voor de lezers die PicBasic niet kennen...als er meerdere variabelen kunnen worden meegegeven dat staan die altijd tussen teksthaken, als er maar 1 variabele wordt verwacht staat die niet tussen teksthaken. Heeft allemaal overigens geen biet met variabelen van het type array te maken.

Het commentaar op de interrupthandler is wel correct overigens, daar mag van zijn lang zal ze leven geen lange delay in.

De problematiek rond intcon.7 en clear snap ik niet, maar het lijkt mij verstandig de intcon.7 voor de clear op 1 te zetten.
Wat me wel opvalt is dat je in je eerste post nergens aangeeft welk interrupt bit je gebruikt en je lijkt het ook niet op 0 terug te zetten. In je laatste post zet je de interrupt flag wel op 0, dus dat is goed.

$FFFF bij een ERead wijst op een adres waar de de waarde helemaal maagdelijk is. Pas overigens op met het quoten van en refereren aan de PicBasic.nl cursus. Deze is intussen ernstig verouderd en er is helemaal geen garantie dat een moderne PIC zich net zo gedraagt als een 16F628A!. Altijd even de datasheet lezen.

Wat je kunt doen is met een EData statement initieel de eerste bytes in de EEProm een waarde geven zodat je in je pickit kunt zien of er daadwerkelijk iets is veranderd.

Just find out what you like and let it kill you

@hadv,

Wauw dat is nog eens even een berg info.

Wat betreft de delay in de interrupthandler. Ik weet dat het verre van netjes is om daar lange delays of eigenlijk überhaupt delays in te gebruiken. Maar zoals ik al uitgelegd heb zal dat stukje code waar die in zit "nooit" aangeroepen worden tenzij de verdere afloop van het programma, de eeprom, enz me een zorg zal zijn zolang die accu maar losgekoppeld wordt.

Ik vraag me alleen sterk af (zeker omdat ik intussen geprobeerd heb de interrupt helemaal uit het programma te halen) of het probleem daar vandaan komt. De interupt komt nu niet voor, dus wordt de code die daar staat niet doorlopen, dus komt het probleem niet daardoor.... zou ik zeggen tenminste. Tergelijk moet ik toegeven dat het probleem juist is dat er code doorlopen wordt zonder dat dat de bedoeling is xD...

Ik volg even niet wat je bedoeld met "de problematiek rondom intcon.7 en clear. Na de initialisatie en leeg gooien van het ram zet ik de interupt aan en duik ik de hoofdlus in.
Jij zegt de interupt aan zetten nog voor de clear. Maar dan gaat de interupt dus (potentieel) al voorkomen voordat de hele initialisatie gebeurt is. In die initialisatie staat ook een stuk waar ik 3 arrays vul met een redelijk aanneembare waarde voor de accuspanning. Doe ik dat niet moet mijn lopend gemiddelde eerst 20 keer berekend worden voordat daar een zinnige waarde uit komt en tegen die tijd heeft de bms de accu al lang uit gegooit wegens een te lage spanning. Door die eerste waardes er in te zetten omzeil ik dat en wijkt de spanning alleen iets af de eerste 20 cycli. Dus ik zal de interrupt sowieso daarna aan moeten zetten...

Haha dat de picbasic.nl cursus wat verouderd is geloof ik graag. Dat was mijn eerste ervaring met PIC's, programeren, electronica, enz. Dus ik neem het ook wel met een korreltje zout. Ik moet wel zeggen dat ik tot nu toe geen dingen ontdekt heb die echt veranderd zijn... Ik neem aan dat je die opmerking maakte vanwege mijn herrinnering van de cursus wat betreft $FF in het eeprom zolang er niks ingeschreven is. Ik kon dat ook al zien op de pickit dus vandaar dat ik redelijk zeker was dat het klopte. Daarbij lees ik in een ander projectje ook het eeprom uit en heb ik daar in de code staan dat als de eerste byte 255 is. De waardes in het eeprom niet gelezen moeten worden omdat deze dan blijkbaar niet kloppen (255 komt nooit voor op dat adres in het programma).

Ik ben bekend met EData, maar ik heb al gezien dat de inhoud van het eeprom kan, en ook daadwerkelijk veranderd. Het teruglezen gaat alleen niet goed. Ik heb even een chip op een breadboardje gezet om even met een (zo goed als) kaal programma te testen. Een tellertje die elke seconde verhoogt wordt en als als de deelrest van teller//10 = 5 is naar het eeprom geschreven is. En dat doet preceis wat ik verwacht. Na het uit- en weer aanzetten begint hij bij de laatste waarde waar 5 in voorkwam (5,15,25,35...) Dus daar werkt het eeprom zonder problemen. Zodra ik weer even tijd heb ga ik proberen om de code vanuit de originele versie stuk voor stuk in die kale versie met alleen wat eepromgeschrijf/lees te zetten. Kijken of ik kan ontdekken waneer het lezen weer over de zeik gaat. Dan heb ik (we) in elk geval een kleiner stuk code waar toch een fout in zit... een stackoverflow sluit opzich aan bij het gedrag, maar ik kan niet vinden waar dat dan zou moeten gebeuren...

Ik geef in elk geval een gil als ik weer verder ben. En ik zal ook even proberen wat er gebeurt als ik die intcon.7 eerder aanzet (zo vroeg als dat kan in elk geval). Ik gebruik overgens timer 1 voor de interrupt.

Het uit/aanzetten van het GIE bit in de interrupt routine is zinloos; interrupts zijn niet re-entrant, dus automatisch geblokkeerd.
(beter de naam van het bit (GIE) gebruiken i.p.v. INTCON.7, dat begrijpt niemand zonder het eerst op te moeten zoeken in de datasheet)

Ook CONTEXT SAVE / RESTORE zijn zinloos bij de 16F1xxx processors en kunnen weg. (de processor doet dat zelf al hardwarematig bij iedere interrupt)
Als je een ander type processor gaat gebruiken, is het altijd het beste om eerst de datasheet even goed door te nemen...

Als je een interrupt afhandelt, moet je eerst testen waardoor die interrupt veroorzaakt is en dan pas die afhandelen.
(er kunnen tenslotte tientallen verschillende interrupts worden gebruikt die allemaal in dezelfde routine terechtkomen.)
Vervolgens moet je de interruptflag aan het eind van de interruptroutine weer resetten)

pic basic code:


InterruptHandler:

  If TMR1IF_bit Then
    ...
    ...
    ...
    TMRIF_bit = 0
  End If
Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com

@Arco, ik heb iets gelezen over high en low priority interupts (of woorden van gelijke strekking) vandaar dat ik het uit zet. Baat het niet dan schaadt het niet.

GIE of intcon.7. oké tot op zekere hoogte met je eens, maar ik moet zeggen dat de compiler die namen niet altijd herkent. Is me al een paar keer gebeurt. Vandaar dat ik gewoon het bitje zelf aanwijs.

De context restore en save: ik wist niet dat dat vanzelf ging, en geloof me:niet omdat ik de data-sheet niet doorgespit heb. Maar ik heb niet alle 300+ pagina's letter voor letter gelezen. Daarbij ben ik zeker geen held met interupts en heb ik dit gemaakt op basis van een voorbeeld waar die regels in stonden... Vandaar dat ik ze er ook in zet.

Bij een interupts moet je kijken waar het vandaan komt. Ook dit ben ik slechts deels met je eens. Als je meerdere interupts kan hebben dan absoluut mee eens. Was het een timer of een ingang? En afhankelijk daarvan zal je ook iets anders doen met de interupt... Ik heb echter maar 1 ding in mijn programma die een interupt kan geven en dat is de timer. Dus heeft het geen zin om te checken of dat van die timer af komt.

Je verwijst veel naar hoe dingen eigenlijk horen. En tuurlijk er is een goede en slechte manier om dingen te doen. 1000ms delay in een interupt verdient niet bepaald een schoonheidsprijs (om het zachtjes uit de drukken) maar wat ik met het verhaal hierboven probeer duidelijk te maken. Het is zeldzaam dat ik dingen programmeer zonder daar over na te denken. Dus de intcon IPV hoe, de delay in Dr interupt, het zijn geen willekeurige dingen. Ik heb daar bewust voor gekozen om het zo te doen.

En zoals je ziet reset ik de flag na het goed zetten van de preset.

Begrijp me niet verkeerd, ik ben blij dat jullie mee willen denken en sta zeker open voor ideeën. Maar als ik iets gedaan heb onderbouw ik graag even waarom ik het zo gedaan heb. En van mijn werk weet ik, iedere programmeur heeft zijn eigen stijl. Zelfs binnen onze standaard waar we altijd mee werken zie je duidelijk verschillen tussen iets dat ik of een collega gemaakt heeft. Dat wil niet zeggen dat het fout is. Alleen is de gedachtengang van de een niet die van de ander. Dus bouwd die het misschien anders op.

De pic16 familie heeft geen aparte hi/low priority interrupt routines (alleen de 18F familie heeft dit), maar slechts eentje, waar alles in terecht komt.
Zelfs al zou dat wel zo zijn, dan is er nog geen reden om interrupts uit te zetten (ze kunnen prima 'concurrent' worden uitgevoerd)

Het uit/aanzetten van interrupts gaat leiden tot verlies van interrupts. Misschien nu niet, maar wel later bij uitbreiding of grotere programma's.
(beter nu meteen de juiste methode aanleren. Is ook handiger als je later bestaande code wilt uitbreiden, dan hoef je niet eerst de 'fouten' eruit te halen)

De autosave context bij 16F1xxx is heel nuttig als je interrupts vaak aanroept, het spaart enorm veel processortijd.
Als een interrupt bijv. 50000x per sec. wordt uitgevoerd, dan spaar je met autosave ongeveer 550.000 instructies/sec uit! (save/restore kost zo'n 11 instructies)

Arco - "Simplicity is a prerequisite for reliability" - hard en software ontwikkeling: www.arcovox.com