View previous topic :: View next topic |
Author |
Message |
temtronic
Joined: 01 Jul 2010 Posts: 9221 Location: Greensville,Ontario
|
|
Posted: Wed Jun 16, 2021 12:35 pm |
|
|
couple of things....
1) 4MHz clock is slow for that PIC,depending on what else it has to do....
2) should never,ever have delays in any ISR ! Set flags, do 'stuff' in main() based upon the flags.
3) no apparent 'default' or 'startup' edge detection, maybe that's not a problem but........
4) if 'inputsignal' is the zero cross, 'high' will always be true, L to H edge .... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 16, 2021 12:35 pm |
|
|
matthewmilford wrote: |
#fuses HS, XT, NOWDT, NOPROTECT, NOPUT, NOLVP
#use delay(clock = 4MHz)
|
XT is the correct oscillator fuse for a 4 MHz crystal. Get rid of the
HS fuse. Also, when using a crystal, the PUT fuse is normally good
to use.
matthewmilford wrote: |
#INT_EXT // external interrupt ISR
void EXT_ISR()
{
int1 high;
if(input(inputsignal) == 1)
{
high=TRUE;
delay_cycles(1);
ext_int_edge(L_TO_H);
}
else
{
high=FALSE;
delay_cycles(1);
ext_int_edge(H_TO_L);
}
delay_ms(2);
output_high(gate2);
delay_us(50);
output_low(gate2);
}
|
You have swapped the edges from the way that Ttelmah showed you. It's not going to work.
Quote: | void main()
{
output_drive(gate2);
output_low(gate2);
clear_interrupt(INT_EXT);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
while(TRUE)
{
delay_cycles(1);
}
}
|
In the above code, you don't set the initial edge that you want to
have it interrupt on. |
|
|
matthewmilford
Joined: 09 Feb 2021 Posts: 23
|
|
Posted: Wed Jun 16, 2021 1:33 pm |
|
|
temtronic
1. its primary job is really to do this interrupt. Everything else is secondary and not all that time sensitive (it only needs to go as fast as a human for display and stuff). So how fast or slow is semi - irrelevant.
2. I know in the end I won't use a delay....that was just a quick and dirty way of getting a pulse rather than setting a timer. I was trying to simplify the code as much as possible.
3. I put one in.... no change. Good thought though.
4. Okay so I swapped around the delay and gating to be in front of edge detection rather than after. Thus it should be checking if its high or low in the middle of the square wave rather than an edge. No change. Yes I am still using a delay to do this, if it would have worked I would write a timer to do it.
PCM
I am not using a crystal I removed the XT to make sure its not trying to use an external clock. I want to do it internal. Is this correct?
I swapped the edges back but either way that I put it, no change.
I added a line to set initial edge to interrupt on.
See new code.
Code: |
#include <18f26k42.H>
#device ADC = 10
#include <BMLCD420.c>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#fuses HS,NOWDT, NOPROTECT, NOPUT, NOLVP
#use delay(clock = 4MHz)
#define inputsignal PIN_B0
#define gate2 PIN_B2
#INT_EXT // external interrupt ISR
void EXT_ISR()
{
int1 high;
delay_ms(2);
output_high(gate2);
delay_us(50);
output_low(gate2);
if(input(inputsignal) == 1)
{
high=TRUE;
delay_cycles(1);
ext_int_edge(H_TO_L);
}
else
{
high=FALSE;
delay_cycles(1);
ext_int_edge(L_TO_H);
}
}
void main()
{
output_drive(gate2);
output_low(gate2);
clear_interrupt(INT_EXT);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
ext_int_edge(L_TO_H);
while(TRUE)
{
delay_cycles(1);
}
}
|
P.S.
Thanks for all the help, I really appreciate the feedback. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 16, 2021 2:09 pm |
|
|
matthewmilford wrote: |
#fuses HS,NOWDT, NOPROTECT, NOPUT, NOLVP
#use delay(clock = 4MHz)
|
This code above is for an external crystal.
The quick way to setup for the internal 4 MHz oscillator is to use this:
Code: | #fuses NOWDT, NOPROTECT, NOPUT, NOLVP
#use delay(internal = 4MHz)
|
|
|
|
matthewmilford
Joined: 09 Feb 2021 Posts: 23
|
|
Posted: Wed Jun 16, 2021 2:25 pm |
|
|
Okay fixed that. Still no change but certainly good to get it right. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 16, 2021 3:27 pm |
|
|
Have you run an LED blinker program to make sure your PIC is
really running at 4 MHz ? Example:
Code: | #include <18F26K42.h>
#fuses NOWDT
#use delay(internal=4M)
#define LED_PIN PIN_B1 // Put in a suitable pin
//=================================
void main()
{
while(TRUE)
{
output_toggle(LED_PIN);
delay_ms(500);
}
}
|
The LED circuit should be like this:
Code: |
pin 470 ohms LED
B1 -----/\/\/\/------->|----
|
|
----- Ground
---
-
|
|
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 478 Location: Montenegro
|
|
Posted: Wed Jun 16, 2021 4:13 pm |
|
|
It looks like a very simple thing to do, changing the firing edge of the interrupt. Those other guys answering you are doing it while they sleep, and then some. Have you tried changing PIC? Maybe your debugger doesn't work (not that I believe that). Have you checked if the appropriate SFR changes when you reverse the edge? I'd hook two LED's and toggle them inside ISR, one for L-H and the other for the H-L part of if statement. Just to see "live" what happens, which one glows. Maybe try EXT1, if your stuff is on a breadboard. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Jun 17, 2021 8:13 am |
|
|
Lets make a comment.
The edge changing code has worked many times for people here in the past.
However this chip is more complex, since it has three EXT interrupts. I'd
suspect you probably have to specify which interrupt is involved in the
change code to make it work.
However 'why use this'?. This PIC also supports IOC on this pin. Much
simpler. So:
Code: |
#include <18f26k42.H>
#device ADC = 10
#include <BMLCD420.c>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#fuses NOWDT, NOPROTECT, NOPUT, NOLVP
#use delay(internal = 4MHz)
#define inputsignal PIN_B0
#define gate2 PIN_B2
//#PIN_SELECT INT0=PIN_B0
#byte IOCBF=getenv("SFR:IOCBF")
#INT_IOC // external interrupt ISR
void EXT_ISR()
{
int1 high;
if(input(inputsignal) == 1)
{
high=TRUE;
delay_cycles(1);
}
else
{
high=FALSE;
delay_cycles(1);
}
IOCBF=FALSE;
}
void main()
{
output_drive(gate2);
output_low(gate2);
IOCBF=FALSE;
clear_interrupt(INT_IOC);
enable_interrupts(INT_IOC_B0); //enable IOC in both directions on B0
enable_interrupts(GLOBAL);
while(TRUE)
{
delay_cycles(1);
}
}
|
This enables IOC on pin B0 for both directions. Much easier. The only
complexity for this is you have to manually clear the IOCBF.0 bit
before the interrupt can be cleared. I've done this by just defining the
register and clearing this. |
|
|
matthewmilford
Joined: 09 Feb 2021 Posts: 23
|
|
Posted: Thu Jun 17, 2021 9:00 am |
|
|
Everyone,
I finally got a working code. A bit strange as, so far as I can tell the ext_int_edge command is not working properly on this chip. So, I decided to change the bits manually and with a bit of twiddling here is a small working code for doing both edges.
Code: |
#include <18f26k42.H>
#device ADC = 10
#include <BMLCD420.c>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#fuses NOWDT, NOPROTECT, NOPUT, NOLVP
#use delay(internal = 4MHz)
#define inputsignal PIN_B0
#define gate2 PIN_B2
#byte OPTION_REG = GETENV("SFR:INTCON0") // get OPTION_REG register address
#bit INTEDG = OPTION_REG.0
#INT_EXT // external interrupt ISR
void EXT_ISR()
{
delay_ms(2);
output_high(gate2);
delay_us(50);
output_low(gate2);
if(input(inputsignal) == 1)
{
delay_cycles(1);
//ext_int_edge(H_TO_L);
INTEDG = 0;
}
else
{
delay_cycles(1);
//ext_int_edge(L_TO_H);
INTEDG = 1;
}
}
void main()
{
output_drive(gate2);
output_low(gate2);
clear_interrupt(INT_EXT);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
ext_int_edge(L_TO_H);
while(TRUE)
{
delay_cycles(1);
}
}
|
|
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 478 Location: Montenegro
|
|
Posted: Thu Jun 17, 2021 10:15 am |
|
|
It's nice you have a working code and also that Mr. Ttelmah posted an alternative. And I do like his "only complexity" thing. One line, once :-). I'd like all the things to be that complex. BTW, what chip are you using for ZCD, to buy some?
Regards,
Samo |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 478 Location: Montenegro
|
|
Posted: Thu Jun 17, 2021 11:17 am |
|
|
It would be interesting to see the .lst code for this part of program with int_ext and manual change of the SFR. Maybe your version of CCS is the culprit for this behavior. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Thu Jun 17, 2021 11:23 am |
|
|
Yes. The interesting thing for me, is I haven't kept 5.102. I don't keep
versions where I have found a major issue. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19496
|
|
Posted: Fri Jun 18, 2021 1:12 am |
|
|
As I guessed (and mentioned earlier), the issue is simply that your code is
not telling the compiler 'which' interrupt to set the edge on.
You need:
Code: |
#INT_EXT // external interrupt ISR
void EXT_ISR()
{
int1 high;
if(input(inputsignal) == 1)
{
high=TRUE;
delay_cycles(1);
ext_int_edge(0,H_TO_L);
}
else
{
high=FALSE;
delay_cycles(1);
ext_int_edge(0,L_TO_H);
}
}
|
Note the '0'.
Though the manual says these should default to the first interrupt, checking
the assembly on 5.101 (since I don't have 5.102), shows that without this
the second entry is accessing the FSR register, and not the INTCON0
register. Add the zero, and the first clears INT0EDG bit while the second
sets it. |
|
|
|