|
|
View previous topic :: View next topic |
Author |
Message |
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
timer1 external |
Posted: Wed Jun 13, 2012 6:13 pm |
|
|
I use one of pic16f684 in difficult condition (-15*C) and i chose to put crystal
resonator as 4MHz because is tested in low temperature.
I try to make interrupt of every 1 second with timer1 external but without any success.
If i chose T1_INTERNAL it's works but without good precision , i think T1_INTERNAL is copy of internal RC oscillator/4 - is correct?
And if i chose T1_EXTERNAL or T1_EXTERNAL_SYNC the timer don't work.
I am very confused and i spend a lot of time of this simple problem.
I posted a simple try of code.
Code: | #include <16F684.h>
#device *=16
//#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //High speed Osc (> 4mhz)
#FUSES PROTECT //Code not protected from reading
//#FUSES NOBROWNOUT //No brownout reset
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#use delay(clock=4000000)
#Byte TMR1H = 0x0F // TIMER1 HIGH BYTE LOOK DATASHEET
#Byte T1CON = 0x10 //TIMER1 CONFIG REGISTER LOOK DATASHEET
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void main()
{
setup_oscillator(OSC_4MHZ);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while(true)
{
}
}
//=======================****************************************
#int_TIMER1
void TIMER1_isr()
{
Bit_clear(T1CON,7); //Enable access to the individual bytes of the timer register
Bit_Set(TMR1H,854); //Add 4000000 to timer1 by setting high bit or timer register
Bit_Set(T1CON,7); //Disable access to the individual bytes of the timer register
if(input_state(pin_c1) == false)
output_high(pin_c1); // !comanda
else
output_low(pin_c1); // !comanda
} |
I give many beer for any help.
THX. Bogdan |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jun 13, 2012 7:53 pm |
|
|
Quote: | Bit_Set(TMR1H,854);
|
What is the 854 ? TMR1H is an 8-bit register. It only has bits from 0 to 7.
The CCS manual lists the possible parameters for bit_set():
Quote: |
bit_set( )
Syntax: bit_set(var, bit)
Parameters: var may be a 8, 16 or 32 bit variable (any lvalue).
bit is a number 0-31 representing a bit number, 0 is the least significant bit.
|
Do you have a 32.768 KHz crystal (and capacitors) on the Timer1
oscillator pins ? You need them. These are different pins than the
main oscillator pins.
Also, to enable the Timer1 external crystal circuit, you need to do this:
Quote: |
setup_timer_1(T1_EXTERNAL | T1_DIV_BY_1 | T1_CLK_OUT); |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19482
|
|
Posted: Thu Jun 14, 2012 1:48 am |
|
|
T1_INTERNAL, has nothing to do with an RC oscillator. It is the master clock/4. Whatever source this is from.
Best Wishes |
|
|
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
|
Posted: Thu Jun 14, 2012 6:05 am |
|
|
I have external crystal 4MHz and capacitors. I can't put 32768 kHz, my applications don't permit that, only 4MHz crystal.
Entire program's include communication rs232 and I2C works fine.
The single problem is the precise timer.
My application write with rs232 or I2C a data in internal eeprom of 16f684 and with condition of 1 pin decrement time of eeprom in seconds and ms.
Ex: my time is 123.4 = my 16f684 wait when powered this time in second and switch the state of 1 pin.
I try with T1_INTERNAL but the error of timer is random not in line.
I posted entire code.
Main file:
Code: | #include "16f684.h"
#device *=16
#FUSES NOWDT //No Watch Dog Timer
//#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES XT //Crystal osc <= 4mhz for PCM/PCH , 3mhz to 10 mhz for PCD
#FUSES NOPROTECT //Code not protected from reading
#FUSES BROWNOUT //Reset when brownout detected
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOPUT //No Power Up Timer
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#use delay(clock=4000000)
#use rs232(baud=2400,xmit=PIN_c0,rcv=PIN_A2,bits=8) // ,TIMEOUT=8000
#Byte TMR1H = 0x0F // TIMER1 HIGH BYTE LOOK DATASHEET
#Byte T1CON = 0x10 //TIMER1 CONFIG REGISTER LOOK DATASHEET
#include </src/operatii.c>
#include </src/serial_1.c>
//====================================================================================================
//float triger = 0;
int1 flag_data = false;
//int16 start_err = 1810;
//===============================//=======================//==========================================
#int_RTCC
void RTCC_isr(void)
{
counter++;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#int_EXT
void EXT_isr(void)
{
cifre.id = fgetc();
cifre.m = fgetc();
cifre.s = fgetc();
cifre.z = fgetc();
cifre.u = fgetc();
flag_data = true;
//disable_interrupts(INT_TIMER1);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//=========//===========//===========//=========//========//=========//========//=========//========//========
void main()
{
output_low(pin_c1);
output_high(pin_c2);
output_high(pin_c3);
output_high(pin_c5);
// output_float(pin_a2);
// output_low(pin_c0);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
setup_ccp1(CCP_PWM);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
setup_oscillator(OSC_4MHZ);
// setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //524 ms overflow
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_4);
// setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);
setup_timer_1(T1_EXTERNAL|T1_CLK_OUT); // external TIMER1 with
setup_timer_2(T2_DIV_BY_1, 180, 1); // 100 kHz // only from PWM
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// set_pwm1_duty(0); // 25% duty cycle on pin C2 // 160L pt 96kHz
read_eeprom_data();
triger = 0;
suma_t();
set_RTCC(0);
// set_timer0(0);
enable_interrupts(INT_RTCC);
// enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
// printf("%Lu\n\r", triger);
if(input(PIN_C4)==0) //if button pressed
{
disable_interrupts(INT_EXT);
}
else
{
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
disable_interrupts(int_RTCC);
}
while (true)
{
bum();
//******************************************************
if(flag_data == true)
{
disable_interrupts(INT_EXT);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if(cifre.id == 0xA0)
{
test_min_max_data();
re_send_eeprom_data();
flag_data = false;
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
// disable_interrupts(INT_TIMER1);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if(cifre.id == 0xD0)
{
re_send_eeprom_data();
flag_data = false;
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
// disable_interrupts(INT_TIMER1);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if(cifre.id != (0xD0 && 0xA0))
{
delay_ms(3000);
putc(0xB2);// limit min config
putc(0xB2);
clear_variable();
reset_cpu();
}
}
}
}
// if (INPUT_STATE(PIN_B0) == 0)
// { output_low(pin_d7);
//=======================****************************************
#int_TIMER1
void TIMER1_isr() // 2^16= 65536/2 = 32768 * 1/32.768Hz <--- (1sec)
{
// counter++
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Bit_clear(T1CON,7); //Enable access to the individual bytes of the timer register
Bit_Set(TMR1H,7); //Add 32768 to timer1 by setting high bit or timer register
Bit_Set(T1CON,7); //Disable access to the individual bytes of the timer register
if(input_state(pin_c1) == false)
output_high(pin_c1); // !comanda
else
output_low(pin_c1); // !comanda
} |
Operatii file.
Code: | unsigned int16 counter = 0;
unsigned int16 counter_s = 0;
struct{
unsigned int8 id; // ident
unsigned int8 m; // mii
unsigned int8 s; // sute
unsigned int8 z; // zeci
unsigned int8 u; // unit
}cifre;
struct{
unsigned int8 m_1; // mii
unsigned int8 s_1; // sute
unsigned int8 z_1; // zeci
unsigned int8 u_1; // unit
}suma_1;
float temporizare = 0;
unsigned int16 triger = 0;
unsigned int16 err_min_max = 0;
//==============================================================================
void init_cifre()
{
cifre.m = 0;
cifre.s = 0;
cifre.z = 0;
cifre.u = 0;
}
//==============================================================================
void suma_t()
{
temporizare = ((int16)suma_1.m_1*1000)+((int16)suma_1.s_1*100)+((int16)suma_1.z_1*10)+suma_1.u_1 ;
// triger *= 24;
// triger/= 10;
temporizare = temporizare*0.976464f; //0.9785f
triger = temporizare ;
// triger = triger * 24; // normalize in concordance of timer
// triger = triger / 10; // normalize in concordance of timer
// triger = triger - 30;
// printf("%Lu\n\r", triger);
}
//==============================================================================
void suma_err()
{
err_min_max = ((int16)cifre.m*1000) + ((int16)cifre.s * 100) + ((int16)cifre.z * 10) + cifre.u ;
}
//===============================================================================
void read_eeprom_data()
{
suma_1.m_1 = read_eeprom(0x00);
suma_1.s_1 = read_eeprom(0x01);
suma_1.z_1 = read_eeprom(0x02);
suma_1.u_1 = read_eeprom(0x03);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void bum()
{
if(counter >= 100)
{
counter_s ++;
counter = 0;
set_RTCC(0);
}
// triger --;
// delay_us(1990);
if(counter_s >= triger)
{
delay_ms(0);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
set_pwm1_duty(360L); // 40L
delay_ms(825);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
output_low(pin_c3);
delay_ms(2000);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
output_high(pin_c1); // !comanda
output_low(pin_c2); // comanda
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void test_bum()
{
if(counter >= 3000)
{
counter_s ++;
counter = 0;
}
if(counter_s >= 6)
{
output_high(pin_c1); // !comanda
output_low(pin_c2); // comanda
}
} |
and serial file.
Code: |
int1 flag_err_min = false;
int1 flag_err_max = false;
extern int1 flag_data;
// extern unsigned int16 triger;
extern unsigned int16 err_min_max;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//===========================================
//===============================================
void clear_variable()
{
cifre.id = 0;
cifre.m = 0;
cifre.s = 0;
cifre.z = 0;
cifre.u = 0;
}
//=============================================
void re_send_eeprom_data()
{
unsigned int8 temp_m = 0;
unsigned int8 temp_s = 0;
unsigned int8 temp_z = 0;
unsigned int8 temp_u = 0;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
temp_m = read_eeprom(0x00);
temp_s = read_eeprom(0x01);
temp_z = read_eeprom(0x02);
temp_u = read_eeprom(0x03);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
delay_ms(3000);
putc(0xC0);
putc(temp_m);
delay_ms(20);
putc(0xC1);
putc(temp_s);
delay_ms(20);
putc(0xC2);
putc(temp_z);
delay_ms(20);
putc(0xC3);
putc(temp_u);
delay_ms(20);
}
//=============================================
//================================================
void write_eep_data()
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if(cifre.id == 0xA0)
{
write_eeprom(0x00, cifre.m);
write_eeprom(0x01, cifre.s);
write_eeprom(0x02, cifre.z);
write_eeprom(0x03, cifre.u);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// test_min_max_data();
}
//================================================
void test_min_max_data()
{
unsigned int16 temp_min = 0;
unsigned int16 temp_max = 0;
// unsigned int16 temp_s = 0;
suma_err();
//~~~~~~~~~~~~~~~~~ pt minim ~~~~~~~~~~~~~~~~~~~~~
temp_min = read_eeprom(0xF1);
temp_min += (int16)read_eeprom(0xF0) * 100;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~ pt maxim ~~~~~~~~~~~~~~~~~~~~~
temp_max = read_eeprom(0xFF);
temp_max += (int16)read_eeprom(0xFE) * 100;
//~~~~~~~~~~~~~~ verif min max ~~~~~~~~~~
if(err_min_max < temp_min)
{ flag_err_min = true;
delay_ms(3000);
putc(0xB0);// limit min config
putc(0xB0);
clear_variable();
// reset_cpu();
}
if(err_min_max > temp_max)
{ flag_err_max = true;
delay_ms(3000);
putc(0xB1);// limit max config
putc(0xB1);
clear_variable();
// reset_cpu();
}
// if(temp_s == 9999)
// reset_cpu();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if((flag_err_min && flag_err_max) == false)
{
write_eep_data();
}
}
//===============================================
|
I try to normalize the error of timer. Normally I think the right value is 1024 ms and not 1000 ms because is impossible to divide exactly 4MHz to 1000.
Code: |
temporizare = temporizare*0.976464f; //0.9785f
|
I have 1 solution but I don't know how to do that.
To divide the timer with 8 and with 125
Code: |
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_8);
|
and = 4000000/4 = 1000000 / 8 = 125000 / 125 = 1000ms.
But again the questions RTCC_INTERNAL copy master clock (XT 4MHz) or internal RC oscillator ?
Is not important what timer I use 0 or 1.
THX again for fast reply. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19482
|
|
Posted: Thu Jun 14, 2012 8:16 am |
|
|
One key thing leaps out, before going very far. You _cannot_ expect an interrupt based timer to keep reasonable time, if you sit for a minimum of 0.02 seconds inside an other interrupt. Seriously, if you are using 'int_ext', to give serial reception, the interrupt means you have the falling edge on a start bit, and _one_ character may be coming. Using software serial this way is 'bad enough', but to then sit and wait for six characetrs, could have you locked in this interrupt 'for ever', if the bits don't arrive....
Rethink this code as the first _vital_ thing.
Realistically far better to switch to a chip with a USART, and give yourself a chance.
Repeat the old mantra, that an interrupt _should only do the thing that the interrupt signal implies, and exit ASAP. Anything else is asking for trouble.
The rest is I'm afraid a mess as well.
For getting an accurate time, do a search on the forum. There was a tidy routine for generating accurate times from a 'tick' running at an odd interval using integer maths, and letting a counter wrap, to give exact timings, posted a long time ago.
Best Wishes |
|
|
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
|
Posted: Thu Jun 14, 2012 8:24 am |
|
|
Is impossible to switch to other chip and I don't have any solution for serial.
If serial running, timer is disabled and if timer is active serial is disabled.
Serial working with small problem,
Maximum count of timer is 900 sec and precision must be less than 10 ms.
Thx for reply and if you want to send a link with timer trick, I search 2 h and can't find any solution.
Thx again
Bogdan |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jun 15, 2012 5:28 pm |
|
|
Quote: | I you want to send a link with timer trick, I search 2 h and can't find any solution. |
It's in the CCS forum. You don't need a 2 hr search. Go to the CCS
Code Library forum. http://www.ccsinfo.com/forum/viewforum.php?f=2
It's on the first page. Look for:
Quote: | Timer based Real Time Clock (RTC) |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9218 Location: Greensville,Ontario
|
|
Posted: Fri Jun 15, 2012 7:31 pm |
|
|
PCM p is right again ! I've used that code on a number of projects over the past couple of years so I know it does work. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19482
|
|
Posted: Sat Jun 16, 2012 1:40 am |
|
|
Important also to say, that you can improve the serial handling by a huge factor, by just receiving one character at a time.
Basically the same as the 'standard' approach if you had a hardware USART. Just have your interrupt trigger reception of one character and exit. Use a state machine so you know 'where' you are in the string of characters. Difference is that at the end of every character you have at least half a character time, when other jobs (like servicing the timer interrupt) can be done. This gives everything else a 'chance'....
Best Wishes |
|
|
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
|
Posted: Sun Jun 17, 2012 9:31 am |
|
|
I understand now. but other solution to detect serial transmission without ext interrupt?
This solution has simple for me but now i see the error of this.
True i have something problems but with 2400 and 19600 works.
I say again is impossible to switch to other chip . This is condition :d.
I resolve with timer i read in library code a tutorial and i use timer0.
THX again.
Maybe now other solution with serial interrupt. |
|
|
|
|
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
|