View previous topic :: View next topic |
Author |
Message |
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
capture mode in pic18F13K22 |
Posted: Mon Jul 10, 2017 2:41 am |
|
|
Earlier I used capture mode with pic18F2520. It was working good. For some reasons, I have to change the controller to 18F13K22.
Using Internal oscillator.
I tried to debug the code using Pickit3. Though i don't apply any frequency, the tm3_variable is not zero. Any help please.
Code: |
#include "18f13k22.h"
#FUSES INTRC_IO, PLLEN
#use delay(clock = 64000000)
#BYTE INTCON = 0xFF2
#BYTE TMR0H = 0xFD7
#BYTE TMR0L = 0xFD6
#BYTE TRISB = 0xF93
#BYTE PORTA = 0xF80
#BYTE PORTB = 0xF81
#BYTE PORTC = 0xF82
#BYTE T3CON = 0xFB1
#BYTE TMR3H = 0xFB3
#BYTE TMR3L = 0xFB2
#BYTE T0CON = 0xFD5
#BIT TMR0IF = INTCON.2
#BIT TMR0IE = INTCON.5
#BIT TMR0ON = T0CON.7
#BIT TMR3ON = T3CON.0
#define CAL_LED1 PIN_C7 // Material Present Status
#define LED1 PIN_C0 // Relay LED status
#define MAX_SAMPLE 100 // Sets No of period samples
// Variable Declaration
unsigned int8 sample = 0; // Current sample
unsigned int32 total_period; // Total period count in machine cycles
unsigned int16 new_ccp_value; //
unsigned int16 old_ccp_value; //
unsigned int16 new_period_value; // latest period value = difference between ccp values
unsigned int16 frequency;
float capacitance, disp_value;
unsigned int16 delay_ms_flag = 0;
unsigned int16 seconds;
unsigned int seconds1 = 0;
int1 flag_500ms = 0, flag1_500ms = 0;
unsigned int16 flag = 0;
unsigned int16 tm3_Variable;
float read_capacitance();
void timer0_init();
#int_ccp1
void ccp1_isr()
{
new_ccp_value = CCP_1; // captures the timer value
if ((sample > 0)&&(sample<MAX_SAMPLE+1)) // Ignores sample zero!
{
new_period_value = new_ccp_value - old_ccp_value; //
total_period+=new_period_value; //
}
old_ccp_value = new_ccp_value; // ready for next sample
if (sample < (MAX_SAMPLE+1)) // stops overflow when done
{
sample++; // Increment the variable
}
}
#INT_TIMER0
void timer0_isr()
{
if(TMR0IF == 1)
{
delay_ms_flag++; // increment variable
seconds++;
flag++; // increment variable
if(flag >= 500) // for 500 ms
{
flag_500ms = 0;
}
if(flag >= 1000) // for 1second
{
flag = 0; // reset variable to 0
flag_500ms = 1;
}
if(seconds >= 1000) // every 1 second
{
seconds = 0;
SECONDS1++; // Variables are incremented
}
TMR0IF = 0; // clear flag
TMR0IE = 1; // enable interrupt
TMR0H = 0xC1; // 1ms for 64Mhz
TMR0L = 0x7F;
}
}
void main()
{
TRISB = 0b01110000;
PORTA = 0; // configure PORTA as low
PORTB = 0; // configure PORTB as low
PORTC = 0;
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF|ADC_TAD_MUL_0);
setup_comparator (NC_NC_NC_NC); // Disable comparator
setup_ccp1(CCP_CAPTURE_RE); // Looks for Rising edge
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1); // Timer1 internal & 1:1 Prescaler
timer0_init(); // Timer0 Initialization
enable_interrupts(INT_CCP1); // enables the CCP2 Interupt
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL); // Enables global interrupt
T3CON = 0b10000110; // 16 bit, external clock input, TMR3 OFF
while(1)
{
TMR3H = 0; // Values are reset to 0
TMR3L = 0;
TMR3ON = 1; // Timer 3 ON
delay_ms(10); // 10 ms delay
TMR3ON = 0; // Timer 3 OFF
tm3_Variable = TMR3H << 8 | TMR3L; // Get the values
if(tm3_Variable == 0) // if the values are 0
{
output_low(CAL_LED1);
delay_ms(50);
output_high(CAL_LED1);
delay_ms(50);
TMR3H = 0; // Values are reset to 0
TMR3L = 0;
output_low(LED1);
}
else
{
read_capacitance(); // Read the capacitance.
disp_value = capacitance;
if(flag_500ms == 0)
output_high(CAL_LED1);
else if(flag_500ms == 1)
output_low(CAL_LED1);
}
}
}
float read_capacitance()
{
total_period = 0; // Ensure variables are reset
sample = 0; //
while (sample<(MAX_SAMPLE+1)){} // waits here 'til done sampling
frequency = (int32)((16000000*MAX_SAMPLE)/(total_period)); // calculates the frequency which is non-linear ,
capacitance = 2467917.077/frequency; // frequency converted to capacitance. to make it linear
return capacitance;
}
void timer0_init()
{
T0CON = 0b00001000; // 16 bit, prescaler not assigned
TMR0H = 0xC1; // 1ms for 64Mhz
TMR0L = 0x7F;
TMR0ON = 1; // Timer1 ON
TMR0IF = 0; // set Timer1 Interrupt Flag as zero
TMR0IE = 1; // Set Timer1 Interrupt Enable = 1
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 10, 2017 10:35 am |
|
|
Run a 1 Hz LED blink test. I suspect that your PIC is not really running
at 64 MHz. There may be other problems, but that one should be
checked first. |
|
|
hemnath
Joined: 03 Oct 2012 Posts: 242 Location: chennai
|
|
Posted: Mon Jul 10, 2017 9:31 pm |
|
|
Thank you. I used the same code to test the LED blinking. By applying the frequency input, the main code goes into else statement where it has a blinking of LED for 500 ms. It is working. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jul 10, 2017 9:57 pm |
|
|
So is your whole program now working correctly, or is just the LED part
working ? Do you still have a problem ? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19499
|
|
Posted: Tue Jul 11, 2017 6:52 am |
|
|
Some comments on just one routine:
Code: |
#INT_TIMER0
void timer0_isr()
{
if(TMR0IF == 1)
//Pointless. Wasted instructions. The interrupt handler is only
//called if the interrupt flag _is_ set....
{
delay_ms_flag++; // increment variable
seconds++;
flag++; // increment variable
if(flag >= 500) // for 500 ms
{
flag_500ms = 0;
}
if(flag >= 1000) // for 1second
{
flag = 0; // reset variable to 0
flag_500ms = 1;
}
if(seconds >= 1000) // every 1 second
{
seconds = 0;
SECONDS1++; // Variables are incremented
}
TMR0IF = 0; // clear flag
//Pointless. The compiler will always clear the flag for you
//unless you specify for it not to...
TMR0IE = 1; // enable interrupt
//Pointless. How can the code get here unless the interrupt
//is already enabled....
TMR0H = 0xC1; // 1ms for 64Mhz
TMR0L = 0x7F;
//These values should be loaded ASAP in the routine.
}
}
//So lets do the same routine using the compiler...
#define TIMER0_PRELOAD 0xC17F
#INT_TIMER0
void timer0_isr(void)
{
set_timer0(TIMER0_PRELOAD); //set the timer
delay_ms_flag++; // increment variable
seconds++;
flag++; // increment variable
if(flag >= 500) // for 500 ms
{
flag_500ms = 0;
}
if(flag >= 1000) // for 1second
{
flag = 0; // reset variable to 0
flag_500ms = 1;
}
if(seconds >= 1000) // every 1 second
{
seconds = 0;
SECONDS1++; // Variables are incremented
}
}
|
However 'think again'. Why not use timer2?.
Set this to use the /16 prescaler. Count to 250 (249 in PR2), and to interrupt every fourth time. Result, an accurate 1mSec interrupt.
setup_timer_2(T2_DIV_BY_16,249,4); //16MHz/(16*250*4) = 1000Hz
No need to load timer values etc..
Now another comment. The 32bit value being reset in the read routine "total_period=0". What happens if an interrupt occurs during this load?...
For any variable larger than 8bit, that is externally and is changed inside an interrupt, you need to disable interrupts during the load.
Now, like PCM_programmer, I'm surprised if your chip really is clocking correctly at 64MHz. A bit of a fluke. Use this syntax:
Code: |
#use delay(INTERNAL = 64MHz)
#FUSES INTRC_IO
|
The 'internal' setting ensures the compiler sets up the PLL, and selects the 16MHz clock branch and PLL. Having the INTRC_IO fuse _after_ this, then ensures the IO pin is set correctly as well. |
|
|
|