OK, bear with me for my misconceptions here, but I've started playing with the simulator in MPLABIDE and I don't understand a few things. I'm planning on using a PIC16F871 and I've been going through a few web tutorials (for other PICs) and have the samples they offer working alright, but I can't find/figure out how you do conditional flow in the code. For instance, I stick a value in a register, I have the code increment that value when I want it to. But when it reaches the value I want how do I make it do the next thing I want? Like if I want it to increment a different register and clear the first one. I know how to actually do those two requirements, but not how to test for the condition. The only method I see working from the commands I see available is to have another register doing a decrement of a reverse value and do things when it reaches zero, but that doesn't seem very elegant, so I think I'm missing something here. Also, I'm missing something in how you work with the OSC. Well perhaps it would be more accurate to say I don't understand at all how it interfaces with the code you write. Does it perhaps effect the speed each cycle happens, meaning step by step through the code?
The PIC uses a fiarly typical mannor for doing conditional code execution or branching. This is, you check one single bit each with each conditional structure. This is normally a STATUS register BIT, but with the loverly BTFSS and BTFSC commands this could be any bit, lets look at an example, that will call a subrutine if the value in PORTB is 60d or over (3C in hex). Code: MOVF PORTB, W ADDLW 0xC4 ; -60d BTFSC STATUS, C CALL SUB1 ...rest of code ... SUB1: ;not too far away, segmented data memory model! (data address is wider than the parmiter lengh in CALL, thou this is not normally a problem, its a good idea to watch out for it) BSF PORTA,3 ;set some led on porta on or somthing RETURN ; the stack is hardware, and only 8 deep, and you might need 1 for an int, so BE CAREFUL, stack overflow = tits up. BTFSS and BTFSC as the datasheet will tell you are Bit Test on File [register] Skip if Set . and Skip if Clear respectivly. Skip if clear, was used above, so that if the carry flag of the status register is clear (0) then the CALL SUB1 line WILL NOT BE EXECUTED, instead a NOP will be. If you wanted it to call the sub, only if it was below 60, then BTFSS would of course do that. The carry flag is set after most arithmetic operations, (such as ADD literal with Working) if the result "over-flowed" the 8 bit data bus. when you add the 2's compliment of a number to the original, you get 0, with the carry flag set, if you wanted to execute the code ONLY when portb = 60, then you would change the line to: BTFSC STATUS, Z Z been the ZERO flag, this flag is set if the WHOLE of W is zero. The DECFSZ and INCFSZ functions work in the same manner, only that it decrementes (or increments) a file register, and skips the line below it, when the register = 0. so to make a loop that will be executed say 60 times Code: cblock 0x20 loopvar ; cblock is a nice way of defining file reg variables. endc MOVLW d'60' MOVWF loopvar loop: <SOMTHING> ; that will be executed 60 times DECFSZ loopvar GOTO loop <rest of code> Ok oscillators provide the clock pulse needed to the fetching and executing of commands, an oscillator has a resonant requency, and "oscillates" at exactly that frequency. Some PICs have internal Oscillators, these are high quailty resistor + capacitor oscillators, but for fine timing applications these are not upto it (thats y i sugested a RTC to track the time). If you put a 20mhz oscilator on a PIC16F871, then you will have an "instruction cycle" of 5mhz (20/4). That means most intrsutions will be done in the one instruction cycle, JUMPS, and conditionals take 2, always, if test is false, and it skips, a NOP is executed so you don't have problmes working out ur timing.
Is a PIC together with a crystal and capacitors accurate enough? I would calculate the percentage of accuracy, if only I knew how to do it. I suppose power (speed) isn't a problem (that for example not the whole code would be able to execute before 1 sec is passed), so that can be solved with NOPs. May I also say that this is a nice idea Gedron, and that I will also do something similar (if I may?) Great info Smilodon and Animus, once again
Its all about % error at the end of the day. If you have crystal that is 0.001% acurate at 32.768khz and one that is 0.0005% acurate at 20Mhz then i hope you can see the slower crystal is more acurate! But while a PIC will very happly run on a 32.768kh oscillator, your code will take longer to execute its a trade off! I like to use RTCs or Real Time Clocks, because they normally run of VERY slow and acurate oscillators (normally cost a bit more, but we are talking pence here so for us hobbiests, its not going to break the overdraft). But you could by all means use a PIC and a slow watch crsytal without any problems. I just find RTCs draw soo little current, even PICs in sleep tend to draw more! This means that you can just glue gun in a lithiuam cell onto your project and only have to replace it (un solder the wires, throw the blob away) every few years, not recomended for those who don't mind bodging on the little things.
I can indeed. The problem is availability. I do not live in a place where there is an electronics shop anywhere within 20 km. Also, living in a small country like Belgium limits the possibilities of internet-shops who can ship cheaply to here vastly. If you know of any online electronics shop that ships internationally for cheap, please tell me .
make friends with lecturers at the nearest higher education place that teaches electronics. I know what u mean, when i am at my rents (finaly escaped to uni ) i am stuck in cornwall, aka, no where, the nearest electronics shop is in plymouth, another county away, some 30miles away from me. www.rswww.com are very international, from ausland to frogland. They might have one somewhere that will delivery cheaply too u. (but you still pay $10 for shipping of $3's worth of stuff)
Go for it Relix And I want to add my thanks to you guys also. With your help I have the basics worked out now in tracking the time as I want to. I'm not gonna post the code here, but here is a link to it if anyone wants to look it over. Feel free to offer improvements, I know there have to be better methods out there. Sorry about the formatting (I just changed the .asm to .txt), but its fully commented to show what I was thinking and how I did it (might make a decent learning tool for someone perhaps). Now I just need to work out: sync'ing it with real time figuring out how I'm gonna add the SET features Set Mode Button (clears seconds and 10's of seconds) Set Hours Button (works with ^button) Set Min Button (same) Look into the battery to keep it running when system is off solution
not bad, you look to have almost all the proc's u will need, one little thing thou, try using the include files! ;*****Set up the Constants**** STATUS equ 03h ;Address of the STATUS register TRISA equ 85h ;Address of the tristate register for port A TRISB equ 86h ;Address of the tristate register for port B TRISC equ 87h ;Address of the tristate register for port C PORTA equ 05h ;Address of Port A PORTB equ 06h ;Address of Port B PORTC equ 07h ;Address of Port C is realy just asking for errors when INCLUDE "p16f871.inc" has them all also has stuff like C, on the status register, so its well worth using. As for the time, if you look into a RTC (Real Time Clock) i think i mentioned one on page 1, these are neat little devices, that you set the time on, and retrive the time from, in yyyy:dd hh:mm:ss style, well not like that for is used for formatting strings but that info anyway! And most have built int circuitry to switch to a cell when the power goes down, without losing a tick!
Problem is, you need to be from a company to order on that site (well, the Belgian version of it anyway), and you need to supply a VAT-number (I don't know what it's called in english). As only real companies have such a number, I cannot fake one. Thus I can't order from them. Same goes for Farnell.com, which also has a site in every country. I really don't know why they do it like that, I think they'd get many more things sold when they let us hobbiest also purchase.
Wait a minute... please tell me I am mis-interpreting something here. If I understand interfacing with the OSC propperly I can set a prescaler to whatever I want, but I'm going to have to deal with using some sort of delay loop to change adjust the speed that the instructions happen. I need to count how many cycles are going to occur and adjust the delay accordingly to make it TICK when I want to. Isn't there a way to trigger off something that is saying that the time I want has passed? say once every second?
Timer registors These are specail file registers, you can set them to be automatically incremented, the pre-scaler effects that incrementation. (is that a word?) When the timer over-flows (goes from 255 to 0 for an 8bit one like TMR0) then the CPU does an interupt, with the TxIF flag set. To work out the frequncy at which you ISR will be called, simply devide the instruction cycle by 256, with no prescaler. All in the data sheet, except maby the whole interupt idea, see mid-range manual ORG 0x00 CLRF INCTON GOTO initcode ORG 0x04 ; ISR ..... initcode: all my code tends to start with that! Code enters at 0, interupts at 04
wow, maybe I need more coffee this morning, but I don't think I follow you. Is this how that works: (I'm gonna user pseudo code) -Turn on interupt capability -Do the code I want when the interupt happens -Reset the interupt flag -Do the normal code till the interupt happens again
sorry i was typing it in a bit of a hurry as i had to meat someone, basically when the micro starts up, you should assume no value to be zero, INTCON is the interupt control register, by clearing this, we zero, and disable all interupts, its just good practice, helps reduce that 1 in a 100 chance of a bug. initcode label is just some place where your code can start, that is to say, will be called before any interupts are re-enabled, so you can set up all the registers, and stuff there. the ORG 0x04, will place any code below that at memory location 4, this is the ISR or interupt service routine, all interupts call this vector, you use conditional testing to determine which one was called. ie. BTFSC INTCON, T0IF GOTO TIMER0ISR Hope thats everything about interupts and good PIC'ing practice
Thanks for your help in this TheAnimus, I'm going to now try you patience further I've played with this a bit, however I still feel I'm going the wrong direction. Perhaps this will shed some light on my thoughts. Let me give a scenario: Lets say I want to do something with a PIC once every second. The something I want to do takes say 17 instruction cycles to complete and the PIC does 1 instruction cycle per uS. I can make a delay to eat up the rest of the time remaining in the second then loop back to the beginning and it will work just fine. But lets say I want to add another something to be done. This something is a "conditional" something where it will only occur once every so often in the program (say every 10 of the previous loops). When this instruction happens the code goes through 25 cycles. I could have a different loop to run when this happens to eat of the slightly different number of cycles remaining, and perhaps this is the answer, but it’s unwieldy to say the least. Especially if there are a lot more conditional things being done. Maybe I'm dreaming and a PIC can't in and of itself do this, but it seams that if there were a method of having the code run through every X period of time (so long as the total time for the longest amount of instruction cycles possible to run is shorter than the frequency of the "trigger" pulse) it would suit my needs better. Or maybe (and I'm hoping) I'm thinking about this the wrong way, and there is a better or available method built in. The RTC you mentioned is intriguing, and I think I see how it would be implemented in general terms I.E. The PIC would handle the lighting of the LEDs in the manner I prefer after gathering the information from the RTC. Perhaps this is a more elegant/effective method I should dig into. I looked at the data sheets for a few of the RTCs but I don't understand how the PIC interfaces with it. I'm assuming I set one of the ports as an input and connect the output of the RTC there... but then how does the PIC interpret the information sent etc.
yeh getting a 1 second gap thing isn't a problem. but if your running the micro of a high-ish speed oscillator i would recomend using a RTC for the second counting, or else you will get accuracy issues after a week or so, you can of course calculate the limits of these, given the % acuracy of the crystal. Any way, 1 second gap. There are 2 main ways of doing it, The first is like you described, use a "delay loop" These can be fasioned fairly simply, if you have a 1u second cycle, and you want to have a 1second delay cycle you need to waste 1,000,000 instruction cycles. as such, lets say you have 2 files registers you've named delaycount1 and delaycount2 Code: CLRF delaycount1 CLRF delaycount2 delayloop1: DECFSZ delaycount1, F GOTO delayloop1 DECFSZ delaycount2, F GOTO delayloop1 that code will loop 255*255 times. To work out the cycles, look at the first loop (3 instructions, every time it loops, 2 instructions, when it passes) so the first loop delays, (255*3)+2 times. So thats 767 done, this is then repeated 255 times, with a 255*3+2 on the end again. giving a total of 196,352 add two for the delaycount clearing, thats 196,354 as you can see this gets very messy and nasty, its good for VERY small gaps, but not much else TMR0 overflow, is probably more suited. But again, on a 4mhz clock, that would give the 1mhz instruction cycle rate. Its hard. lets start off by working out our time peroid in instruction cycles, 1 second, with a 4mhz oscillator, thats 1mhz cycle (/4 rule again) so thats 1,000,000 TMR0 is an 8bit timer, on overflow to 0, it triggers an interupt, so thats 255 steps, lets devide that by 255 then! 3921.568627450980392156862745098 nice! Lets work with the 3921, thats how many times a second the interupt would be called if the prescaller was 1:1, we want this to be one, so we devide the 3921 by the maximum pre-scaler value, 256. this gives us 15.somthing That of course is less than a second. So getting a proper second is hard, you can cheat around this, by adding a value to TMR0 register, but i can't remeber the exact behavoiur of the TMR0 register when you add to it. I'll have to read up a little.
How about the other timers built into the PIC? is there a way to use one of them to work as the trigger?
how about this... I haven't counted it, but I'm certain I can rewrite the code so it is less that 256 cycles. maybe doing a set loops which count the overflows of 1 of the timers, when the overflows reach a total value of the 1,000,000 we need (will need multiple registers to hold the overflows... but there are pleanty free) it kicks off the code for what I want. does that make sense?
yeh thats very possible! Yup there are other times you can use, some have higher resolution, but counting them when you have just 8 bit to work with is hard! In the datasheet each timer is explained, some "belong" to other bits of hardware like CCP module etc. You could probably make your life easyer by chosing a more suiteable oscilator speed like 32.768khz. That will also have less of an error value over time. My self however, i would just constantly talk to the RTC updating the LEDs constantly (except in time set mode etc) or use the RTC to call the PIC making that invoke my code every second.
Guess what I found... a RTC with integrated crystal AND lithium cell, for data retention of up to 10 years without ever needing an external powersource! http://www.maxim-ic.com/quick_view2.cfm?qv_pk=2757 I need to figure out a bit still how it talks to a microprocessor. The thing I do know is that it uses 8 pins to address and to read/write data. On that site are a lot more of those kind of modules, with integrated battery and crystal. When the power goes off, it automatically switches to the integrated battery. You can even attach another battery for even more backup. The accuracy isn't that much though. I read in the datasheet that it's about a minute a month. What do you think?
Yup RTC's make it nice n easy. "The DS1685 is a clock/calendar chip with the features described above. An external crystal and battery are the only components required to maintain time-of-day and memory status in the absence of power" I would choose an RTC that had an I2C interface myself, and use the PICs SPI in master mode to talk to it, KISS at play. (keap it simple... Stupid!)