|
|
View previous topic :: View next topic |
Author |
Message |
karlo
Joined: 07 Jan 2008 Posts: 10
|
no timer1 interrupt on pic16f628 |
Posted: Wed Jan 09, 2008 6:56 am |
|
|
Hello,
I'm using an external crystal oscillator to create a real time counter, i've used a 2,457600 MHz crystal.
I've allready checked the oscillation frequency, test was ok
But i ve noticed in the list file, that probably a bit is set on a wrong adress
on line 026B bit0 of 0C (= PIR1) is set, this a flag register
The interrupt enable of timer1 is on address 8C,0
Had someone the same problems?
How can I check in the hex file to be sure this the problem?
Thanks
.................... ENABLE_INTERRUPTS (INT_TIMER1) ;
026A: BSF 03.5
026B: BSF 0C.0
.................... ENABLE_INTERRUPTS (GLOBAL) ;
026C: MOVLW C0
026D: BCF 03.5
026E: IORWF 0B,F
....................
.................... set_timer1(0x0000) ;
026F: CLRF 0F
0270: CLRF 0E |
|
|
Ttelmah Guest
|
|
Posted: Wed Jan 09, 2008 7:22 am |
|
|
You need to read up on how the PIC memory space is addressed.
The value '0C', addresses either address '0C', or address '8C', according to the value stored in the bank select bit. Guess what bit the line '026A' is setting?....
This is not your problem.
Best Wishes |
|
|
karlo
Joined: 07 Jan 2008 Posts: 10
|
|
Posted: Wed Jan 09, 2008 7:48 am |
|
|
I did a test and it don't make a difference
What i did
#byte PIE1 = 0x8C
bit_set(PIE1,0) ;
But i've seen that i don't have a proper interrupt service routine.
The first few lines ,also the last ones are made for a proper jump into the progam where the interrupt had occur,
but if goto 05F is used i don't think the interrupt routine will finish his routine properly.
How can i changes the goto 0057 into a call 0057 instruction in the C language
0000: MOVLW 00
0001: MOVWF 0A
0002: GOTO 211
0003: NOP
0004: MOVWF 7F
0005: SWAPF 03,W
0006: CLRF 03
0007: MOVWF 21
0008: MOVF 7F,W
0009: MOVWF 20
000A: MOVF 0A,W
000B: MOVWF 28
000C: CLRF 0A
000D: SWAPF 20,F
000E: MOVF 04,W
000F: MOVWF 22
0010: MOVF 77,W
0011: MOVWF 23
0012: MOVF 78,W
0013: MOVWF 24
0014: MOVF 79,W
0015: MOVWF 25
0016: MOVF 7A,W
0017: MOVWF 26
0018: MOVF 7B,W
0019: MOVWF 27
001A: BCF 03.7
001B: BCF 03.5
001C: MOVLW 8C
001D: MOVWF 04
001E: BTFSS 00.0
001F: GOTO 022
0020: BTFSC 0C.0
0021: GOTO 05F
0022: MOVF 22,W
0023: MOVWF 04
0024: MOVF 23,W
0025: MOVWF 77
0026: MOVF 24,W
0027: MOVWF 78
0028: MOVF 25,W
0029: MOVWF 79
002A: MOVF 26,W
002B: MOVWF 7A
002C: MOVF 27,W
002D: MOVWF 7B
002E: MOVF 28,W
002F: MOVWF 0A
0030: SWAPF 21,W
0031: MOVWF 03
0032: SWAPF 7F,F
0033: SWAPF 7F,W
0034: RETFIE
#INT_TIMER1
.................... void isr()
.................... {
.................... count_13ms ++ ;
*
005F: INCF 2B,F
0060: BTFSC 03.2
0061: INCF 2C,F
.................... bit_clear(PIR1,0) ;
0062: BCF 0C.0
.................... } |
|
|
Ttelmah Guest
|
|
Posted: Wed Jan 09, 2008 11:01 am |
|
|
You don't want to, or need to.
If code is 'called' from only one location, it is faster, to jump to it, and then jump back at the end. The compiler does this automatically for you, which is why it is using 'goto', not a call. The only 'fault' in the code shown, is you clearing the PIR bit. You should not do this. The compiler will automatically do this, unless you add the keyword 'noclear' to the interrupt declaration.
If you remove the '#nolist' line from the processor include file, the extra code, will become visible in the listing (otherwise a lot of this gets excluded, making the listing hard to understand...).
I'm afraid you are chasing 'hairs'. Describe your hardware better. What prescaler are you using on timer1?. Are you running with synchronisation enabled or disabled?. What processor clock?. What is actually happening?. You are looking for faults in the compiled code, when something else is wrong...
Best Wishes |
|
|
karlo
Joined: 07 Jan 2008 Posts: 10
|
|
Posted: Fri Jan 11, 2008 5:24 am |
|
|
I've installed the MPLAB simulator to see what's happening.
The timer1 interrupt occurs and i made it visible by toggling the LCD backlight.
But when the interrupt service routine is finished, the next step is to jump into main program at the program address + 1
In my program it jump to the next address under my interrupt routine (no instruction there) and than back to line where the interrupt is detected.(= endless loop)
My program
while (TRUE) // endless loop
{
/*----------sec. counter--------*/
if(count_13ms == ms_to_1s)
{
count_sec ++ ;
count_13ms = 0 ;
}
LcdPutC (0x0C) ;
LCD_dec_byte (count_sec) ;
Lcd_dec_byte (count_13ms) ;
loop: // wait for timer1 interrupt
goto loop ;
}
Interrupt routine
#INT_TIMER1
void Timer1_isr()
{
output_toggle(LCD_backlight) ; // for test purpose normally
//count_13ms++; filled in here
} |
|
|
Ttelmah Guest
|
|
Posted: Fri Jan 11, 2008 7:06 am |
|
|
Start by posting the actual program, including the headers, and setup. Use the 'code'buttons, so it is legible...
What you post, can't work, since it does not setup the timer, enable the interrupts, etc. etc.
Make the program simple, but showing the fault. For example:
Code: |
#include "C:\Program Files\PICC\USBtest\628test.h"
int16 count_26mSsec=0;
#define count_per_sec (37)
#int_TIMER1
void TIMER1_isr(void)
{
count_26mSec++;
}
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT|T1_EXTERNAL_SYNC);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while (true) {
if (count_26mSec==count_per_sec) {
count_sec++;
count_26mSec=0;
}
}
}
|
Your test, should be a complete program, that can be compiled, and works/fails, to show the problem.
As you see, I have changed the counter to be 26mSec, since if your clock is 2.3576MHz, then the counter will wrap at 23457600/65536 = 37.5 times per second, which is 26.6666mSec.
Best Wishes |
|
|
karlo
Joined: 07 Jan 2008 Posts: 10
|
|
Posted: Fri Jan 11, 2008 9:53 am |
|
|
Code: |
#if defined(__PCM__)
#include <16F628.H>
#fuses INTRC_IO,NOWDT,NOPROTECT,NOLVP
#ID CHECKSUM
typedef unsigned int8 uc;
int8 current, last ;
int32 count_13ms;
int8 count_sec, prev_count_sec, count_minutes, count_hours ;
int8 workreg, status, ms_to_1s ;
/*----- Constant Definitions -----*/
#define LCD_TYPE 2 // 0=5x7, 1=5x10, 2=2 lines
#define LCD_LINE_TWO 0x40 // LCD RAM address for the second line
#define LCD_WRITE 0xF0 // ddr port-b lcd write b'11110000'
#define LCD_READ 0xFF // ddr port-b lcd read b'11111111'
#define offset 60 // minimum temperature
#define ms_to_1s 74 // divide by 75
// ports bit definitions
#define magneetdetector (input(PIN_B4))
#define LCD_RS PIN_A7
#define LCD_RW PIN_A3
#define LCD_EN PIN_A4
#define PUSHBUTTON PIN_A0
#define LCD_backlight PIN_A6
#ROM 0x2100= {0x00,0x40,0x01,0x06,0x01,0x09,0x01,0x09,0x01,0x06,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,
0x00,0x48,0x01,0x0E,0x01,0x11,0x01,0x11,0x01,0x11,0x01,0x11,0x01,0x11,0x01,0x0E,0x01,0x00}
/*----- Global Variables -----*/
#byte Port_A = 0x05
#byte Port_B = 0x06
#byte CMCON = 0x1F
#byte VRCON = 0x9F
#byte PIR1 = 0x0C
#USE FAST_IO(A)
#USE FAST_IO(B)
#USE DELAY(CLOCK=4000000)
//#priority TIMER1, RB
/*----- interrupt routine -----*/
#INT_TIMER1
void Timer1_isr()
{
count_13ms ++ ;
}
/*----- Functions Prototypes -----*/
void Initialize (void) ;
uc LcdReadByte (void);
void LcdSendNibble (uc n) ;
void LcdSendByte (uc address, uc n) ;
void LcdPutc (uc c) ;
void Lcd_dec_byte(unsigned char val); // display a value in decimal
char num_to_char(unsigned char val); // convert to ASCII
uc const LCD_INIT_BYTES[4] = {0x20 | (LCD_TYPE << 2), 0x0C, 1, 6} ;
uc Cursor ;
signed int8 Dx, Dx_1, max_min ;
int8 tx, tx_1, motor_temp,data_flag, ee_address, value, a ;
/*------------------------------*/
void main (void)
{
// Presettings
Port_A = 0x04 ; // b'00000100'
set_tris_a (0x27) ; // set port-a bits direction b'00100111'
Port_B = 0x00 ; // b'00000000'
set_tris_b (0x30) ; // set port-b bits direction b'11110000'
CMCON = 0x25 ;
VRCON = 0xC0 ;
tx = 0 ;
tx_1 = 0 ;
Dx = 0 ;
Dx_1 = 0 ;
max_min = 0 ;
motor_temp = 0 ;
data_flag = 0 ;
bit_set (last,6) ;
current = 0 ;
last= 0xFB ; // Input RB4 is H to L ; RB5 is L to H active
count_13ms = 0 ;
prev_count_sec = 0x3D ; // Startvalue of 61 seconds
count_sec = 0 ;
count_minutes = 0 ;
count_hours = 0 ;
workreg = 0 ;
status = 0 ;
ee_address = 0 ;
value = 0 ;
Initialize() ;
LcdPutc (0x0C) ;
for (a=0; a<=18;a++) // loading special characters from eeprom into LCD RAM memory
{
ee_address = read_eeprom(workreg) ;
workreg ++ ;
value = read_eeprom(workreg) ;
workreg ++ ;
LcdSendByte (ee_address,value) ;
}
setup_timer_1 ( T1_EXTERNAL | T1_DIV_BY_2 | T1_CLK_OUT) ; // Timer1 overflow at 65536 / (2.457600 * 2) = 13333.3333333 µs
delay_ms (100) ;
ENABLE_INTERRUPTS (INT_TIMER1) ;
ENABLE_INTERRUPTS (GLOBAL) ;
set_timer1(0) ;
while (TRUE) // endless loop
{
if ( bit_test (CMCON,7) && VRCON <= 204) // repeat temperature measurement every 13.3333 ms
{
tx = VRCON & 0x0F ;
VRCON ++ ;
Dx = tx - tx_1 ;
}
else
{
if (VRCON >= 193)
{
Dx = tx_1 - tx ;
VRCON -- ;
}
else
{
LcdPutC (0x0C);
LcdPutC ("motor cold") ;
goto no_data ;
}
}
max_min = Dx - Dx_1 ;
tx_1 = tx ;
Dx_1 = Dx ;
if ( tx_1 >= 12)
{
LcdPutC (0x0C);
LcdPutC ("motor too hot!") ;
}
else
{
if ( max_min == 0 )
{
LcdPutc (0x0C) ;
motor_temp = tx_1 * 5;
motor_temp += offset ;
Lcd_dec_byte ( motor_temp) ;
LcdPutc ("°C ") ;
}
}
/*----------sec. counter--------*/
no_data:
if(count_13ms == ms_to_1s)
{
count_sec ++ ;
count_13ms = 0 ;
}
LcdPutC (0x0C) ;
LCD_dec_byte (count_sec) ;
Lcd_dec_byte (count_13ms) ;
loop: // wait for timer1 interrupt
goto loop ;
}
}
/*------------------------------*/
void Initialize()
{
uc i ;
Cursor = 0 ;
delay_ms (30) ;
for (i=1 ; i <= 3 ; ++i)
{
LcdSendNibble (3) ;
delay_ms (5) ;
}
LcdSendNibble (2) ;
for (i=0 ; i <= 3 ; ++i)
LcdSendByte (0, LCD_INIT_BYTES[i]) ;
}
/*------------------------------*/
uc LcdReadByte (void)
{
uc low, high ;
dataread:
set_tris_b (LCD_READ) ;
output_high (LCD_RW) ;
delay_cycles (2) ;
output_high (LCD_EN) ;
delay_cycles (2) ;
high = (Port_B & 0x0F) ; // b'00001111'
high = high << 4 ;
output_low (LCD_EN) ;
delay_cycles (2) ;
output_high (LCD_EN) ;
delay_us (2) ;
low = (Port_B & 0x0F) ; // b'00001111'
output_low (LCD_EN) ;
set_tris_b (LCD_WRITE) ;
if (bit_test (high,7) )
goto dataread ;
else
if (data_flag)
{
output_high (LCD_RS) ;
data_flag = FALSE ;
goto dataread ;
}
return (high | low) ;
}
/*------------------------------*/
void LcdSendNibble (uc n)
{
Port_B &= 0xF0 ; // clear RB0 to RB3 b'11110000'
Port_B |= n ; // OR the data with the lower nibble of Port_B
delay_cycles (4) ;
output_high (LCD_EN) ;
delay_us (4) ;
output_low (LCD_EN) ;
}
/*------------------------------*/
void LCdSendByte (uc address, uc n)
{
output_low (LCD_RS) ;
LcdReadByte() ;
output_low (LCD_RS) ;
if (address)
output_high (LCD_RS) ;
delay_cycles (3) ;
output_low (LCD_RW) ;
delay_cycles (3) ;
output_low (LCD_EN) ;
LcdSendNibble (n >> 4) ;
LcdSendNibble (n & 0x0F) ;
}
/*------------------------------*/
void LcdPutc (uc c)
{
switch (c)
{
case 0x0C :
LcdSendByte (0, 1) ;
delay_ms (3) ;
break ;
case 0x0D :
LcdSendByte (0,0x0D) ;
delay_ms (3) ;
break ;
case 0x10 :
LcdSendByte (0, 0x10) ;
break ;
case 0x14 :
LcdSendByte (0, 0x14) ;
break ;
case '°' :
LcdSendByte (1, 0b00000);
break;
case '0' :
LcdSendByte (1, 0b00001);
break;
default :
LcdSendByte (1, c) ;
break ;
}
}
/*------------------------------*/
void Lcd_dec_byte(unsigned char val)
{
unsigned char d,e;
char c;
d=val/1000;
if (d < 1)
LcdPutc(0x14);
else
{
c=num_to_char(d);
LcdPutc(c);
}
d=val/100;
if (d < 1)
LcdPutc(0x14);
else
{
c=num_to_char(d);
LcdPutc(c);
}
val=val%100;
d=val/10;
c=num_to_char(d);
LcdPutc(c);
d=val % 10;
c=num_to_char(d);
LcdPutc(c);
}
/*------------------------------*/
char num_to_char(unsigned char val)
{
char c;
c=val+'0';
return(c);
}
Hereby my program to check the temperature of an engine
But i also need a real time clock for speed counts.
I also prefer to wait until timer1 is overflowed and than go back to temperature analysis of the engine,speed counts (input change on RB5 = also interrupt for this)
I want no conflicts between both interrupts if they should both been set on the same time (priority timer1 instead of RB)
Thanks
|
|
|
|
Ttelmah Guest
|
|
Posted: Fri Jan 11, 2008 10:37 am |
|
|
First,the prescaler, _divides_ the clock, it does not multiply it. Your interrupt will only be every 53.3mSec...
You seem to be trying to increment the Vref signal, and use this to change the comparator, to provide a crude ADC. Presumably with a signal conected to RA1?.
Read what I said, about making the program _simple_ to show the problem. What you have here, is a mess.
Best Wishes |
|
|
SET
Joined: 15 Nov 2005 Posts: 161 Location: Glasgow, UK
|
|
Posted: Fri Jan 11, 2008 12:54 pm |
|
|
Karlo, your code is:
Code: |
while (TRUE) // endless loop
{
/*----------sec. counter--------*/
if(count_13ms == ms_to_1s)
{
count_sec ++ ;
count_13ms = 0 ;
}
LcdPutC (0x0C) ;
LCD_dec_byte (count_sec) ;
Lcd_dec_byte (count_13ms) ;
loop: // wait for timer1 interrupt
goto loop ;
} |
This will write once to the LCD, then sit in an endless loop goto'ing loop.. I assume thats not what you intended?
Try:
Quote: | Code: |
while (TRUE) // endless loop
{
/*----------sec. counter--------*/
while(count_13ms < ms_to_1s)
{
count_sec ++ ;
count_13ms = 0 ;
}
LcdPutC (0x0C) ;
LCD_dec_byte (count_sec) ;
Lcd_dec_byte (count_13ms) ;
} |
|
You dont need to 'wait' for the interrupt, it takes care of itself.
And if you want the LCD updated every interrupt:
Quote: | Code: |
while (TRUE) // endless loop
{
/*----------sec. counter--------*/
while(!interrupted); // flag set in ISR
interrupted=0;
if(count_13ms == ms_to_1s)
{
count_sec ++ ;
count_13ms = 0 ;
}
LcdPutC (0x0C) ;
LCD_dec_byte (count_sec) ;
Lcd_dec_byte (count_13ms) ;
} |
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jan 11, 2008 6:13 pm |
|
|
See my post at the end of this thread. It has a small test program
that shows how to check if Timer1 interrupts are working, when
Timer1 is clocked by the Timer1 oscillator with an external crystal.
http://www.ccsinfo.com/forum/viewtopic.php?t=25824
You need to make a very simple program like this to test your problem. |
|
|
karlo
Joined: 07 Jan 2008 Posts: 10
|
|
Posted: Wed Jan 16, 2008 5:36 am |
|
|
I found out what the problem was, it had nothing to do with the interupt(routine)
I tested 2 variables with an if statement, if (var1 < var2)
If checked the assembly code and i saw that only the zero flag was tested.
Somehow var1 was bigger than var2 , and if (var1 < var2) condition was true. The carry flag was set (but not tested)
How can i check var1 < var2 without checking the assembly code?
THX |
|
|
Ttelmah Guest
|
|
Posted: Wed Jan 16, 2008 5:54 am |
|
|
'var1 < var2', should evaluate fine.
How are var1, and var2 declared (integers or what?).
What values do they contain?.
The behaviour you are seeing, will sometimes happen, if the values are impossible for the variables concerned.
Best Wishes |
|
|
SET
Joined: 15 Nov 2005 Posts: 161 Location: Glasgow, UK
|
|
Posted: Wed Jan 16, 2008 7:13 am |
|
|
Quote: | I tested 2 variables with an if statement, if (var1 < var2)
If checked the assembly code and i saw that only the zero flag was tested.
Somehow var1 was bigger than var2 , and if (var1 < var2) condition was true. The carry flag was set (but not tested)
How can i check var1 < var2 without checking the assembly code? |
Post your code that shows this behaviour. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|