Sida 2 av 4
Postat: 13 november 2007, 14:13:43
av speakman
"Komprimera" koden och klistra in den här mellan code-taggar om du vill att någon ska se något.
Postat: 13 november 2007, 14:21:56
av Ulf
Ja ja, Sodjan, jag pillade lite med dom på 80-talet och har förträngt detta till den grad att jag inte kommer i håg hur de stavas, de var ju inte, i mitt tycke, direkt trevliga att pilla med vad jag minns. Tur att C finns!
Postat: 13 november 2007, 14:51:02
av Lullen
sodjan skrev:Någon speciell anledning att lägga koden just *där* ?
Sen fanns det ingen fråga i inlägget så varför ska jag ladda ner koden ?
Slutligen, förstår du nu vad som är feltänkt med "PORTC.F1 = CO;" ?
Se det som en update på första posten. Då jag hade gjort missar vid första posten så gjorde jag på samma sätt igen och anledningen till att jag la koden där var för att jag tyckte det skulle vara bättre för alla då inte hela sidan blir massa kod, men jag kanske har fel?
Ja jag fattar vad jag gjorde för fel med den där raden, stor skillnad på bit o byte

Postat: 13 november 2007, 15:00:01
av sodjan
> Se det som en update på första posten...
Ja, men varför ?
Du sa inget om vad som inte fungerarde eller om det var något problem med den.
Så varför ska (t.ex) jag titta på den alls ?
Finns ju ingen anledning att sitta och slötitta på kod som fungerar...
Det har hänt förr att någon har postat en kod i en tråd, och efter att
ha kollat som fan efter fel så sa jag att jag hittar inget fel, och fick
till svar att "nä, det fungerar bra..." Skitkul...
Generellt, när någon kod inte uppför sig som förväntat, fixa ett
litet test-case som visar problemet (d.v.s plocka bort *ALLT* som inte
direkt har med aktuella problemet att köra). Resterande kod (som brukar
bli kort) kan postas direkt. Dessutom brukar man hitta felet under tiden
som man fixar test-case't i alla fall...
> stor skillnad på bit o byte
Japp !

Postat: 15 november 2007, 18:48:59
av Lullen
hmm kom o tänka på en sak... min kod ovan fungerar inte eftersom det kommer att bli ett allt för stort avbrott, ska väl inte vara något problem med ett livet avbrott, då kommer programmet bara att öka effekten lite för att kompensera avbrottet, men nu kommer ju avbrottet vara upp emot en sekund(läsa av 1-wire samt det andra), så då kommer den max ha effekten 50%, så hur gör jag för att ha denna kod snurrandes hela tiden?
Kod: Markera allt
PORTC.F1 = 1; //tid som relä är hög
for(i = 0; i < pwr;i++)
{
delay_ms(20);
}
PORTC.F1 = 0; //tid som relä är låg
tid = 100 - pwr;
for(i = 0; i < tid;i++)
{
delay_ms(20);
}
Postat: 15 november 2007, 21:49:43
av sodjan
Du får se till att ha kortare avbrott helt enkelt.
Det handlar om att ha rätt arkitektur på applikationen.
Du kan inte ligga längre i avbrottet en vad resten av applikationen
tillåter. Simple as that...
Postat: 15 november 2007, 22:08:57
av Ulf
Kika på hur interrupt fungerar,det gör livet lite enklare.
Kanske låta timer interruptet generera någon form av systemticks.
Då får du rätt gott om tid att göra något nyttigt under tiden istället för att "bara" räkna plus i en loop.
Postat: 15 november 2007, 22:15:18
av sodjan
Jag antog att "avbrott" = "interrupt", det brukar vara det...
Postat: 16 november 2007, 10:35:46
av Ulf
Jag är inte helt säker på att det är så när man kikar på koden...
Postat: 24 november 2007, 16:37:14
av Lullen
har kollat lite på interrupts o det verkar riktigt läskigt
så jag kom på att eftersom när man läser av tempen så behöver man en delay på 400ms så kan man ju stoppa in avläsningen av temperaturen i själva effektregleringen. Men detta kommer ju göra att 2st loopar kommer bli lite längre, men eftersom relät har nollgenomgångstriggning så kommer den att vänta tills nästa nollgenomgång(kanske 19ms senare) eller tänker jag fel? hur bra kommer detta att fungera? här är koden iaf
Kod: Markera allt
void Set_Pwr( unsigned int pwr)
{
PORTC.F1 = 1; //tid som relä är hög
for(i = 0; i < pwr;i++)
{
delay_ms(20);
}
PORTC.F1 = 0; //tid som relä är låg
tid = 100 - pwr;
for(i = 0; i < tid;i++)
{
if(i==0)
{
ow_reset(&PORTB,1); // Onewire reset signal
OW_Write(&PORTB,1,0xCC); // Issue command SKIP_ROM
OW_Write(&PORTB,1,0x44); // Issue command CONVERT_T
Delay_us(120);
OW_Reset(&PORTB,1);
OW_Write(&PORTB,1,0xCC); // Issue command SKIP_ROM
OW_Write(&PORTB,1,0xBE); // Issue command READ_SCRATCHPAD
}
if(i==20) //gått 400ms
{
j = OW_Read(&PORTB,1); // Get temperature LSB
temp = OW_Read(&PORTB,1); // Get temperature MSB
temp <<= 8; temp += j; // Form the result
temp = Format_Temperature(temp); // Format result
readTemp = temp; //skicka tillbaka temp så det kan kontrolleras
}
delay_ms(20);
}
}
Postat: 24 november 2007, 17:08:44
av sodjan
> har kollat lite på interrupts o det verkar riktigt läskigt
Hur då ? Vad undrar du över ?
Sen känns det lite, hm, rörigt att ha 1-Wire rutiner in något som heter "Set pwr",
men det kanske mest beror på att jag inte förstår vad det är du gör...
En allmän känsla är att det är lite för mycket delay_ms() anrop för att det
ska kännas riktigt bra. Det brukar bli väldigt rörigt efter ett tag.
Postat: 24 november 2007, 17:41:53
av Lullen
jag förstår principen med interrupts men sen när jag kollar på koden så fattar jag inget. Vad är det som kallar den funktionen?
om jag tar ett exempel som kom med kompilatorn, har även
Kod: Markera allt
unsigned cnt;
void interrupt() {
cnt++; // Increment value of cnt on every interrupt
TMR0 = 96;
INTCON = 0x20; // Set T0IE, clear T0IF
}//~
void main() {
OPTION_REG = 0x84; // Assign prescaler to TMR0
TRISB = 0; // PORTB is output
PORTB = 0xFF; // Initialize PORTB
TMR0 = 96;
INTCON = 0xA0; // Enable TMRO interrupt
cnt = 0; // Initialize cnt
do {
if (cnt == 400) {
PORTB = ~PORTB; // Toggle PORTB LEDs
cnt = 0; // Reset cnt
}
} while(1);
}//~!
eller denna, ett exempel från kths hemsida
Kod: Markera allt
/* exint62x.c External interrupt turns on light */
#include "16F628.h"
#include "int16Cxx.h"
#pragma config |= 0x3f90
#pragma origin 4
interrupt int_server( void )
{
int_save_registers
if( INTF == 1 ) /* test if it is the INT-interrupt? */
{ /* this time it's obvious that it is! */
PORTA.2 = 1; /* Lightdiode on to show "Kilroy was here" */
INTF = 0; /* Reset INT-flag before leaving */
}
int_restore_registers
}
void main( void )
{
/* the main program */
CM0=1; CM1=1; CM2=1; /* no comparators at PORTA */
TRISB.0 = 1; /* RB0/INT is input */
TRISA.2 = 0; /* RA2 output to lightdiode */
PORTA.2 = 0;
INTEDG = 0; /* interrupt on negative going edge */
INTE = 1; /* local enable */
GIE = 1; /* global enable */
while( 1 ) nop();
Postat: 24 november 2007, 18:57:59
av Kaggen
> Vad är det som kallar den funktionen?
PIC är byggd så att vid interrupt så avbryter den det den håller på med, spar nuvarande adress på stacken och fortsätter exekvera från address 4 i programminnet tills den stöter på "RETI" instruktionen. Efter RETI så plockar den gammla adressen (där den var innan interruptet) från stacken och fortsätter där den vart avbruten.
Hur olika programspråk hanterar detta internt är olika från språk till språk. I ditt första exempel ovan gissar jag att interrupt() är den funktion som anropas vid interrupt (kompilatorn ser till att ett goto till adressen för interrupt() läggs på position 4 i programminnet alternativt lägger hela funktionen från position 4 och frammåt). Och samma med funktionen int_server(void) i koden nedanför.
Det är sedan upp till dig att kolla *vilket* interrupt som har inträffat. Detta gör du genom att kolla vilken interruptflagga som är satt. Detta kan också skilja sig mellan kompilatorer/språk. I ditt första exempel ovan verkar dom ta förgivet att det bara är TMR0 interrupt som är aktiverat eftersom dom aldrig verkar kolla interrupt-flaggan. Detta är dålig programmering. Den nedre koden kollar iaf att INTF är satt så att rätt kod körs.
Att kolla vilket interrupt som har skett *måste* göras manuellt genom att kolla att rätt interruptflagga är satt. Annars är risken att du t.ex. kör kod för att sätta timern när det igentligen är ett helt annat interrupt som triggat (t.ex. en byte som kommit på serieporten).
En annan sak som somliga missuppfattar är att ett interrupt kör *inte* samtidigt som övrig kod. Under tiden interruptet körs står din s.k. main loop still. Om du t.ex håller på att skriva text på LCD:n och mitt i så inträffar ett interrupt som varar 1 sekund, så stannar utskriften under den tid interruptet varar. Därför skall interrupt *alltid* vara korta kodsnuttar. Skall något större jobb utföras kan man trigga/sätta en flagga/variabel som kollas i mainloopen, så att mainloopen utför grovjobbet.
Postat: 25 november 2007, 00:47:13
av Lullen
vad får du 4an ifrån?
sedan känner jag att det säkert kommer bli en himla massa frågor om detta o de guider jag läst är antingen ren kod eller så är det bara text där det står vad interrupts är. Så är någon en fin länk som beskriver detta utförligt i c eller basic? eller kan tipsa om en specifik bok som finns på biblan?
Postat: 25 november 2007, 01:35:24
av Kaggen
> vad får du 4an ifrån?
Från databladet för processortypen från tillverkaren av processorn på avdelningen i databladet som beskriver hur interrupt fungerar t.ex.
Det är detta som blir så abstrakt när man inte kan assembler. 4 är addressen i programminnet. Du vet att 16F628 har 2k programminne, 1 - 2048 (edit: address 0 - 2047)? Processorn är byggd så att vid interrupt hoppar programräknaren till position/address 4 i programminnet och börjar exekvera kod som ligger där, allt enligt databladet till 16F628. Detta är väldigt svårt att förklara för de som kör enbart högnivå språk, eftersom det blir så abstrakt.
C och de flesta BASIC till PIC (och många andra uC / processorer) kompileras ju till maskinkod/maskinkodsinstruktioner. Dessa läggs upp i programminnet. Det är dessa instruktioner som processorn läser. Den läser inte den C-källkod som du skriver i din texteditor, utan de prograministruktioner som blir efter kompilering. RETI (return from interrupt) som jag nämde tidigare är just en maskinkods-instruktion.
Men om vi struntar i hur det fungerar "under huven" så har de flesta språk/kompilatorer *reserverade* funktionsnamn eller definitioner för att definiera funktioner för interrupt. Hur de ser ut beror helt på den C-kompilator BASIC-kompilator du använder och information om detta finns antagligen i manualen till den C/BASIC/whatever-kompilator du använder.
Om vi förenklar ytterligare:
1. Interrupt "händer"
2. Programmet avbryter sig där det förnärvarande exekverar (men lägger på minnet vart den befinner sig)
3. Programmet börjar exekvera interrupt funktionen (vad den nu må heta interrupt() eller int_server() som i dina exempel ovan) tills den kommer till slutet av funktionen.
4. Programmet fortsätter där det avbröt sig vid steg 2.