I am working with a PIC 18F microcontroller from Microchip to continuously generate a rectangular signal. The code for the signal itself is at label5.
I need to generate 255*20 pulses of this signal. So basically, I need to repeat the instructions from the first 4 lines at label 5 for 255*20 times. Because I cannot have numbers higher than 2^8, I needed to write the number this way.
label5 BSF portd,5 call timer1 BCF portd,5 call timer2 In the code below I tried to achieve this behavior. I gave variable1 the value of 255 and I decremented from this value until variable1 was zero, in which case I returned at label2 and restarted the program. Everytime I decremented the variable1 I called label4. A similar things happens at label4. Here I have another variable, variable2, that is also decremented until it hits zero (and here comes the main signal generation program, repeated with each decrement operation), in which case, the program returns.
Can someone please tell me if I am on the right track ?
label2 movlw .255 movwf variable1 label3 call label4 decfsz variable1,1 goto label3 goto label2 ; """""""""""""" label4 movlw .20 movwf variable2 label5 BSF portd,5 call timer1 BCF portd,5 call timer2 decfsz variable2,1 goto label5 return end 42 Answers
The general recommendation is to use timers to burn time, some would argue interrupts to have a possibility of putting the chip in a lower powered mode. But with processors like the PIC18 where you can count instructions and very accurately from that determine execution time to use simple loops to burn time.
Two ways to make a loop take longer and I am very rusty on my PIC coding so consider this psuedo-code:
variable2 = 0 label: decfsz variable2,1 goto label That essentially is 256 loops yes? and you can count instructions including the extra clock or whatever for the time that it is zero...
variable2 = 0 label: nop nop decfsz variable2,1 goto label Adding nops can burn more time (yes I may still not understand if it is time you are burning or simply want more loops).
Or if you want to make it more loops and you only have 8 bits to count with then nest the loops
variable1 = 20 variable2 = 0 outer: inner: ; other stuff goes here? decfsz variable2,1 goto inner decfsz variable1,1 goto outer the inner loop will count 256 times, the outer loop will count 20 so you get 20*256 total loops
I have used this type of approach to make very accurate signals that couldn't be made by using a timer with this processor a much more efficient instruction set and faster processor would need to be used to have done the same thing with a timer if even possible. But you would instead buy a product that has a timer peripheral that does what you are trying to do or a portion of it, for example infrared remote you can get some ST products that take two timer outputs and have the and gate in the chip, so you can have a hardware generated carrier signal and a hardware generated gate, but generate the duration of the gate via software. with the pic I just had some small loops to do the same thing and it was all timed by counting instructions.
I would not use this approach on a cortex-m, maybe an msp430, maybe an avr, but not something pipelined and not something that was purchased IP from someone else (arm doesn't make chips, st and nxp and others make chips and simply purchase IP from arm as well as most of the rest of the chip is not arm IP and each vendor can tweak the ip when the get it so the same core (cortex-m0+ rev x.y for example) in different chips does not necessarily behave the same).
Another way would be to use a 16-bit loop counter that has a value of 255*20.
Something like this:
; ; ; TIMER1_CODE code timer1: return ; ; ; TIMER2_CODE code timer2: return ; ; main application ; MAIN_CODE code main: bcf TRISD,5 ; make RD5 an output ProcessLoop: movlw D'255' ; Compute loop count movwf PRODL movlw D'20' mulwf PRODL ; PRODH:PRODL = 255*20 = 5100 OutBitLoop: movlw 0xFF ; Decrement loop count addwf PRODL,F addwfc PRODH,F bnc Stop ; Stop when done enough loops bsf LATD,5 ; Set output bit high call timer1 BCF LATD,5 ; Set output bit low call timer2 bra OutBitLoop bra ProcessLoop Stop: bra Stop end Note that the code you posted uses the PORTD register to set or clear an output bit with an opcode that does a Read-Modify-Write. This is a bad choice.
For the PIC18F always use the output latch register (LATD) when changing the state of output bits.