EEPROM lezen/schrijven


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
hadv

Golden Member

Ik kan zo gauw de datasheet van dit device niet vinden, maar in de regel is het zo dat, in ieder geval bij 16F, dat je, om een timer1 interrupt te krijgen, je ook het PEIE-bit van INTCON (bit6) op 1 moet zetten.

@Daan: het aanzetten van het GIE bit kan inderdaad beter vlak voor de eerste code.
Het feit dat de compiler alleen 'GIE' niet herkent is omdat dit geen SFR is, maar een bit in een SFR. Voor dit device is geen bitnamefile gemaakt, dus het klikken op het device in de code explorer levert niets op. Je kunt zelf een bitnamefile maken, ik heb daar een tool voor gebouwd, te vinden op de Crownhill site. Daar kun je ook de fuse configurator van JohnGB vinden. Dit is zo ongeveer de handigste plugin die ik ken.

Overigens is de opmerking van Arco over autosaving op zijn plek, want het gebeurt nu twee keer: één keer door de PIC en één keer in de code. Of het op zich veel sneller is dan de software save/restore denk ik dat dat wel meevalt. Uiteindelijk gebruikt autosaving ook hulpvariabelen.
Of je echt interrupts kwijtraakt met aan/uitzetten durf ik niet te zeggen.

Just find out what you like and let it kill you

De autosave/restore feature is geheel hardwarematig en kost geen extra clockcycles.
Bijv. RETFIE doet meteen een restore en gebruikt toch maar 2 cycles. (zelfde als bij 'oude' PIC16's zonder auto-restore)
Geeft dus een enorme winst aan cycletijd... (de stack wordt hier niet voor gebruikt, maar een aparte geheugenpage waar de boel wordt gekopieerd)

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

Ik weet niet hoe groot je stack is maarbij de oudere pics weet ik dat die relatief klein is. Een "hserout" kan zomaar tig functies weer aanroepen waardoor je je stack "opblaast".

Verder over timing die je "correct" wilt houden: Dat is geen excuus om alles in de interrupt handler te prakken.

Wat je in zo'n geval beter kunt doen is de waarde + timer clock SAMEN opslaan in een buffer. In de main loop reken je dan alles uit.

Hoe je precies aan de tijd in je ISR komt is even een ander verhaal, je kunt een hardware timer maken die je laat tellen op een bepaalde clock rate en die zou je kunnen lezen in de ISR. Hoe je dat in picbasic moet doen weet ik effe niet. Zule je zelf moeten maken.

Dus de ISR hoeft alleen dit te doen:

code:


Int-hander 
   lees waarde
   lees timertick
   store beide in fifo of ringbuffer oid
   incrementeer een "werk todo counter"
ret from isr

In de main loop ga je wachten op de "werk todo counter" of die > 0 wordt en dan reken je alles uit wat je moet doen etc. dan decrementeer je die werk counter en wacht je weer.
Kijk/zoek even naar de uitleg/werking van "counting semaphores". Zoiets zul je moeten maken in picbasic (of misschien heeft die daar wat voor).

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

@ Arco: Ah ja het zou kunnen dat ik dat hi/low gezien heb in een 18F. Ik gebruik onderandere ook de 18F4520. Ik gooi de interupt uit om te voorkomen dat tijdens het afwerken van de interupt er nog een interupt komt. Omdat dat zooi geeft. Ik heb er inderdaad niet bij stil gestaan dat eigenlijk dus betekend dat ik potentieel interupts mis. Ik had bedacht dat het dus gewoon een kwestie is van de Interupthandler kort genoeg houden... maar dat heeft eigenlijk het zelfde effect als de interupt gewoon aan laten staan. Betekend dat dan ook dat ik de flag en preset helemaal in het begin van de interupthandler moet doen?

Haha ja met 50000 keer per seconde tikt dat aan. Ik zit op 10 keer per seconde. Dus dat valt nogal mee. Maar ik snap wat je bedoeld. Het is intussen ook uit de code ;)

@hadv: Hm, dat is vreemd die set ik namelijk niet (ook niet elders) en de interupt komt wel gewoon... in de datasheet staat het volgende:
bit 6 PEIE: Peripheral Interrupt Enable bit
1 = Enables all active peripheral interrup

Peripheral vertaal ik grofweg naar omgeving. Ik nam aan dat dat betekende interupts van IO, of iets dergelijks, zegmaar de "externe" interupts... Wat bedoel je met een SFR? Ik begrijp uit de rest van je verhaal dat er voor (sommige) chips een appart bestand is waar dingen als GIE gedefinieerd wordt en verwezen wordt naar het eigenlijke adres?
Wat betreft autosaving en interupts kwijtraken, zie het verhaal hierboven aan arco ;).

@henri62: De stack die ik zelf maak valt opzich wel mee. 1, hooguit 2, niveau's 2,3 als ik de interupt mee tel. Dus dat is niet zo spannend, ik heb wel heel veel meer gedaan (denk 6,7) met daar nog een hserout in. Al denk ik wel dat dat in een 18F was. Maar als het toch een stackoverflow is reset de hele chip... dan zou ik verwachten dat alle code (dus ook de hserout met de initialisatie) opnieuw uitgevoerd wordt, niet alleen de eread.
De berekeningen heb ik uit de interupt gehaald. het enige is nu dat servo verhaal. Dat kan ik inderdaad ook met een bitje in de interupt aangeven en dan in de hoofdlus uitvoeren. Maar ALS die situatie optreed wil ik dat de stroom vrij vlot uitgeschakeld wordt. En met de serin in de hoofdlus kan dat rustig een seconde zijn voor de hoofdlus. En wat ik zei, als die code aangeroepen wordt intereseert timing me geen fluit meer. Als die accu maar los gaat.
Ik moet eerlijk zeggen dat ik de rest van je verhaal niet helemaal volg. Begrijp ik goed dat ik eigenlijk zeg "op die en die tijd was de stroom zoveel" zodat ik dus ook met de tijd kan rekenen?

De ISR (neem even aan dat dat de interupthandler is ;)?) doet nu eigenlijk het volgende:
Seconde teller verhogen (equivalent van bitje hoog zetten wat een functie in de hoofdlus aftrapt)
analoge signalen binnen halen
de ruwe waarde daarvan vergelijken met een getal (Dus alleen maar twee dword's met elkaar vergelijken, geen lopend gemiddelde meer, geen omrekeninen naar floats).
Preset goed zetten
flag resetten
terug naar hoofdlus

Ik zal eens gaan zoeken naar counting semaphores. Nooit van gehoord maar ik ga even googlen ;).

Voor iedereen die de datashit niet kon vinden, bij deze ;)
http://ww1.microchip.com/downloads/en/devicedoc/40001574c.pdf

EDIT: Ik ben intussen nog stukje voor stukje aan het kopieren naar een project met wat eeprom lezen/schrijven. Kijken wanneer het er mee ophoudt. Ik heb de context save/restore er uit gehaald. En onderaan vervangen door een "return" maar dan voert hij de interupt maar 1 keer uit. Hij komt wel terug in de hoofdlus. Maar de interupt komt maar 1 keer. Weet je zeker dat die er niet in hoeven. Ik heb in de datasheet even gezocht en daar staat wel dat het automatisch gebeurt (saven en restoren). Moet ik soms iets anders dan return er onder zetten..?

PS: stack is 16 levels. Dus ik kom nieteens in de buurt (levels die de hserout bijv gebruikt even niet meegerekend)

Op 13 november 2018 21:50:28 schreef DaanSteeman:

Peripheral vertaal ik grofweg naar omgeving.

Niet alles gelezen, maar... Peripheral in deze context is eerder iets als "randapparaat". In een PIC is het dan een "ingebouwd randapparaat". Dus denk aan een "uart module".

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

Golden Member

Gebruik Retfie ipv Return. Retfie is speciaal voor interrupts. In tegenstelling tot een return, die is voor subroutines.

SFR: Special Function Register. Dit zijn geheugenplaatsen die zijn toegewezen aan specifieke taken zoals bijvoorbeeld het instellen van een Timer, UART of ADC en natuurlijk INTCON, PIE en PIR.

Peripheral is 'normaal' een randapparaat, maar binnen een PIC is het in grote lijnen alles dat niet mbv het INTCON register kan worden afgehandeld. Dat kan van alles zijn, ook Timer1.

Dat de interrupt wordt doorlopen is op zich vreemd, maar je kunt er wat aan doen:
na het declareren van je variabelen neem je een regel op met 'Goto Init'.
na deze regel voeg je de interrupthandler toe
en daarna dus een regel 'Init:'

Just find out what you like and let it kill you

Oke voor de tweede keer dat ik dit schrijf... op "nee ik wil niet de rechter balk verwijderen bij een resolutie kleiner dan whatever" klikken zorgt er voor dat je text ook meteen verdwijnt...

Peripheral betekend dus in dit geval een andere module in de chip die niet de CPU is eigenlijk. Duidelijk.

Retfie heb ik geprobeerd. Dan blijft hij rond fietsen in de interupthandler. Hij springt niet meer naar de hoofdlus. Momenteel staat er dus nog context save/restore.

Dat de interrupt wordt doorlopen is op zich vreemd, maar je kunt er wat aan doen:
na het declareren van je variabelen neem je een regel op met 'Goto Init'.
na deze regel voeg je de interrupthandler toe
en daarna dus een regel 'Init:'

Het over subroutines springen met goto ken ik wel. Het probleem was ook niet dat de routine doorlopen werd bij het opstarten. Hij werd maar 1 keer afgetrapt. Alsof ik na die ene keer de interupt uit zette (wat uiteraard niet zo was).

Dat gezegd hebbende. HET WERKT!?!? Ik snap alleen niet waarom. Ik heb de twee versies naast elkaar gelegd. Het enige verschil dat ik kan vinden is (afgezien van wat onbelangrijke dingen) dat ik bij de huidige versie met edata de eepromadressen die ik gebruik na het programeren op 0,000 zet. Ipv gewoon FF te laten tot ik er de eerste keer in schrijf. Maar volgensmij zou dat geen bal uit moeten maken. De eerste keer leest hij dan volkomen onzin uit het eeprom. Maar dat wordt na 1 keer meten gewoon overschreven in het normale programma en na 5 min in het eeprom geschreven voor de volgende keer.

Hoe dan ook, ik heb de interupthanlder helemaal uitgekleed. Het is nu eigenlijk alleen nog een counting semaphore (ja ik heb zitten googlen ;)). Die in de hoofdlus het rekenwerk aftrapt. Nu heb ik alleen weer het probleem dat mijn teller niet op 9 komt, het rekenwerk aftrapt en dan weer op 0 gezet wordt. Nu loopt de teller tot 23 op waardoor mijn seconde bijna 2,5 seconde duurt en er dus van mijn berekening in Wh niks klopt.... Heeft iemand enig idee hoe ik dat dan een beetje netjes op kan lossen (dus zonder het rekenwerk gewoon maar weer in de interupthandler te kwakken)?

Op 11 november 2018 23:07:19 schreef DaanSteeman:

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]
; Je zou zoiets kunnen maken. Als secondeteller te hoog is, bijv 23 dan wordt
; bovenstaande berekening gewoon 2x achter elkaar uitgevoerd en de 3 wordt
; bewaard totdat er weer (meer dan) 0,7 sec verstreken zijn
;  Secondeteller = 0                    ; was
  Secondeteller = Secondeteller - 10   ; moet worden
  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                   ; zie commentaar boven, 
  Vijfminteller = Vijfminteller - 300
; Ik denk toch dat bovenstaande niet hoeft. Het heeft weinig zin om een
; aantal keren strak achter elkaar dezelfde Hoogstesom weg te schrijven in
; EEhoogstesom. De 5-minutencoordinatie klopt niet helemaal. Het is niet
; meer precies 5 minuten
EndIf

  INTCON.7 = 1
Context Restore

End


Bezoek mijn neefjes' site: www.tinuselectronics.nl

Ik weet niet hoe die ERead en EWrite functies werken, maar vaak keert dat soort functies na uitvoer direct terug, zonder te wachten tot read/write compleet is.
Je moet dan tussen writes en reads een korte delay doen van 5mS ofzo, anders gaat het geheid mis. (de ene is nog bezig als je de andere aanroept)

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

@Ohm pi: JUIST.... die tip had ik even nodig. Dat lijkt me inderdaad een prima oplossing. Ik tel gewoon hoe vaak de interupt gebeurt is. Als dat 5 keer is gebeurt is er dus 0,5seconde voorbij sinds de vorige keer. Als dat 200 keer is is er dus 20 seconde voorbij sinds de vorige keer. Dan klopt de Wh weer, en ik tel simpelweg dat aantal secondes op bij de vijfminteller zodat die ook weer klopt.

Ik snap alleen even niet wat je bedoeld met

; Ik denk toch dat bovenstaande niet hoeft. Het heeft weinig zin om een
; aantal keren strak achter elkaar dezelfde Hoogstesom weg te schrijven in
; EEhoogstesom. De 5-minutencoordinatie klopt niet helemaal. Het is niet
; meer precies 5 minuten

Het was inderdaad geen 5 minuten. Met de bovenstaande aanpasseningen zou dat wel weer moeten kloppen (hoewel die 5 minuten niet kritisch is. Het betekend alleen maar dat wanneer de spanning uit gegooit wordt ik iets meer of minder tijd aan gegevens kwijt ben. Maar 5 minuten op periodes van weken dat dit ding aan staat is totaal insignificant. Dus dat is geen punt.
Maar ik schrijf uberhaupt nooit de zelfde hoogstesom weg. Als die veranderd is (wat tijdens het leren van de capaciteit continue is, maar daarna alleen maar gebeurt als de accu helemaal vol is, of helemaal leeg is) schrijf ik hem naar het eeprom. Zo niet schijf ik ook niks om het eeprom een beetje te sparen.

@Arco: dat zou ik eerlijk gezegd niet weten. In de manual staat dat ewrite tot wel 5mS kan duren per byte. Dus dat is inderdaad behoorlijk lang. Maar ik zou eens moeten uitproberen wat er gebeurt als ik de delay er tussen gooi... Eread zou in elk geval een stuk sneller zijn.

Als je na een write meteen een read doet is de eeprom nog niet klaar daarmee. Je krijgt random 'rommel' te zien.

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

Op 17 november 2018 10:37:10 schreef DaanSteeman:
..
Ik snap alleen even niet wat je bedoeld met [...]
..

Originele 5-minutencode is goed. Daar hoef je de truc om 300 er van af te trekken niet toepassen. Foutje van mij.

Bezoek mijn neefjes' site: www.tinuselectronics.nl

Op 17 november 2018 12:14:39 schreef Arco:
Als je na een write meteen een read doet is de eeprom nog niet klaar daarmee. Je krijgt random 'rommel' te zien.

Dank voor de reminder dat ik NOOIT meer met PICs te maken wil hebben. Iedere zinnige CPU stopt dan totdat de write klaar is en geeft de verwachte resultaten. de handleiding zegt dan: Je moet niet van de eeprom/flash lezen als je niet wilt dat de boel ineens stopt.

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

De hele CPU stoppen tot een write compleet is, is onzinnig en onwerkbaar... (in meeste applicaties kun je de boel niet zo lang bevriezen)
Het wordt aan het gezonde verstand van de programmeur overgelaten om geen read/writes te doen zolang de vorige niet klaar is.
(je kunt trouwens simpel testen of de write compleet is)

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

Golden Member

Misschien is het handig om de datasheet eens door te lezen (waar Arco wellicht ook al op hint). Daarin staat beschreven hoe je op het schrijven van de eeprom moet wachten.
Dan kom je er ook achter dat het echt niet zo erg is als rew zegt en dat je dus niet tot zulk soort over the top conclusies komt.

Uit het PicBasic manual: writing can take op to 10ms per byte.

Als je een .lst van de basic compiler bekijkt zie je ook dat deze keurig gebruikt maakt van de daartoe aangewezen registers en loopt tot de verschillende bits de juiste waarde hebben.

Conclusie: in PicBasic kun je gewoon een EWrite doen zonder zelf allerlei delay acties uit te voeren.

Just find out what you like and let it kill you

In Mikrobasic wat ik gebruik keert de routine meteen terug na een read/write; wachten moet je zelf doen.
Ook wel prettig: kun je ondertussen wat anders doen... (10mS is een eeuwigheid voor een microcontroller... :) )

Erg vaak gebruik ik het niet meer, want de meeste nieuwe pics hebben geen eeprom meer...

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

m.i. is het dom om een CPU te ontwerpen die "onjuiste resultaten" kan geven als je niet lang genoeg gewacht hebt na het schrijven van een eeprom.

Als ik een taal ontwerp met +, -, * en / met de gebruikelijke betekenis, dan -= trek van huidige waarde af, *=, vermenigvuldig huidige waarde met .. , maar dan ineens met += een logisch or beschrijf, dan heb je iets wat een verrassing veroorzaakt bij mensen die enigszins weten waar ze mee bezig zijn en extrapoleren van bestaande patronen, maar niet voor 100% de handleiding lezen.

Zo dus ook met het stopzetten van de CPU danwel gewoon foute resultaten geven. Wie trapt er in en heeft er last van de ontwerp beslissing om het op de ene of de andere manier te doen?

Volgens mij is het "m'n timing klopt niet meer, die stomme CPU is 9 ms gaan wachten om de eeprom read af te maken." een geavanceerde gebruiker die je makkelijk kan opzadelen met "had je maar het registertje moeten checken of de write al klaar is". De beginner die niet tijd-kritisch gewoon de 10ms delay accepteert krijgt tenminste betrouwbare resultaten.

Geef je onbetrouwbare resultaten, dan zadel je de beginner die niet de tijd of kapstok heeft om de handleiding in 1x goed te kunnen lezen op met een onverwacht resultaat.

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

Zo lust ik er nog wel een paar... :)
Zelfde geldt voor A/D converter, I2C,... (als je bij A/D niet de vereiste aquisition wachttijd in acht neemt krijg je ook onjuiste resultaten.)

Programmeur wordt geacht enige moeite te hebben gestoken in het leren van de werking van de betreffende processor.
Wat betreft de eeprom: je kunt simpel een bit afvragen om te zien of een write klaar is.

De processor geeft geen 'onbetrouwbare' resultaten terug, de 'programmeur' heeft geen idee waar 'ie mee bezig is dan...

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