Oh, and I wouldn’t waste time studying that code that you posted. It’s doing some more-advanced things that you shouldn’t be worrying about yet, such as “in-line assembly”, and modifying interrupt vectors, and using the PWM module and such.
Pete
Oh, and I wouldn’t waste time studying that code that you posted. It’s doing some more-advanced things that you shouldn’t be worrying about yet, such as “in-line assembly”, and modifying interrupt vectors, and using the PWM module and such.
Pete
Doh!
I gotcha, now.
TMR0L = 0x64;
It’ll start counting at 100 and stop counting at 255.
That means there’s 156 registers to fill.
So…
2,000,000 / (156 * 256) = 50.080Hz, which should be accurate enough for most tasks.
I don’t actually need to drive servos.
I’ll be using the 20mS timer as a way to keep track of the SSC-32’s 20mS updates.
I fixed the code to reflect the new changes, as usual.
By the way, do you agree that the
PIR1 = 0;
was unecessary?
The PIR1 register will default to all 0’s I believe. To verify, check the “Reset” chapter in the datasheet - it gives the initial state of all registers.
Regarding your latest code-post :
You should add a line in main() to set an initial value for OSCCON. Otherwise you may come up at a speed other than 8 Mhz.
In your interrupt routine, in one spot you have “second_counter”, when it should be “tick_counter”.
In your interrupt routine, you have TMR0L=0x00, but it needs to be TMR0L=0x64. You have to re-set TMR0L to the desired value on each interrupt, if you want the period to stay at 20 mS.
Just a terminology note here. Your first sentence is mostly correct - but it doesn’t stop counting at 255, rather it overflows to 0 and keeps going. The wrap-around (overflow) is what triggers an interrupt (if the TMR0 interrupt is enabled).
The 2nd sentence doesn’t make sense. You’re not working with 156 registers. Rather, a single 8-bit register (TMR0L) is counting upward, beginning with 100, then 101, then 102, etc. What you mean to say is that there will be “156 counts until the TMR0L register overflows to 0”. The datasheets use the word “overflow” instead of “wrap around”.
If you want to understand how (generally) the TMR0 counter works, try Googling for keywords like “binary counter”, “ripple counter”, “flip-flop counter”, etc.
Pete
Nick, I saw your post in the Microchip forum (2-timer! ).
So, does C18 require you to set up the interrupt vectors yourself? In PICC, it’s optional.
As someone said in the other forum, you should try compiling your code, to see if the compiler points out any problems.
Pete
Yep, PIR1 defaults to 0, so we don’t need that.
Yuck… those are some dumb mistakes.
They’re all fixed, now.
I individually set the three OSCCON bits that control the frequency, since I didn’t want to mess with the other buggers.
Aghhh!
You cought me.
My doctor always tells me to get a second opinion, hehe.
I posted the latest code in the microchip forums, just to be sure that I had the interupt syntax right.
The answer to my post was pretty much: “No, it’s not correct. Read the manual.”
That’s about as helpfull as the manual itself…
And, as it turns out that the interrupt syntax is waaaaaay different in C18.
All those priority, in-line assembler, and interupt vector pieces in that example program are actually required.
Oh, and the RA0 thingy is supposed to be PORTAbits.RA0…
Don’t ask me why they needed to use them as subcategories, since all of the pins have different names.
The assembler was easy enough to understand.
All it does is call the timer_interupt function.
The priority is pretty easy to understand, too.
I can have as many nested low-priority interupts as I want, but only one high-priority can occur at a time.
I believe this is because low-priority is actually put on the memory stack, wheras high-priority allocates “shadow” (sneaky) memory.
The hardest part to wrap my brain around was the interupt vectors, but they make perfect sense when you organize them like so:
//***********************************************************************//
// This program blinks an LED hooked up to RA0 every 20ms. //
// It also blinks an LED hooked up to RA1 every second. //
// The Timer0's 20ms intervals was calculated in the following way: //
// Timer0 clock = 8,000,000Hz(Oscillator Frequency) / 4 = 2,000,000Hz //
// 2,000,000Hz / 256 (Prescalar) = 7812.5Hz //
// 7812.5Hz / 156 (amount of counts when "TMR0L = 0x64") = 50.080Hz //
// 1 second / 50.080Hz = 19.968 millisecond interval //
//***********************************************************************//
//**************************** Inclusions. ******************************//
#include <PIC18F4620.h> // Specify the micro's library. //
#include <timers.h> // Timer library (OpenTimer function)//
//***********************************************************************//
//**************************** Configurations. **************************//
#pragma config WDT = OFF // Turn off Watch Dog Timer //
// otherwise, it resets the micro. //
#pragma config OSC = INTIO2 // Use the 8 MHz internal oscillator //
// without externals. //
#pragma config LVP = OFF // Turn off Low Voltage Programming. //
//***********************************************************************//
//**************************** Global variables. ************************//
#define TICKS_PER_SECOND; 50 // Number of interrupts in 1 second. //
int tick_counter = 0; // Create and zero a global counter. //
//***********************************************************************//
//********************** Low-priority interupt setup. *******************//
void timer0_interupt (void); // Declare an empty function. //
#pragma code timer0_vector = 0x18 // Go to low_vector's memory section.//
void timer0_vector (void) // Declare the setup function. //
{ //
_asm GOTO timer0_interupt _endasm //
// Execute timer0_interupt function. //
} //
#pragma code // Return to original memory section.//
#pragma interruptlow timer0_interupt// Redeclare the timer function as a //
// low priority interupt. //
//***********************************************************************//
//********************** Main code. *************************************//
void main (void) //
{ //
OSCCONbits.IRCF2 = 1; // Set 8MHz internal clock. //
OSCCONbits.IRCF1 = 1; // Set 8MHz internal clock. //
OSCCONbits.IRCF0 = 1; // Set 8MHz internal clock. //
TRISA = 0; // Sets bank A for output. //
OpenTimer0 (TIMER_INT_ON & TO_SOURCE_INT & TO_8BIT & TO_PS_1_256); //
// Instantiate the clock with timer //
// interupts enabled, internal clock,//
// 8-bit mode, and prescalar 1:256. //
INTCONbits.GIE = 1; // Global interupts enabled. //
RCONbits.IPEN = 1; // Enable priority levels. //
while(1) // Infinite loop keeps micro running.//
{ //
// Interuptable processes goes here. //
} //
} //
//***********************************************************************//
//********************** Low-priority interupt. *************************//
void timer0_interupt (void) //
{ //
INTCONbits.TMROIF = 0; // Reset timer0 interupt flag. //
TMR0L = 0x64; // Reset the timer period. //
tick_counter++; // Count how many interupts occured. //
//
//
//
//****************** Blink an LED really fast. *****************// //
if (PORTAbits.RA0 == 0) // If the LED is off... // //
{PORTAbits.RA0 = 1;) // ...turn the LED on. // //
else // If the LED is on... // //
{PORTAbits.RA0 = 0;} // ...turn the LED off. // //
//**************************************************************// //
//
//
//
//****************** Blink an LED more slowly. *****************// //
if (tick_counter > TICKS_PER_SECOND) // //
// This is true every second. // //
{ // //
tick_counter = 0; // Reset the counter. // //
if (PORTAbits.RA1 == 0} // If the LED is off... // //
{PORTAbits.RA1 = 1;} // ...turn the LED on. // //
else // If the LED is on... // //
{PORTAbits.RA1 = 0;} // ...turn the LED off. // //
} // //
//**************************************************************// //
//
//
//
} //
//***********************************************************************//
First, an empty function is created as a shell for the interupt function.
Then those interupt vectors nest the interupt code within themselves and, for that nested period, shift the memory allocation to a “safe” place.
That way, the code that gets interupted won’t have it’s memory stack corrupted/overwritten/etc.
Did I get that explanation right?
Go ahead… tell me that my code looks pretty!
Really, I don’t mind.
Hey, guys.
Time for an update.
I finally discovered PCBExpress’s wonderful schematic-drawing program over last weekend.
So, I set to writing up a real schematic for the board.
Here’s what the board will look like after the initial assembly:
f5.putfile.com/6/17916470894-thumb.jpg
I got the Jameco stuff on Monday, so I was all set to start in on making the board.
I ran into a few troubles with my regulator.
As it turns out, I had the 10uF cap and the .1uF caps on the wrong side.
So, a couple days later, here I am.
I scrapped the original board and started making a new one – I did mention that I bought an arsenal of electronic parts for just this reason, right?
Now I’ve got the regulator working properly (although I’m not using a .1uF cap, because I don’t have any more) and am starting in on the fun stuff.
I won’t actually be able to program this bugger, though, since Dan’s got my USB->DB9 cable >.<".
I probably won’t finish it that soon, anyhow.
This weekend, I should be going down to Dan’s to pick the bot up.
After that, I’ll be ripping him appart and improving him.
If I sound a bit random-headed in this post, I appologise.
Robotics tends to bring out my inner ADHD child.
EDIT
If I’ve gotten the LEDs in the wrong direction, don’t bite me, please.
For some reason, one of my books always draws the arrow pointing against the current flow, and the other shows it pointing in the more logical direction.
Since electronics has repeatedly mystified me with its intrinsic backwardsness (yep, that’s a word ), I thought that going with the illogical choice was best.
Did I guess right?
The LEDs are backwards. The cathode (the end with the line) goes toward the ‘more negative’ stuff.
Note that the PIC can drive the LEDs in either direction. So another way to fix your schematic is to leave them oriented as you have them, but connect the LED anodes to +5, instead of to ground.
Pete
Damn…
I hate when things get all logical and sneak up on me.
I had forgotten about it being able to drive the LEDs both ways…
(Brace yourself, and don’t laugh too hard; this is where I attempt to whack what I’ve read into what I’m playing with.)
So… the output pin is able to both source and sink because it’s setup in a totem-pole fashion?
Well, whatever the case, I think that it’s better to just fix the LEDs, as connecting them to ground seems to be the more accepted norm.
Thanks!
Yes. And it’s a totem-pole output that is designed to source and sink significant current.
Many logic devices (like nearly all TTL devices) have totem-pole outputs, but often the output current rating is quite low in the ‘source’ direction.
BTW, on your schematic: I think you know that the resonator is not needed if you use the internal oscillator.
I would recommend using the INTOSC to get started, because it’s one less variable to worry about (if something doesn’t work).
Pete
What?!?!
I was right?!?!
Coooooooool.
I definitely agree.
I’m leaving the resonator off of the board until I’ve got my first couple of simple programs under my belt.
I put it on there because Dan has given me an example code of a highly stable bit-banging protocol that needs an accurate clock (sorry, guys, he told me not to share it ).
One of my next projects will be trying to understand it.
I chose to go with a resonator mainly because he has one to give me, but also because I’ve read that they don’t require the tuning that’s usually necessary with an oscillator.
They also have the necessary caps onboard, so they’re about as plug-n’-play as it gets.
Project update:
Except for the resonator, everything on that schematic is now on my board.
I ended up putting the two LEDs on pins RA2 and RA3, on the other side of the micro.
That’s because they’re set in a nice right-angle casing which put their positive leads on the left.
Since I wanted to keep with the convention of having the micro be the source, I had to put them on the right side of the micro instead.
I’m troubleshooting a bit of a problem, now.
Everything was fine until I soldered the SMiRF on.
When I connected it to test it, everything worked fine (both my board’s power LED came on and the SMiRF’s status LED started blinking), but my 9V quickly got hot.
I’m going to go check for shorts, and then I’ll try using my 9V supply, instead of a battery.
I doubt that something’s shorted, because there shouldn’t be enough current going to the LEDs to light them up if that were the case.
At least… that’s what “current takes the path of least resistance” seems to tell me.
Plus, I’ve been very careful and have scraped between the pads with a knife.
This seems to clean the area between free of debris quite well.
I’m willing to bet, though that there’s just too much load for my battery to handle.
I don’t believe that the regulator got warm, but I’m going to go check that.
If so, then it might be the regulator and not the battery.
Whether a resonator is accurate enough is debatable. The main feature of a resonator is “cheap and simple”.
Here are the main oscillator options, and their pros/cons:
PIC’s internal oscillator. Simplest and cheapest (no components). Accuracy and precision are not very good.
External R-C oscillator. Still cheap. Not very stable unless you do an exotic design. A good way to go if you want to be able to fine-tune it via a small variable cap. But it will still tend to be temperature-sensitive.
External resonator. Fairly cheap (maybe $1). More accurate (around ±0.5%) and precise than the above options, but not nearly as good as the following choices.
External crystal. Still pretty cheap (less than $1) if you use a common frequency. Often requires 1 or 2 small caps in addition to the crystal itself. Very accurate and precise. Probably 100 times more accurate than a resonator.
External oscillator module. They are usually rectangular metal cans that plug into a 14-pin DIP socket (but usually have just 4 pins on the corners). Internally they have a crystal oscillator circuit, and logic-level output circuit, and probably temperature compensation and such. This is the most accurate and stable option, other than an exotic discrete-crystal circuit. May cost $4-5. May use a fair amount of power. The best thing about these is that they output a logic-level square wave, so you can use its output to drive other circuitry at the same time.
Pete
That was quick…
I found the problem.
Apparently, the excess flux that inevitably congeals between the pads of whatever I use it on is slightly conductive.
I found a row of adjacent pads that I must have forgotten to scrape.
After doing so, I turned it back on and wallaaa!
The battery stayed ice cold for more than 15 minutes, and the regulator was luke-warm.
Next, I’m going to throw a switch onboard, so I don’t have to keep plugging and unplugging the damn battery.
After that, I’ll go cut out a heatsink and the board should be as done as I can now make it.
By the way, I’ve got some 1/16" mild steel sheet metal.
Will that transfer heat well enough to act as a decent heatsink, or should I go with aluminum?
I’m pretty sure that alluminum is good at dissipating heat, but I also believe that it doesn’t absorb it well, which is the heatsink’s purpose.
dont forget the thermal grease 8)
Aluminum is much better than steel for heatsinking.
However, if you’re not too close to the edge of overheating, then the steel will probably be good enough.
The purpose of a heat sink is not really to “absorb” heat, but rather to “conduct” it away from the component, and then allow the heat to be conducted to the surrounding air, which then convects the heat away.
Pete
Aluminum is a great heat sink material because of the speed at which it can conduct/disipate heat. Aluminum heats & cools much faster than steel. In the automotive world, steel is often used as a heat sheild. Like Pete said, steel should work fine for mild heat.
Ahhh…
Goodie.
Then aluminum it is.
Too bad that I can’t use the biped’s brackets as a heatsink, since the regulator’s tab is also the GND.
I’m not actually putting a heatsink on this one, but I will on the final board.
I’m redoing the board (much later on) for a few reasons:
I didn’t leave enough room for a power switch.
I didn’t leave enough room for a heatsink.
The board probably won’t fit well on the biped in one piece.
I want to go SMT, next time.
When I do remake the board, I’ll be chopping the board into a bunch of pieces and connecting them with ribbon wire.
Where they eventually go will depend upon the final outcome of my biped’s setup, but if I do SMT, I should have a low enough profile to stick them in the gap between my servos and my 15 degree slanted ASB’s (they’ll give it a more gorrilla look) on the biped’s back.
This’ll make them hard to access for debugging, but, by then, I’ll have the board up and running “perfectly”, anyhow.
I’ll drill some holes, then, in the biped’s back so the LEDs can shine out, and to give me access to connectors and jumpers.
In school, I managed to get into three electronics classes: an introductory course, Digital Electronics, and Microcontrollers.
I got into Micro without the prerequisites by going to the department chair and showing him my biped.
He actually thinks that I know diddly squat about electronics.
Who knows… by the time spring rolls around, I might actually know diddly squat.
Nick, did you have the board fabed? or is it perf board? If you had the board fabed, what fab house did you use?
Oh, no.
It’s perfboard.
I’ll be going the perfboard route until I actually get everything working, which will be a LONG time, yet.
Once it’s all good, I’ll probably be using ExpressPCB as my fabhouse.
A lot of people (including you, right?) have used it before, so help isn’t far away…
Plus, $50 for three prototypes isn’t bad.
PROJECT UPDATE:
I went down to Dan’s house, yesterday, and we fleshed out the LED blinking program that I’d made.
He showed me the little quirks of MPLAB and C18 and where that list of PIC18 configuration settings was.
After a bit of code-fixing (I kept using “O” instead of “0”) the program worked!
We kind of guessed on the whole timing thing, and the LEDs seem to be blinking faster than we guessed, but I’m going go fix that, now.
I’ll repost the code once I’ve fixed it.
I think I’ve got the code right, now.
The only problem is, I can’t test it.
I don’t have MPLAB talking to my Tiny-ICD2.
I’ve tried reinstalling the drivers and I have that port’s settings and the MPLAB’s portsettings all correct.
I’m guessing that the Tiny-ICD2 just wasn’t made to function with a USB->DB9 cable.
I’ll dowload MPLAB and C18 on my old desktop and see if it’ll work with its normal serial cable.
zZzZzZ
56k downloads are poop.