CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

problem with pic16f886 and timers

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
pirraca
Guest







problem with pic16f886 and timers
PostPosted: Tue Mar 24, 2009 7:20 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Mar 24, 2009 12:28 pm     Reply with quote

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







PostPosted: Tue Mar 24, 2009 4:36 pm     Reply with quote

I will try it, and I will comment the results!

Regards!
pirraca
Guest







PostPosted: Wed Mar 25, 2009 4:06 am     Reply with quote

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







PostPosted: Wed Mar 25, 2009 4:36 am     Reply with quote

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







PostPosted: Thu Mar 26, 2009 4:47 am     Reply with quote

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... Confused

Thank you for your help
pirraca
Guest







sorry, I put a wrong code
PostPosted: Thu Mar 26, 2009 6:02 am     Reply with quote

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







PostPosted: Thu Mar 26, 2009 7:29 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu Mar 26, 2009 4:25 pm     Reply with quote

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







PostPosted: Thu Mar 26, 2009 5:31 pm     Reply with quote

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 Sad
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Mar 27, 2009 11:27 am     Reply with quote

Does the modified code work if you disable the INT_RTCC interrupts ?
pirraca
Guest







PostPosted: Sat Mar 28, 2009 5:21 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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