Timer0 och interrupt i en PIC16F887

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
nibman
Inlägg: 17
Blev medlem: 30 mars 2010, 18:30:19

Timer0 och interrupt i en PIC16F887

Inlägg av nibman »

Hej!

Jag har försökt få igång Timer0 som skall generera interrupt i en PIC16F887, men det bara vägrar komma igång, trots idoga försök och tester. Kan någon se vad jag har gjort fel?

Jag har försökt korta ned min kod till ett minimum och hoppas att ingen tar illa upp att jag klistrar in den här.

Jag förväntar mig att pinne RC7 skall gå hög, men det händer aldrig.

Sedan om någon kan upplysa mig om NÄR jag måste använda mig av banksel så vore jag glad. Har försökt hitta information som beskriver detta, men har gått bet på det än så länge. Jag har i varje fall märkt att om jag inte lägger en banksel framför förändring av egna variabler så fungerar inte MPLAB SIMs watch för lokala variabler om jag dessförinnan har ändrat något register som t.ex. PORTA, TRISC eller liknande. Jag förmodar också att användning av banksel på det sätt jag gör nedan är felaktigt, eller kanske snarare onödigt? :oops:

banksel TRISA
clrf TRISA
banksel TRISC <-- den här är onödig??
clrf TRISC

Tack för hjälp som tar mig vidare...

Här är min felande kod:

Kod: Markera allt

; ==============================================================
	list p=16f887
	include <p16f887.inc>


	__CONFIG _CONFIG1, _BOR_OFF & _XT_OSC & _DEBUG_OFF & _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_OFF & _WDT_OFF
	ERRORLEVEL	0,	-302	;suppress bank selection message
; ==============================================================
	cblock	0x20

	count
	count1
	counta
	countb

	flags

	Count1us
	Count10us
	Count1ms
	Count100ms

	W_SAVE
	STATUS_SAVE
	PCLATH_SAVE

	endc

; ==============================================================
	org	0x00
	goto StartProgram
	org 0x04
	goto InterruptServiceRoutine

; ==============================================================
	include "delay.inc"
; ==============================================================
StartProgram
	call InitPorts
	call InitInterrupt
again
	bsf PORTC,0
	call delay1s
	bcf PORTC,0
	call delay1s
	goto again

; ==============================================================
InitPorts
	banksel ANSEL
	clrf ANSEL
	clrf ANSELH

	banksel PORTA
	clrf PORTA
	banksel PORTB
	clrf PORTB
	banksel PORTC
	clrf PORTC
	banksel PORTD
	clrf PORTD
	banksel PORTE
	clrf PORTE

	banksel TRISA
	movlw 0xFF
	movwf TRISA
;	clrf TRISA
	banksel TRISB
	clrf TRISB
	banksel TRISC
	clrf TRISC
	banksel TRISD
	clrf TRISD
	banksel TRISE
	bsf TRISE,0
	bsf TRISE,1
	bsf TRISE,2
	bsf TRISE,3
	return

; ==============================================================
InitInterrupt
	clrwdt
	banksel OPTION_REG ; Change prescaler from WDT to TMR0
	movlw b'11110000'
	andwf OPTION_REG,W 	
	iorlw b'00000111'
	movwf OPTION_REG

	banksel INTCON
	bcf INTCON,T0IF
	bsf INTCON,T0IE ; start Timer0 interrupt
	bsf INTCON,GIE ; start general interrupt
	return
	
; ==============================================================
InterruptServiceRoutine
	movwf W_SAVE ; Save W
	swapf STATUS,F ; Save STATUS
	swapf STATUS,W
	movwf STATUS_SAVE
	movfw PCLATH
	movwf PCLATH_SAVE
	; =======

	banksel PORTC
	bsf PORTC,7

	; =======
	banksel INTCON
	bcf INTCON,T0IF
	bsf INTCON,T0IE
	bsf INTCON,GIE

	movfw PCLATH_SAVE
	movwf PCLATH
	swapf STATUS_SAVE,F ; Restore W & Status
	swapf STATUS_SAVE,W
	movwf STATUS
	swapf W_SAVE,F
	swapf W_SAVE,W
	retfie
	
; ==============================================================

	end
Senast redigerad av nibman 30 mars 2010, 19:21:56, redigerad totalt 2 gånger.
v-g
EF Sponsor
Inlägg: 7875
Blev medlem: 25 november 2005, 23:47:53
Ort: Kramforce

Re: Timer0 och interrupt i en PIC16F887

Inlägg av v-g »

Först och främst använd CODE taggarna (dvs redigera ditt inlägg).

Därefter är det bra att använda den färdiga templaten som finns i MPLAB, den har en bra layout tycker jag.

Sen ett tips är att skriva (tex) BSF INTCON, GIE så ser man direkt vad det är du försöker göra.

BANKSEL används då du byter bank, i vilken bank saker och ting finns står i databladet, den bästa översikten tycker jag är den med 4 kolumner.
nibman
Inlägg: 17
Blev medlem: 30 mars 2010, 18:30:19

Re: Timer0 och interrupt i en PIC16F887

Inlägg av nibman »

Redigerat, nu med CODE tag.

Färdig template, hur hittar jag den i MPLAB?

Jo, jag hade GIE osv tidigare, men i mina idoga försök att hitta orsaken till felet med min kod blev det till att jag satte bitnumret istället. Jag redigerar igen. :-)

Jo jag har läst om banker när det kommer till bank0 till 3, men jag uppfattade det som om detta endast gällde programkoden när den överstiger de 2048 bytes som varje bank är i storlek, men där hade jag också fel då? Jag kan ju se i disassembly listing att en banksel motsvarar bsf/bcf 0x3,0x5 och bsf/bcf 0x3,0x06 och då är frågan är det detsamma som STATUS,RP0 och STATUS,RP1 ??
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Timer0 och interrupt i en PIC16F887

Inlägg av Icecap »

Jepp, du har fel. Banksel används när man ska adressera de olika minnesbankar, t.ex. ligget TRISx på samma adress som PORTx fast i en annan bank.
Rocky_AL
Inlägg: 617
Blev medlem: 7 december 2006, 15:14:50
Ort: Stockholm

Re: Timer0 och interrupt i en PIC16F887

Inlägg av Rocky_AL »

För att få ändra en variabel/byte i bank X så måste du först se till att du är i bank X. T.ex. om du ändrar på PORTA och sedan vill ändra något i TRISA så måste du byta bank först (t.ex. genom att skriva: BANKSEL TRISA)

Edit: För sen...
nibman
Inlägg: 17
Blev medlem: 30 mars 2010, 18:30:19

Re: Timer0 och interrupt i en PIC16F887

Inlägg av nibman »

Ok, tack!

Då är jag nästan säker på hur banksel används. :-) Enda saken som gör mig fortfarande konfunderad är varför jag måste använda den för att addressera mina egna variabler, vilken bank ligger de i? Ligger de i bank 0, titta på min kod ovan?

Sedan har ingen nämnt något om varför mitt försök att få igång ett timer0 interrupt har misslyckats, huvudorsaken till att jag gör ett inlägg här på elektronikforum, som för övrigt är en mycket god kunskapskälla. Vad gör jag fel?
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Timer0 och interrupt i en PIC16F887

Inlägg av Icecap »

Sannolikt har du inte skrivit rätt värde i rätt register, kolla detta med banksel. Har du testat efter att du har använd banksel?
v-g
EF Sponsor
Inlägg: 7875
Blev medlem: 25 november 2005, 23:47:53
Ort: Kramforce

Re: Timer0 och interrupt i en PIC16F887

Inlägg av v-g »

Du kan dels välja att lägga variablerna i ACCESSminnet då får du tillgång till dem oavsett var du är bankad annars väljer du bank lämpligen i .map filen.

Problemet:

Först och främst funderar jag varför du inte använder MOVWF när du sätter option_reg?

Dessutom borde du ta och kolla varför T0CS BIT:en är satt, (tips: sätt den låg annars måste du klocka in en signal på T0CKI) <-- detta tror jag är felet.

För att göra det extra tydligt för dig och ALLA gör som följer:

Kod: Markera allt

CLRF OPTION_REG ;Nollar registret
BSF OPTION_REG, INTEDG
BSF OPTION_REG, T0SE
osv osv
nibman
Inlägg: 17
Blev medlem: 30 mars 2010, 18:30:19

Re: Timer0 och interrupt i en PIC16F887

Inlägg av nibman »

Varför jag inte väljer det sätt du säger är för att i processorns manual så står det på sida 74 ruta "Example 5-2" att man skall följa det sätt som beskrivs där, för att undvika en icke önskade reset. Men säger du att man kan undvika detta genom det sätt du skriver, så skall jag givetvis testa det. :-)

Tack för svaret!
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Timer0 och interrupt i en PIC16F887

Inlägg av sodjan »

Hm, du har väl fått svar på det mesta. Dock ibland via lite omvägar och i
något fall på gränsen till felaktigt, så får du lite svar till här... :-)

> BANKSEL används då du byter bank,...

Nja, BANKSEL använder man för att *slippa hålla reda på* vilken bank
som saker och ting (FSR och GPR) befinner sig ! Alltså inte att man säger
att "nu ska jag byta bank, alltså använder jag BANKSEL". Man behöver inte
*veta* när man byter bank, det är det som är hela "grejen" med BANKSEL !

> i vilken bank saker och ting finns står i databladet,...

Jo, ja, det gör det i och för sig, men finessen med BANKSEL är att man inte behöver veta det !

Sen så finns det en massa optimeringar man kan göra (om det finns behov av det)
genom att själv kolla var saker och ting ligger och utesluta BANKSEL där man är helt
säker på att det inte behövs. Men det gör man när allt fungerar, inte om man har
problem och inte vet vad det beror på... :-) Så från start så är det lika bra (säkrast)
att lägga en BANKSEL före varje access av en SFR eller GPR/variabel.

> Färdig template, hur hittar jag den i MPLAB?

Katalogen ".../templates/...".
Jag tror även att det är dokumenterat i MPLAB eller MPASM manualen
har jag för mig (öppnar 51519C.PDF....) japp, i kapitel "15.6 FILE LOCATIONS"
i "MPLAB IDE User’s Guide" är det dokumenterat !

> Jo jag har läst om banker när det kommer till bank0 till 3, men jag uppfattade det
> som om detta endast gällde programkoden när den överstiger de 2048 bytes som
> varje bank är i storlek, men där hade jag också fel då?

Du blandet i hop två helt olika saker !
*Banks* är det som RAM (FSR och GPR) är uppdelat i. Hanteras av BANKSEL.
*Pages* är det som programminnet är upp uppdelat i. Hanteras av PAGESEL.
Läs på i kapitlet om minne i databladet, jag är helt säker på att just detta är
*väldigt* bra dokumenterat !

> Jag kan ju se i disassembly listing att en banksel motsvarar bsf/bcf 0x3,0x5 och
> bsf/bcf 0x3,0x06 och då är frågan är det detsamma som STATUS,RP0 och STATUS,RP1

Ja, det är det. BANKSEL är ett inbyggt macro i MPASM som genererar BCF/BSF STATUS RP0/1
beroende på var (i vilken bank) den önskade SFR (eller GPR/variabeln) befinner sig. BANKSEL
gör alltså exakt samma sak som om du själv skulle sitta och slå upp varje register i
databladet, kolla vilken bank det ligger i och sedan själv skriva rätt BSF/BCF STATUS RP0/1
instruktioner. Men eftersom ett register inte hoppar runt kring bankerna så där utan vidare,
så är det ju någon som med fördel automatiseras, alltså BANKSEL...

> ...Enda saken som gör mig fortfarande konfunderad är varför jag måste använda den för
> att addressera mina egna variabler, vilken bank ligger de i?

Poängen är att du inte behöver veta det ! MPASM ser till att du accessar rätt bank via BANKSEL.
Nu (i just ditt programexempel) så har du ju hårdkodat adresserna vid CBLOCK, så då vet du
ju det. I modern kod allokerar man variabler via RES och då överlämnar man (inom vissa gränser)
det till länkaren (MPLINK) att bestämma var (i vilken bank och på vilken adress) variablerna
ska hamna, det är ju inget som man normalt har något intresse av i alla fall...


> Du kan dels välja att lägga variablerna i ACCESSminnet

Desinformation... Det finns ingen "Access bank" på en PIC16 !

Motsvarande på en PIC16 kallas "unbanked memory" eller "shared memory"
(även om databladet kanske inte använder just det utrycket, men det är
det namnet/namnen som normalt används för detta minnesområde).

På en 16F887 så är det de sista 16 adresserna i varje bank, h'70'' - h'7F'.
Man kan med fördel lägga de variabler som man accessar ofta just där för att
vinna lite prestanda (BANKSEL behövs då inte före dessa variabler).
Notera att MPASM manualen är lite "otydlig" kring just detta i beskrivningen
av BANKSEL, där står : "This directive may be used with all PIC1X devices.
This directive is not needed for variables in access RAM (PIC18 devices.)".
Det är alltså inte heller nödvändigt att använda BANKSEL för variabler i
"shared/unbanked memory" på en PIC16...


> så står det på sida 74 ruta "Example 5-2" att man skall följa det sätt som
> beskrivs där, för att undvika en icke önskade reset.

Så vitt jag förstår, efter en snabb koll, så har det där med att göra att man
kan få ett "falsk" WDT-avbrott (reset) just när man switchar prescalern mellan
Timer0 och WDT timern. Men, å andra sidan, så har du ju _WDT_OFF i din
__CONFIG, så du kommer ju i alla fall aldrig att få ett WDT avbrott eftersom
du (sannolikt helt rätt) har valt bort det. Alltså behöver du inte ta det som
står kring example 5-2 så hårt, om jag tolkar det korrekt.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Timer0 och interrupt i en PIC16F887

Inlägg av sodjan »

Bara ett litet tillägg när det gäller koden som "inte fungerar"...
Det tycker jag på sätt och vis (i alla fall för min del :-) )
är mindre intressant, det borde vara snabbt att åtgärda
via t.ex MPLAB/SIM och databladet...
nibman
Inlägg: 17
Blev medlem: 30 mars 2010, 18:30:19

Re: Timer0 och interrupt i en PIC16F887

Inlägg av nibman »

Jag har nu testat och flaggan T0CS gjorde skillnad, nu går pinne RC7 hög, men... slingan i början av programmet kör inte längre, precis som om interruptet aldrig återvänder. Med "slingan i början av programmet" syftar jag på den oändliga loop som "goto again" åstadkommer.

Vad mer kan vara fel? Är det måhända banksel som spökar igen? Vad banksel "pekar på" efter avslut av interruptet (om det nu avslutas) bör ju vara INTCON som är det sista som jag väljer i interruptet. Skall man spara undan denna vid början av interruptet också?

Utöver detta, vad är accessminnet? Är det eepromminnet du syftar på, vilket jag inte tror på egentligen, utan det borde vara ett RAM-minne? Hur gör man access till det?

Det känns som om jag läser fel datablad för processorn då jag trots allt har plöjt igenom databladet och har ändå inte något minne om att jag läst något om Accessminnet. Det jag har är en PDF på 328 sidor, som behandlar 882 till 887 processorn. Namnet på den är "PIC16F882/883/884/886/887 data sheet", korrekt?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Timer0 och interrupt i en PIC16F887

Inlägg av sodjan »

Kör koden i SIM och se vart den "tar vägen".

> Är det måhända banksel som spökar igen?

BANKSEL kan inte "spöka". Bara avsaknaden av BANKSEL.

> Vad banksel "pekar på" efter avslut av interruptet

BANKSEL "pekar" aldrig på någonting. Du har inte läst mitt inlägg.
Gör det !!

> Skall man spara undan denna vid början av interruptet också?

BANKSEL sätter/clearar bitar i STATUS, och det sparar/återställer du redan.

> Utöver detta, vad är accessminnet?

Som sagt, läs mitt inlägg !!

> Namnet på den är "PIC16F882/883/884/886/887 data sheet", korrekt?

Ja.

EDIT: Ser nu att du postade nästan samtidigt med mig, men å andra sidan
så borde du ha upptäckt det när du använde "Förhandsgranska" och då borde
du ha kollat mitt inlägg innan du "tryckte in" ditt inlägg...
nibman
Inlägg: 17
Blev medlem: 30 mars 2010, 18:30:19

Re: Timer0 och interrupt i en PIC16F887

Inlägg av nibman »

Sodjan, tack för ditt utförliga svar!

Jag är nybörjare på programmering av PIC-processorer, men det har du säkert redan gissat. Det här med bankswitch är inte riktigt min melodi och det är nog orsaken till att jag gick över från assembler till C en gång i tiden när jag skaffade min första PC, Intel 80x86 processorn håller ju på med samma sak om jag inte missminner mig. Jag körde dessförinnan assembler på Atari ST och innan dess på Commodore 64, men det är MÅNGA år sedan. Det var i dessa maskiner ett helt linjärt minne utan någon bankswitchning som gjorde det enkelt att programmera. Man kunde lägga krutet på att få en bra och optimerad kod utan att behöva fundera på banker hit o dit.

Jo, banksel underlättar, det förstår jag. Men jag har tydligen missuppfattat hur minnet verkligen är organiserat. Var finns RAM-minnet? Jag är ju van vid att programminne och RAM-minne är samma sak, i denna processor är det väl inte så, utan RAM-minnet är utspritt lite varstans och det är upp till linkern att utnyttja det på optimalt sätt. Har jag förstått rätt då?

Jo, jag har letat kodexempel på nätet och i manualen för processorn och det jag har gjort är att kopiera de bitar som ser ut att göra det som jag önskar, exv. placering av mina variabler. Jag förstod att det var en statisk allokering i och med att jag skrev CBLOCK 0x20, men det var bara kopierat från andra exempel då jag försöker lära mig syntax generellt. Jag vet inte hur syntax ser ut för att icke statiskt allokera utrymme för variablerna, RES nämner du, har redan letat efter någon sorts beskrivning på det, men gått bet än så länge...

Jag har hittills endast läst manualen för processorn, trodde att det skulle räcka utöver de kodexempel jag har letat upp på nätet. Några pointers i rätt riktning över vilken dokumentation jag bör läsa skulle underlätta, speciellt om syntax för diverse moment i MPLAB. Jag skall givetvis gå raka vägen till Microchips hemsida och söka dokumentation som rör syntax i MPLAB.

Tro mig, jag har tittat flera (läs riktigt många) gånger i databladet och min egen kod fram och tillbaks för att sätta bitarna rätt för Interrupt och Timer0, men ändå blev det fel på en bit. Det första man blir blind på är ögonen. :-)

Att MPLAB/SIM skulle kunna hjälpa mig med interrupt visste jag inte. Den simulerar väl inte processorn så långt? Jag har sett att man kan injicera data i register osv efter något slags schema, men har inte haft möjlighet att titta mer på det än. Har bara hållt på med detta några få timmar än, när ledig tid har infunnits.

Tack allihop för hjälpen så långt...
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Timer0 och interrupt i en PIC16F887

Inlägg av sodjan »

Jag tror att jag ser en "bugg" i din kod...

W_SAVE, STATUS_SAVE och PCLATH_SAVE *måste* ligga i "unbanked/shared memory" !

Problemet är ju att din kod (eller igentligen processorn) inte vet vilken bank
som för tillfället råkar vara vald (via RP0/1 bitarna) just när interruptet inträffar,
och alltså måsta *_SAVE variablerna ligga i ett minnesområde som *ALLTID*
går att komma åt, oavsett hur RP0/1 är satta. Med på det ?

Du får avsluta ditt CBLOCK med dina "vanliga" variabler och börja en ny med t.ex :

Kod: Markera allt

    cblock     h'70'
    W_SAVE
    STATUS_SAVE
    PCLATH_SAVE
    endc
> ...Det var i dessa maskiner ett helt linjärt minne utan någon bankswitchning...

Notera att den nya PIC16 serien ("Enhanced Mid-Range") har delvis löst detta
genom att även mappa allt minne till en linjär adressarea.
http://www.microchip.com/stellent/idcpl ... odeId=2692

> Jag är ju van vid att programminne och RAM-minne är samma sak,

I "Von Neumann" arkitekturer är det det. Många mikrokontrollers (som t.ex PIC och AVR)
har en "Harvard" arkitektur där program och dataminne har separata adressareaor.
http://en.wikipedia.org/wiki/Von_Neumann_architecture
http://en.wikipedia.org/wiki/Harvard_architecture

> utan RAM-minnet är utspritt lite varstans

Nej, inte "lite varstans", utan exakt där databladet säger... :-)

> Jag förstod att det var en statisk allokering i och med att jag skrev CBLOCK 0x20,

Rent formellt är det inte någon "allokering" alls. Du sätter ett antal symboler till
värden som du senare använder som adresser. MPASM har dock ingen koll på att dessa
symboler ("count" o.s.v) faktiskt är *adresser*, det skulle kunna vara vad som helst.
Det finns t.ex inget som helst som hindrar att du sätter två symboer till samma
värde med ganska "intressanta" resultat.

Det finns ett MPASM direktiv som heter RES som även gör en riktigt allokering.
Med RES så kan t.ex inte två allokeringer gå mot samma adress av misstag.

> RES nämner du, har redan letat efter någon sorts beskrivning på det,

MPASM manualen (33114, "K" het den jag har, aktuell finns på MPLAB sidan).
Kapitel "4.57 res - RESERVE MEMORY" i min version av manualen.

> Några pointers i rätt riktning över vilken dokumentation jag bör läsa skulle underlätta,

Manualen för MPLAB för att läsa om själva MPLAB.
Manualen för MPASM/MPLINK för detaljer om just det.
Manualen ("databladet") för processorn, för detaljer om just *det*.

> Att MPLAB/SIM skulle kunna hjälpa mig med interrupt visste jag inte. Den simulerar väl inte processorn så långt?

Det är få delar som *inte* simuleras. Timers är normalt inga problem, speciellt inte om de
ska köras vi den interna klockan, då behövs inga externa "stimuli" på pinnar t.ex.
Skriv svar