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

pic16f767 timing

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







pic16f767 timing
PostPosted: Fri Jun 09, 2006 6:23 pm     Reply with quote

ok. so lets start with some basic details here:

im programming a pic 16f767 with mplab (with CCS of course). its set to the 8mhz internal osc, and is running off of an ICD2 so its getting about 5 volts. hooked up to PORTA i have 8 leds, so i can send a byte to the port and read it off easily.

i am trying to create a device similar to ones created by other people that can display an image in a bicycle wheel, using POV, in a similar way to those novelty clocks you can get. (ladyada made one called "Spoke POV" and a character named 'Ian' made a similar one of the same name. google "ian pov", its the first result. sorry, i cant post links)

i plan to have a string of 32 leds on shift registers (like ian did), and flash 256 raster lines per revolution to create an image (like ian did).
an external interrupt (when the device passes under the 'fork' of the bike) will begin drawing the image regardless of current position, to keep it static within the wheel.

right now i am just trying to get the timing down, before i start trying to work with pictures or anything fancy like that. the basic algorithm i'm going with is as follows:

Code:

int_timer0 increments a counter

int_ext raises a flag

main loop
-if flag has been raised:
--multiply the counter by the length of one timer0 overflow
--divide this time by 256 (256 radial raster lines)
--reset counter, flag, and line counter

- display the (linecouter)th line
- increment line counter
- wait the length of one raster line


so basically it times a revolution and bases the timing of the next revolution on the previous one. now, the problem im having (as the title may suggest) is that the timing is terribly off. i had to calculate some constants, and i really hope im just screwy in my assumptions and that that is where the problem lies.

here is the code i have right now. it just outputs the line counter to PORTA for debugging purposes. as this code is written, the lines are displayed wayyy too fast (less than 10ms for all of them).

Code:
#include <16f767.h>
#use delay(clock=8000000)

void main(void);
void tmr0int(void);
void externalint(void);
void mainloop(void);

long x;          // timer counter
int1 restart;    // ext_int flag

void main(void){
   setup_oscillator (osc_8mhz);                 //set oscillator to 8mhz
   setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_256);  //set timer to internal osc, 256x prescaler
   enable_interrupts (global);                  //enable interrupts
   enable_interrupts (int_ext|int_timer0);      //enable timer0 and external interrupts
   EXT_INT_EDGE (h_to_l);                        //set external interrupt edge to high-to-low
   
   mainint();                          //main loop
}


#INT_TIMER0
void tmr0int(void){x++;  clear_interrupt(INT_timer0);}  // increment counter, clear interrupt

#INT_EXT
void externalint(void){restart = 0x01; clear_interrupt(INT_EXT);}  // raise flag, clear interrupt


void mainloop(){
   long UsPerRev;         // microseconds per revolution ('micro' to avoid floating point operations)
   long linenumber, msperline;   // line number, miliseconds per line
   
   enable_interrupts(global);              //i wasnt sure if you had to enable these for each function or not
   enable_interrupts(int_timer0|int_ext);

   do{
      if (restart == 0x01){         // if flag is raised
         restart = 0x00;         // clear flag
         UsPerRev = x * 32768;      // ok, this line is suspect. see below for detials
         x = 0;                          // clear timer counter immediately (timer is still ticking!)
         msPerLine = UsPerRev / 256000;  // calculate ms per line (256 lines, 1000us per ms)
         linenumber = 0;                 // resent line count
        }

      output_a(make8(linenumber, 0));      // output line counter so i can see whats going on inside
      linenumber++;            // increment line counter
      delay_ms(make8(msPerLine,0));      // wait
     }while(linenumber<255);
 }


ok. so i assume that one timer overflow takes 32768us. here is my logic:

-timer0 is incremented once each instruction cycle (datasheet)
-instruction cycle is fosc/4 = 2mHz = .5us
.5us * 256 (8bit timer) * 256 (prescaler) = 32768us

(in the help file it says you cant pass a variable bigger than 256 to the delay functions, which is why i converted it to ms. but the functions seem to take long variables without trouble. whats up with this?)

so, like i said, no matter how fast you trigger the external interrupt, the loop fires off in an impreceptably small amount of time. whats up with that?

thanks in advance for your help

- Tim
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Jun 09, 2006 8:03 pm     Reply with quote

Quote:
void mainloop()
{
long UsPerRev;
long linenumber, msperline;

enable_interrupts(global);

enable_interrupts(int_timer0|int_ext);

do{
if(restart == 0x01)
{
restart = 0x00;
UsPerRev = x * 32768;
x = 0;
msPerLine = UsPerRev / 256000;
linenumber = 0;
}

In CCS, a "long" is an unsigned 16-bit integer. In the code above,
you multiply x by 32768. If x is greater than 1, you'll get immediate
overflow of the 16-bit variable, UsPerRev.
In the line where you divide by 256000, you will always get 0 as the
result, because UsPerRev can be from 0 to 65535, and dividing any
of those values by 256000 will give 0.
If you want to use values larger than 65535, then I suggest that
you declare your variables as "int32". This gives unsigned 32-bit
variables.


Quote:
#INT_TIMER0
void tmr0int(void)
{
x++;
clear_interrupt(INT_timer0);
}


#INT_EXT
void externalint(void)
{
restart = 0x01;
clear_interrupt(INT_EXT);
}

The statements shown in bold above are not necessary.
The compiler inserts code to clear the interrupts before it leaves the isr.


Quote:

In the help file it says you cant pass a variable bigger than 256 to the
delay functions, which is why i converted it to ms. but the functions
seem to take long variables without trouble. whats up with this?)

They truncate the 16-bit argument and use only the lower 8 bits.
See the following links for functions that accept a 16-bit variable.

long_delay_us():
http://www.ccsinfo.com/forum/viewtopic.php?t=16656

long_delay_ms():
http://www.ccsinfo.com/forum/viewtopic.php?t=375
Guest








PostPosted: Fri Jun 09, 2006 8:48 pm     Reply with quote

haha. yeah. im used to longs being 32 bits. i never even thought about that. Rolling Eyes

ok well, thank you for the help fine sir. i shall see if i can get it to work now
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