| « The Matrix. | The Microcontroller » |
Now that we have most of the fundamentals down and you understand the basics behind microcontrollers, lets have a little fun.
Today's project is a 3 speed PWM(Pulse Width Modified) fan controller.
In this project the user selects the fan level (low, medium, and high) and the program adjusts the duty cycle (%on vs %off) of a 20KHZ signal accordingly. By adjusting the duty cycle we can control how fast the fan runs by limiting how long it is on vs how long it is off.
The code is fairly simple and very inefficient, but we will be working on it time to time to improve its efficiency and not waste clock cycles or memory.
The general flow of the program is like so:
1 - Set up environmental variables
2 - Set up ports
3 - Goto main loop
4 - Check for button press, increment/decrement COUNT variable depending on button press
5 - Check the count variable to see what "level" it is set at (High, Medium, Low)
6 - Adjust the duty cycle based on the level
7 - Return to main loop
8 - Call the table and output the level to 7 segment display
9 - Reset loop
Its fairly simple and works pretty well. However i think i should break down each part to help you better understand the garble of letters. The source is free to grab and modify at the end of the post.
Part 1:
We set up environmental variables by using the equ function, we set labels to places in the memory that are unoccupied. Thus, they will store a value like a variable and have convenient names. The three main variables are DELAY, COUNT and TEMP. DELAY is used for the delay loop, TEMP is used for temporary storage and COUNT is the variable we use to set the speed level.
Part 2:
We set up the ports by first switching to bank 1. After we do that we send values to the TRISA, TRISB, and TRISC registers which control ports a,b, and c. A 1 makes it an input and a 0 makes it an output. We send vales buy moving a literal value to multipurpose register w and then moving the contents of w to the appropriate register.
Part 3:
We use a simple goto statement to go to the main LOOP
Part 4:
We use the function BTFSS (Check if bit is SET) and BTFSC (Check if bit is CLEAR). We provide it a register location as well as a bit. btfsc PORTA,0 means check PORTA bit 0 if it is clear. If it is, jump over the next line. If not, continue as normal.
Increment routine:
If port a bit 0 is set, the program goes into the increment routine. This routine increments count by 1 and checks to make sure it didn't go past 2. It does this by doing an arithmetic operation with w, in this case, subtraction. If a zero is returned the Z flag of the status register is set. We can use this to advance further into our program. If it is not set (thus it is under 2) we return back to the main loop with count only incremented. If it returns a zero, we clear count, and then return back to the loop.
Decrement routine:
Same as the increment routine except we add zero and decrement count.
Part 5:
We call the check level routine. In this routine we do several arithmetic operations to count to see what value it has in it. Its value send it to the proper routine to adjust the duty cycle.
Part 6:
High: Set the fan constantly on, call no delay (100% duty cycle)
Medium: Make sure fan is off, call a delay, turn fan on, call another delay, turn it off. (50% duty cycle)
Low: turn off fan, call 3 delays, turn fan on, call one delay, turn fan off. (approx 25% duty cycle)
DELAY Routine:
The Delay routine decrements the variable DELAY1 by 1 until it reaches 0, once it does it resets DELAY1 to 100 and exits the loop, this eats up 100 program cycles or roughly 100(micro)s
Part 7:
RETURN brings us back from the subroutines back to the main loop
Part 8:
We move COUNT to w, call the TABLE sub routine and add W to the program counter, this makes the program counter advance over the other values not desired and return a value to w back to the main loop. We send this value to PORTC which our 7 segment display is located.
Part 9:
We use a goto function to begin again at the front of the loop
*QUICK NOTE*
GOTO VS CALL
Goto: Simply GOES TO the part of the code, does not return a value
Call: Goes to a section of code and will return to where it was called from once a value was returned with it.
http://mcuplace.com/mcu/media/blogs/blog/pwm2.asm (SOURCE)
http://mcuplace.com/mcu/media/blogs/blog/pwm2.HEX (HEX)