|
|
View previous topic :: View next topic |
Author |
Message |
pirraca Guest
|
problem with pic16f886 and timers |
Posted: Tue Mar 24, 2009 7:20 am |
|
|
Dear all,
I'm having a problem while trying some code.
I receive velocity info by I2C. I put this info in the PWM. I'm reading too the encoder (timer1 like external) each 122 Hz (timer0 interrupt).
The problem is, that the pwm value is not updated and the velocity is always the same in the gear...
Could someone help me??
thanksss
PD.- If I disabled timer 0 interrupt, all works fine.
Code: |
#include <16F886.h>
#include <i2c_config.h>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT, NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa1, FORCE_HW)
#define INTS_PER_SECOND 72 // (20000000/(4*256*256))
BYTE array[4];
BYTE pwm1;
BYTE pwm2;
long time=1,flancos=0;
#int_rtcc
void clock_isr()
{
long value1,value2;
output_high(PIN_B1);
if(time==1)
{
value1=get_timer1();
time=2;
}
else
{
value2=get_timer1();
flancos=value2-value1;
time=1;
}
output_low(PIN_B1);
}
#INT_SSP
void ssp_interupt ()
{
BYTE state;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
array[state] = i2c_read();
if(state == 2){ //Second received byte is data
if (array[0]==0x01){
if( bit_test(array[1],7)){
pwm1 = 0;
pwm2 = array[state];
}
else{
pwm2 = 0;
pwm1 = array[state];
}
}
}
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(0x01);
}
}
void main ()
{
enable_interrupts(INT_SSP);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_ccp2(CCP_PWM); // Configure CCP1 as a PWM
setup_timer_0( RTCC_INTERNAL | RTCC_DIV_32); ///IF I COMMENT THIS LINE, AL WORKS OK
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); //use low power 32kHz crystal
setup_timer_2(T2_DIV_BY_1, 255, 1);
set_timer1(0);
pwm1 = 0;
pwm2 = 0;
while (TRUE){
set_pwm1_duty(pwm1);
set_pwm2_duty(pwm2);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Mar 24, 2009 12:28 pm |
|
|
Quote: | PD.- If I disabled timer 0 interrupt, all works fine. |
Do some experiments. Comment out the guts of the #int_rtcc isr routine.
In your code, the two global variables are not used outside the isr, so
it won't affect any other code that might use those variables, if you
comment the isr. By commenting out the internal isr code, this will tell
you if merely the fact of the isr occuring, is what's causing the problem.
Quote: | #int_rtcc
void clock_isr()
{
/* Comment out this code.
long value1,value2;
output_high(PIN_B1);
if(time==1)
{
value1=get_timer1();
time=2;
}
else
{
value2=get_timer1();
flancos=value2-value1;
time=1;
}
output_low(PIN_B1);
*/
} |
Quote: | #use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa1, FORCE_HW) |
This should be an even number, such as 0xa0. It may work anyway,
but it's more correct if it's set to 0xa0.
Also, the 16F886 is buggy when used as an i2c slave. This thread
talks about it. He didn't post his final code, but he gives some
suggestions on how to fix the bugs.
http://www.ccsinfo.com/forum/viewtopic.php?t=38091 |
|
|
pirraca Guest
|
|
Posted: Tue Mar 24, 2009 4:36 pm |
|
|
I will try it, and I will comment the results!
Regards! |
|
|
pirraca Guest
|
|
Posted: Wed Mar 25, 2009 4:06 am |
|
|
Quote: |
Do some experiments. Comment out the guts of the #int_rtcc isr routine.
In your code, the two global variables are not used outside the isr, so
it won't affect any other code that might use those variables, if you
comment the isr. By commenting out the internal isr code, this will tell
you if merely the fact of the isr occuring, is what's causing the problem. |
I have comment this code, and the results are the same
Quote: | This should be an even number, such as 0xa0. It may work anyway,
but it's more correct if it's set to 0xa0 |
Ok, I have changed this part of code
Quote: | Also, the 16F886 is buggy when used as an i2c slave. This thread
talks about it. He didn't post his final code, but he gives some
suggestions on how to fix the bugs.
|
I have made this changes, but there is no result...
I don't know how introduce this part in my code
Code: |
#bit SEN = 0x91.0
#bit CKP = 0x14.4 |
regards!
I continue trying |
|
|
Ttelmah Guest
|
|
Posted: Wed Mar 25, 2009 4:36 am |
|
|
Some other little comments.
Local variables, are _dynamic_, unless you declare them as static. You are reading two timer values, on different passes through the interrupt, then performing arithmetic on these two values. Value1, _must_ be declared as 'static', or it is not guaranteed to hold the value from the 'last' pass...
You should be sending a nack for the second byte of data received.
I'd put the SSP interrupt in front of the RTCC interrupt, or add a statement, giving the SSP priority. Otherwise if the RTCC triggers close to the SSP interrupt, a lot of extra delay will be added to the SSP handling.
It is possibly worth adding a check in the main loop, and _only_ write the new PWM values, if they have changed. Otherwise, you are looping very fast, continuously writing the same values, before the PWM has a chance to actually respond to the change...
Hopefully, you have correctly amended the I2C address. The 'point' is that the address itself is the upper seven bits of the number given (so in your case, the actual device address is '0x50'. The bottom bit, is the flag for read/write. So in the slave, the address byte, needs to be the required address (0x50), times 2 (0xA0), and can only ever be an even number. Then the master if wanting to _write_ to this device, has to send the number '0xA0' (0x50*2, + 0), while to read from the same device, has to send '0xA1' (0x50*2, + 1). '1' is the 'read' flag.
On the changes, you just add the two bit definition lines, up near the head of your code, and then do what he says below - so in your main, before entering the 'while' loop, add the line:
SEN=TRUE;
and as the last line in your ISR, add:
CKP=TRUE;
Best Wishes |
|
|
pirraca Guest
|
|
Posted: Thu Mar 26, 2009 4:47 am |
|
|
First of all, thanks at all
My new code is: Code: | #include <16F886.h>
#include <i2c_config.h>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT, NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa1, FORCE_HW)
#define INTS_PER_SECOND 72 // (20000000/(4*256*256))
BYTE array[4];
BYTE pwm1;
BYTE pwm2;
#bit SEN = 0x91.0
#bit CKP = 0x14.4
long time=1,flancos=0;
#int_rtcc
void clock_isr()
{
static long value1,value2;
output_high(PIN_B1);
if(time==1)
{
value1=get_timer1();
time=2;
}
else
{
value2=get_timer1();
flancos=value2-value1;
time=1;
}
output_low(PIN_B1);
}
#INT_SSP
void ssp_interupt ()
{
BYTE state;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
array[state] = i2c_read();
if(state == 2){ //Second received byte is data
if (array[0]==0x01){
if( bit_test(array[1],7)){
pwm1 = 0;
pwm2 = array[state];
}
else{
pwm2 = 0;
pwm1 = array[state];
}
}
}
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(0x01);
}
CKP=TRUE;
}
void main ()
{
enable_interrupts(INT_SSP);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_ccp2(CCP_PWM); // Configure CCP1 as a PWM
setup_timer_0( RTCC_INTERNAL | RTCC_DIV_32); ///IF I COMMENT THIS LINE, AL WORKS OK
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); //use low power 32kHz crystal
setup_timer_2(T2_DIV_BY_1, 255, 1);
set_timer1(0);
pwm1 = 0;
pwm2 = 0;
SEN=TRUE;
while (TRUE){
set_pwm1_duty(pwm1);
set_pwm2_duty(pwm2);
}
} |
The new code does not work anyway, the i2c signal is an square signal and has no information. I think I am doing something wrong...
Thank you for your help |
|
|
pirraca Guest
|
sorry, I put a wrong code |
Posted: Thu Mar 26, 2009 6:02 am |
|
|
this is the correct code that continues working wrong
Code: | #include <16F886.h>
#include <i2c_config.h>
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT, NOLVP
#use delay(clock=4000000)
#use i2c(SLAVE, SDA=PIN_C4, SCL=PIN_C3, address=0xa1, FORCE_HW)
#define INTS_PER_SECOND 72 // (20000000/(4*256*256))
BYTE array[4];
BYTE pwm1;
BYTE pwm2;
#bit SEN = 0x91.0
#bit CKP = 0x14.4
long time=1,flancos=0;
#INT_SSP
void ssp_interupt ()
{
BYTE state;
state = i2c_isr_state();
if(state < 0x80) //Master is sending data
{
array[state] = i2c_read();
if(state == 2){ //Second received byte is data
if (array[0]==0x01){
if( bit_test(array[1],7)){
pwm1 = 0;
pwm2 = array[state];
}
else{
pwm2 = 0;
pwm1 = array[state];
}
}
}
}
if(state >= 0x80) //Master is requesting data
{
i2c_write(0x01);
}
CKP=TRUE;
}
#int_rtcc
void clock_isr()
{
static long value1,value2;
output_high(PIN_B1);
if(time==1)
{
value1=get_timer1();
time=2;
}
else
{
value2=get_timer1();
flancos=value2-value1;
time=1;
}
output_low(PIN_B1);
}
void main ()
{
enable_interrupts(INT_SSP);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_ccp2(CCP_PWM); // Configure CCP1 as a PWM
setup_timer_0( RTCC_INTERNAL | RTCC_DIV_32); ///IF I COMMENT THIS LINE, AL WORKS OK
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); //use low power 32kHz crystal
setup_timer_2(T2_DIV_BY_1, 255, 1);
set_timer1(0);
pwm1 = 0;
pwm2 = 0;
SEN=TRUE;
while (TRUE){
set_pwm1_duty(pwm1);
set_pwm2_duty(pwm2);
}
} |
the gear walks good, but in a random time, the i2c is not writted well and it continues at high level
the master i2c part is an AVR32 from atmel |
|
|
pirraca Guest
|
|
Posted: Thu Mar 26, 2009 7:29 am |
|
|
Ttelmah wrote: | Some other little comments.
Local variables, are _dynamic_, unless you declare them as static. You are reading two timer values, on different passes through the interrupt, then performing arithmetic on these two values. Value1, _must_ be declared as 'static', or it is not guaranteed to hold the value from the 'last' pass...
You should be sending a nack for the second byte of data received.
I'd put the SSP interrupt in front of the RTCC interrupt, or add a statement, giving the SSP priority. Otherwise if the RTCC triggers close to the SSP interrupt, a lot of extra delay will be added to the SSP handling.
It is possibly worth adding a check in the main loop, and _only_ write the new PWM values, if they have changed. Otherwise, you are looping very fast, continuously writing the same values, before the PWM has a chance to actually respond to the change...
Hopefully, you have correctly amended the I2C address. The 'point' is that the address itself is the upper seven bits of the number given (so in your case, the actual device address is '0x50'. The bottom bit, is the flag for read/write. So in the slave, the address byte, needs to be the required address (0x50), times 2 (0xA0), and can only ever be an even number. Then the master if wanting to _write_ to this device, has to send the number '0xA0' (0x50*2, + 0), while to read from the same device, has to send '0xA1' (0x50*2, + 1). '1' is the 'read' flag.
On the changes, you just add the two bit definition lines, up near the head of your code, and then do what he says below - so in your main, before entering the 'while' loop, add the line:
SEN=TRUE;
and as the last line in your ISR, add:
CKP=TRUE;
Best Wishes |
why is the reason of this problem??
my pic, gives a NACK in the second byte it receive, but I don't know how repair it
regards |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Mar 26, 2009 4:25 pm |
|
|
Also, you are enabling interrupts before you setup all the devices that
will cause an interrupt. You should move the 3 lines for the interrupt
enables so they come after all the setup code. See below:
Quote: | void main ()
{
*** Delete these 3 lines ***
enable_interrupts(INT_SSP);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
-----------------
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_ccp2(CCP_PWM); // Configure CCP1 as a PWM
setup_timer_0( RTCC_INTERNAL | RTCC_DIV_32); ///IF I COMMENT THIS LINE, AL WORKS OK
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); //use low power 32kHz crystal
setup_timer_2(T2_DIV_BY_1, 255, 1);
set_timer1(0);
pwm1 = 0;
pwm2 = 0;
SEN=TRUE;
*** Add these 3 lines ***
enable_interrupts(INT_SSP);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while (TRUE){
set_pwm1_duty(pwm1);
set_pwm2_duty(pwm2);
}
} |
|
|
|
pirraca Guest
|
|
Posted: Thu Mar 26, 2009 5:31 pm |
|
|
PCM programmer wrote: | Also, you are enabling interrupts before you setup all the devices that
will cause an interrupt. You should move the 3 lines for the interrupt
enables so they come after all the setup code. See below:
Quote: | void main ()
{
*** Delete these 3 lines ***
enable_interrupts(INT_SSP);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
-----------------
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_ccp2(CCP_PWM); // Configure CCP1 as a PWM
setup_timer_0( RTCC_INTERNAL | RTCC_DIV_32); ///IF I COMMENT THIS LINE, AL WORKS OK
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); //use low power 32kHz crystal
setup_timer_2(T2_DIV_BY_1, 255, 1);
set_timer1(0);
pwm1 = 0;
pwm2 = 0;
SEN=TRUE;
*** Add these 3 lines ***
enable_interrupts(INT_SSP);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while (TRUE){
set_pwm1_duty(pwm1);
set_pwm2_duty(pwm2);
}
} |
|
Yes, I think its better too.
Thank you for your help
pd.- the programm still doesn't works |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Mar 27, 2009 11:27 am |
|
|
Does the modified code work if you disable the INT_RTCC interrupts ? |
|
|
pirraca Guest
|
|
Posted: Sat Mar 28, 2009 5:21 pm |
|
|
PCM programmer wrote: | Does the modified code work if you disable the INT_RTCC interrupts ? |
Yes, if I disabled the RTCC interrupt, the part of the code works all right.
Obviously, I can't read the encoder value, but the part that contains the i2c read and pwm write, works fine. |
|
|
|
|
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
|