Sida 2 av 4
Postat: 12 november 2008, 09:09:05
av bearing
Används inte low voltage programming är det bättre att ändra configen. Om du söker i databladets PDF-fil efter ord som: LVP / low voltage programming hittar du nog anledningen till motståndet.
Det finns bara en interruptvektor på de här processorerna; samma rutin anropas alltså vid varje interrupt. I interruptrutinen måste sedan interruptflaggorna kontrolleras.
Exempel:
Kod: Markera allt
#include <int16CXX.H>
////////////// INTERRUPT ROUTINE /////////////////////
#pragma origin 4
interrupt int_server( void)
{
int_save_registers // W, STATUS (and PCLATH)
uns8 sv_FSR = FSR;
if (INTE&&INTF) //External interrupt on RB0
{
INTF=0;
}
if (CCP1IE&&CCP1IF) //Capture on RC2 / CCP1
{
CCP1IF=0;
}
if (CCP2IE&&CCP2IF)
{
CCP2IF=0;
}
if (T0IE&&T0IF)
{
T0IF=0;
}
if (TMR1IE&&TMR1IF)
{
TMR1IF=0;
}
if (RCIE&&RCIF)
{
rxChar=RCREG;
}
if (TXIE&&TXIF)
{
TXREG=txBuf[txHead];
}
FSR = sv_FSR;
int_restore_registers // W, STATUS (and PCLATH)
}
////////////// END OF INTERRUPT /////////////////////
Det är inte alltid nödvändigt att kontrollera både att Interrupt Flag och Interrupt Enable är satta - endast koll av Interrupt Flag är oftast tillräckligt. Jag gör det numera alltid för att slippa de buggar som blir i de fall det behövs. Interrupt Enable-bitarna ligger generellt (alltid?) i en annan bank än Interrupt Flag vilket gör att det tar extra lång tid att kontrollera dem p.g.a bankswitchningen.
Varför..
Postat: 13 november 2008, 22:37:48
av christoferivarsson
Vad gör jag för fel. Har nu övergivit min förra kod och skrivit en ny med interruptrutiner istället för Timer1 som counter.
Nu har jag interrupt p åinsignalen från givaren som räknar upp ett register 'count'. När Timer1 slår runt ger den interrupt som läser värdet i 'count'. Åter igen funkar det finfint i MPlabs simulator men när jag kopplar på däcket så vägrar lcd displayen att ändra värde. Jag kan ändra värde manuellt ifall jag anger typ 'count=10;' men in te genom att stimulera RB0 som är aktiv interrupt och ingång.
Gör jag nåt kardinalfel eller vad???!?!?!
Postat: 13 november 2008, 23:45:59
av bearing
Ja det verkar ju ganska märkligt detta.
Hur simulerar du? stimulerar du RB0 i simulatorn och ser att koden i interruptrutinen körs?
Postat: 13 november 2008, 23:46:30
av sodjan
> Har nu övergivit min förra kod och skrivit en ny...
Var är den ?
Sen så kör du i C, eller hur ? Prova att skriva ett litet testprogram som
gär samma sak i assembler så att du är 100% säker på vad du gör
och se om du får samma fenomen. Och du får väl felsöka din C-kod
lite, skala av allt onödigt, förrenkla tills du har något som fungerar.
Lägg sedan till funktioner tills det lägger av igen. Felsökning kapitel 1A...
Postat: 14 november 2008, 08:08:24
av Nerre
Alltså, grundregeln i felsökning är ju uteslutningsmetoden.
Har du börjat med att testa varje enskild del av koden?
Det första man kan göra är ju att skriva en kod som läser en ingång och baserat på den ingången styr en utgång. Då får man koll på att det fungerar.
Steg två kan vara att läsa ingången och låta den räkna upp en räknare som i sin tur styr en två utgångar. Då ser man t.ex. att man inte har problem med kontaktstuds och liknande.
Nästa steg är att skriva en timer som helt enkelt togglar en utgång. Då får man koll på att man har fått till timern rätt.
Postat: 14 november 2008, 09:55:50
av christoferivarsson
Här e nya koden som bygger på interrupt vid insignalen på RBO samt interrupt då Timer1 slår runt. Funkar lysande i Simulatorn men får ingen respons vid stimuli på RB0 i praktiken.
Allting från registret 'counter' till representationen på displayen funkar felfritt.
Timer1 är prescalad med 8 så den ger ju inte avläsning varje sekund som jag först tänkt men det är sekundärt, får jag fixa i nästa skede. Just nu blir det ju 65535x8 = ca 0.5 sekunder men det hinner man ju göra några knapptryckningar på...
Kod: Markera allt
/*
________ ________
| \/ | R/!WR = 0
D6--|RA2 16F628 RA1|--D5 (only write, wait while busy)
D7--|RA3 RA0|--D4
|RA4-od RA7/OSC1|
|RA5/MCLR RA6/OSC2|
GND--|Vss Vdd|-- +5V
Giv--|RB0/INT (RB7)/PGD|
|RB1/Rx (RB6)/PGC|
|RB2/Tx RB5|--RS
EN--|RB3/CCP (RB4)/PGM|
|__________________|
*/
#include "16F628.H"
#include "int16Cxx.h"
#pragma config |= 0x3fb0 // use internal 4MHz oscillator
#pragma bit RS @ PORTB.5
#pragma bit EN @ PORTB.3
#pragma bit D7 @ PORTA.3
#pragma bit D6 @ PORTA.2
#pragma bit D5 @ PORTA.1
#pragma bit D4 @ PORTA.0
char counter; //define variable k as the normalizing value for 1 litre/sec
char kvot; //deklarera ny variabel för kvoten mellan antalet pulser och en kosntant för att få i liter per timma-----------------------
unsigned long p; //declare variabel p to which T1MRL is later copied
char z; //variabel för text2
char konstant;
#pragma origin 4
interrupt int_server(void) //interruptfunktion
{
int_save_registers //spara undan aktuellt innehåll i arbetsregistret
{
if (INTF==1) //om puls på RB0 => addera räkna upp counter med 1
{
counter++;
INTF=0; //nolla flagga
}
if (TMR1IF==1) //om Timer1 slagit runt => flytta counter till p
{
p=counter;
counter=0; //nolla counter
TMR1IF=0; //nolla flagga
}
}
int_restore_registers
}
#include "delays.c"
void delay( char ); // ms delay function from file delays.c
void lcd_init( void );
void lcd_putchar( char );
char text1( char );
char text2( char );
char division ( char, char ); //definition of new counter function for the incoming pulses on RB6----------------------------
void main( void)
{
CM0=1; CM1=1; CM2=1; // no comparators on
/* I/O-pin direction in/out definitions, change if needed */
TRISB = 0b10.0.1.0.0.11; // output to RS and EN ( and Tx ), RB0 input
TRISA = 0b1111.0000; // output to D4-D7
INTEDG = 0; //interrupt on negative flank
INTE =1; //enable external RB0 interrupt
GIE =1; //enable global interrupt
PEIE=1; //enable peripherial int
OPTION_REG.7=0; // pull-up resistance on PORTB
T1CON = 0b00.11.10.01; //Timer1 prescaled 1:8, oscillator on, internal clock, Timer1 enabled
TMR1IE=1; //enable interrupt on Timer1
RBIE=0; //disable int on other RB ports
lcd_init(); //initiera display
TMR1L=0; //Timer MSB =0
TMR1H=0; //Timer LSB=0
TMR1IF=0; //interruptflagga =noll
counter=0;
konstant=1;
while(1)
{
//Rutin för att beräkna och skriva ut rätt tecken på displayen
if (p>0) //flytta TMR1L till p om större än 0 annars p=1. Detta för att tecknet på displayen blir fel vid en kvot inehållande 0
p=p;
else
p=1;
//p=p<<2; //vänsterskift för att minska effekten av modulot som blir vid divisionen
kvot = division (p,konstant); //anropa funktion som dividerar pulser med konstant-----------------------------------
//kvot=kvot>>2 ; //högerskift för att minska värdet till samma decimal som innan vänsterskift
/* Skriv ut till LCD*/
RS = 1; // LCD in character-mode
if (kvot<10) lcd_putchar('0'+kvot); //testa om kvot mindre än 10, isåfall skriv till skärm från position 0 ASCII plus värdet av kvot
if (kvot>=10) //om kvot större än 10 dela upp 10 tal och ental, skicka till LCD
{
char ch_1; //deklarera nya variabler ch_1 = tecken nr 1, samt ch_2 =tecken nr 2
char ch_2;
ch_1= kvot/10; //dividera kvot med tio för att få ut värdet på första siffran - ex. 23/10=2 modulo 3
lcd_putchar ('0'+ ch_1); //visa värdet på första teckenplaceringen
ch_2=kvot%10; //plocka fram modulot och lägg i ch_2 - se ex. ovan
lcd_putchar ('0'+ ch_2); //visa ch_2 i displayen på plats två
}
// reposition to "line 2" (the next 8 chars)
RS = 0; // LCD in command-mode
lcd_putchar( 0b11000000 );
RS = 1; // LCD in character-mode
// display the 8 char text2() sentence
for(z=0; z<8; z++) lcd_putchar(text2(z));
}
}
/* ****************** FUNCTIONS ****************************** */
char text2( char x) // this is the way to store a sentence
{
skip(x); /* internal function CC5x. */
#pragma return[] = "liter/h " // 8 chars max! Måste vara 8teckenavstånd mellan "" tecknen
}
void lcd_init( void ) // must be run once before using the display
{
delay(40); // give LCD time to settle
RS = 0; // LCD in command-mode
lcd_putchar(0b0011.0011); /* LCD starts in 8 bit mode */
lcd_putchar(0b0011.0010); /* change to 4 bit mode */
lcd_putchar(0b00101000); /* two line (8+8 chars in the row) */
lcd_putchar(0b00001100); /* display on, cursor off, blink off */
lcd_putchar(0b00000001); /* display clear */
lcd_putchar(0b00000110); /* increment mode, shift off */
RS = 1; // LCD in character-mode
// initialization is done!
}
void lcd_putchar( char data )
{
// must set LCD-mode before calling this function!
// RS = 1 LCD in character-mode
// RS = 0 LCD in command-mode
// upper Nybble
D7 = data.7;
D6 = data.6;
D5 = data.5;
D4 = data.4;
EN = 0;
nop();
EN = 1;
delay(5);
// lower Nybble
D7 = data.3;
D6 = data.2;
D5 = data.1;
D4 = data.0;
EN = 0;
nop();
EN = 1;
delay(5);
}
char division( char x, char y) /* function header */
{ /* start of function body */
char f;
f = x / y;
return f;
} /* end of function body */
Postat: 14 november 2008, 14:27:47
av bearing
Något som kanske ställer till det är att counter är en 8-bitars, p är en 16-bitars, argumenten till divisionsfunktionen är 8-bitars men du skickar in p som är 16-bitars.
Ovanstående tror jag dock inte skapar något fel för dig. Förmodligen är felet att timern nollställer counter så ofta att du inte hinner se att något hänt.
Testa att göra om progammet så att counter skrivs ut utan några mellansteg, samt gör att counter inte nollställs i timerinterruptet.
byt ut
Kod: Markera allt
//Rutin för att beräkna och skriva ut rätt tecken på displayen
if (p>0) //flytta TMR1L till p om större än 0 annars p=1. Detta för att tecknet på displayen blir fel vid en kvot inehållande 0
p=p;
else
p=1;
//p=p<<2; //vänsterskift för att minska effekten av modulot som blir vid divisionen
kvot = division (p,konstant); //anropa funktion som dividerar pulser med konstant-----------------------------------
//kvot=kvot>>2 ;
mot
och ta bort
ur interruptet.
Postat: 16 november 2008, 00:47:03
av christoferivarsson
Tack fölr tips, har nu löst problemet. Kommunikationen med LCDn va fel. Siffrorna skrevs ut på fel teckenplats dvs nånstans mellan 16-40 som inte syns på displayen. Nu flyttar jag markören till vänster vid varje utskrift med 0000.0010 som styrkod.
Postat: 16 november 2008, 01:17:25
av sodjan
Självklart är det så...
Första raden början på 00, andra raden börjar på 40 (i hex).
Varje LCD datablad har info om detta, och varje generell HD44780
"turorial" samt det framgår om du kollar den HD44780 exempelkod
som finns här :
http://www.jescab.se/HD44780.html...
Vad jag inte förstår är hur det fungerade när du bara hårdkodade det
värde som skulle skrivas ut, var det inte med samma LCD subrutin ?
> Jag kan ändra värde manuellt ifall jag anger typ 'count=10;'.......
Postat: 18 november 2008, 09:20:14
av christoferivarsson
Jag hade glömt skriva en reset. Först skrev jag ut på rad1 8tecken, sen skrev jag ut rad2 8tecken. Därefter glömde jag flytta tillbaka markören. Thats all.
Postat: 18 november 2008, 09:30:28
av vfr
Du menar att det fanns med en omställning av teckenpekaren när du körde manuella värden men inte när du tog ett "riktigt" värde? Isåfall var det ju inte en riktigt relevant test. Skall man testa något så skall man
bara ändra på just den biten. Annars vet man inte riktigt vad som orsakade eventuella problem.
Men det var ju en bra lärdom att ta med sig till vidare felsökning i framtiden!
Trevligt att du löste problemet!

Postat: 18 november 2008, 11:29:52
av sodjan
> Jag hade glömt skriva en reset.
Vadå för "reset" ?
Du skrev ju att om du bara hårdkodade ett värde så fungerade det:
> Jag kan ändra värde manuellt ifall jag anger typ 'count=10;'.......
Vad har det med någon "reset" att göra ?
Postat: 19 november 2008, 09:55:24
av christoferivarsson
Kika på följande
Kod: Markera allt
/* Skriv ut till LCD*/
RS = 1; // LCD in character-mode
if (kvot<10) lcd_putchar('0'+kvot); //testa om kvot mindre än 10, isåfall skriv till skärm från position 0 ASCII plus värdet av kvot
if (kvot>=10) //om kvot större än 10 dela upp 10 tal och ental, skicka till LCD
{
char ch_1; //deklarera nya variabler ch_1 = tecken nr 1, samt ch_2 =tecken nr 2
char ch_2;
ch_1= kvot/10; //dividera kvot med tio för att få ut värdet på första siffran - ex. 23/10=2 modulo 3
lcd_putchar ('0'+ ch_1); //visa värdet på första teckenplaceringen
ch_2=kvot%10; //plocka fram modulot och lägg i ch_2 - se ex. ovan
lcd_putchar ('0'+ ch_2); //visa ch_2 i displayen på plats två
}
// reposition to "line 2" (the next 8 chars)
RS = 0; // LCD in command-mode
lcd_putchar( 0b11000000 );
RS = 1; // LCD in character-mode
// display the 8 char text2() sentence
for(z=0; z<8; z++) lcd_putchar(text2(z));
}
- Först skrev jag ut på rad 1
- Sen gick jag över i command-mode och flyttade markören till rad 2 genom RS=0
- Därifrån glömde jag gå över till rad 1 igen, dvs det funkade 1gg att skriva ut 'counter' men sen flyttade jag aldrig tillbaka positionen till rad 1 tecken 1
En annan fråga:
Jag lyckas inte få till en användbar utsignal från min hallgivare som mäter flödet
http://shop2.conrad.se/websale7/FLOW-M% ... 1%2fmd5%7d
Har försökt koppla den via en NPN bc547 transistor för att förstärka utsignalen men oscilloskopet visar noll.
Någon som vet hur man enklast gör? (se databladet i länken på vänster sida)
Postat: 19 november 2008, 10:27:43
av Norpan
Har du nån pullup till signalutgången?
Postat: 19 november 2008, 11:30:56
av christoferivarsson
Ja jag har testat med pull-up extern . Koppling enligt nedan
Från hallgivare -> bas via 10k resistor
+5V till kollektor via 1k resistor
Jord till emitter
Använder en BC547C transistor. Helt dött...