This project contains ten labs that demonstrate the capabilities of the Curiosity High Pin Count (HPC) board and showcase the functionality of the PIC18F25K42 device. The idea is to create a state machine that allows navigation through each lab using the S1 button. Some labs need a potentiometer for analog input. The lab outputs are displayed using four LEDs provided by the Curiosity development board. This project is primarily created with the aim of helping beginners in basic programming of microcontrollers (MCUs).
This example also makes use of the latest MPLAB® Code Configurator (MCC) Melody. This is a user-friendly plug-in tool designed for the MPLAB X IDE, which aids in generating codes for a more optimized use of CPU and memory resources. All labs are composed in C language and are compatible with the latest version of the XC8 compiler.
- MPLAB X IDE v6.15 or newer
- MPLAB XC8 v2.45 or newer
- PIC18F-K_DFP Series Device Pack v1.13.292 or newer
- MPLAB Code Configurator v5.5.7 or newer
- MPLAB Code Configurator Melody core v2.6.2 or newer
MPLAB Code Configurator (MCC) is used to configure the system setup for the PIC18F25K42. The clock is set to 500 KHz. The Watchdog Timer (WDT) is set through SWDTEN with a period of approximately four seconds.
The labs in this Readme are presented in the same order as they appear on the MPLAB X Project and the programmed code into the device. The user can switch through each of the labs by simply pressing the S1 button on the board.
- Lab 1: Hello World (Turn on an LED)
- Lab 2: Blink
- Lab 3: Rotate (Moving the Light Across LEDs)
- Lab 4: Analog-to-Digital Converter (ADC)
- Lab 5: Variable Speed Rotate
- Lab 6: Pulse-Width Modulation (PWM)
- Lab 7: Timers
- Lab 8: Interrupts
- Lab 9: Wake-up from Sleep: Using WDT
- Lab 10: EEPROM
- Push Button Switch - Only one on-board push button switch (S1) is utilized. The S1 is connected to the PIC MCU's RB4 pin and is used to switch to the next lab
- Potentiometer - A 10 kΩ Potentiometer connected to the RA0 pin is used in labs requiring analog inputs
- LEDs - The Curiosity HPC Development board has four LEDs (D2 through D5) that are connected to I/O ports RA4 through RA7, respectively. These LEDs are used to display the output of the different labs.
This lab shows how to turn on an LED.
LED D2 lights up and stays lit.
The LEDs are connected to the input/output (I/O) pins. First, the I/O pin must be configured to be an output. In this case, when one of these pins is driven high (LED_D2 = 1), the LED will turn on. These two logic levels are derived from the power pins of the PIC MCU. Since the PIC's power pin (VDD) is connected to 5V or 3.3V and the source (VSS) to ground (0V), a logic level of '1
' is equivalent to 5V or 3.3V, and a logic level of '0
' is 0V.
This lab shows how to blink an LED.
LED D2 blinks at a rate of approximately 1.5 seconds.
One way to create a delay is to spend time decrementing a value. In assembly, the timing can be accurately programmed since the user will have direct control on how the code is executed. In C language programming, the compiler takes the C and compiles it into assembly before creating the file to program to the actual PIC MCU (HEX file). Because of this, it is hard to predict exactly how many instructions it takes for a line of C to execute. For a more accurate timing in C, this lab uses the MCU's Timer1 (TMR1) module to produce the desired delay. TMR1 is discussed in Lab 7: Timers.
This lab is built on Labs 1 and 2, which showed how to light up a LED and then make it blink using loops. This lab incorporates four on-board LEDs (D2, D3, D4 and D5) and the program will light up each LED in turn.
LEDs D2, D3, D4 and D5 light up in turn every 500 ms. Once D5 is lit, D2 lights up and the pattern repeats.
In C language, a Binary Left Shift (<<) and a Binary Right Shift Operators (>>) are used to move bits in the registers. The shift operations are 9-bit operations involving the 8-bit register being manipulated and the Carry bit in the STATUS register as the ninth bit. With the rotate instructions, the register contents are rotated through the Carry bit.
For example, for a certain register rotateReg, we want to push a '1
' into the Least Significant Bit (LSB) of the register and have the rest of the bits shift to the left, we can use the Binary Left Shift Operator (<<). We would first have to set up the Carry bit with the value that we want to push into the register before we execute the next instruction, as seen in the figure below.
Similarly, if we want to push a '1
' into the Most Significant Bit (MSB) of the register and have the rest of the bits shift to the right, we can use the Binary Right Shift Operator (>>). We would first have to set up the Carry bit with the value that we want to push into the register before we execute the next instruction, as seen in the figure below.
This lab shows how to configure the ADC, run a conversion, read the analog voltage controlled by the on-board Potentiometer, display the high order four bits on the four LEDs.
The four most significant bits of the ADC result are reflected onto each of the four LEDs respectively. Rotate the Potentiometer to change the LEDs.
The PIC18-K42 family of devices have an on-board Analog-to-Digital Converter with Computation (ADCC) with 12 bits of resolution. The converter can be referenced to the device's VDD or an external voltage reference. In this lab, it is referenced to VDD. The result from the ADC is represented by a ratio of the voltage to the reference.
This lab combines all of the previous ones to produce a variable speed rotating LED display that is proportional to the ADC value. The ADC value and LED rotate speed are inversely proportional to each other.
Rotate the on-board Potentiometer to change the speed of the LED shift.
A crucial step in this lab is to check if the ADC value is zero. If it does not perform the zero check, and the ADC result is zero, the LEDs will rotate at an incorrect speed. This is an effect of the delay value underflowing from 0 to 255.
In this lab, the PIC MCU generates a PWM signal that lights an LED with the Potentiometer, thereby controlling the brightness.
Rotating The Potentiometer will adjust the brightness of LED D5.
Pulse-Width Modulation (PWM) is a scheme that provides power to a load by switching quickly between fully ON and fully OFF states. The PWM signal resembles a square wave where the high portion of the signal is considered the ON state and the low portion of the signal is considered the OFF state. The high portion, also known as the pulse width, can vary in time and is defined in steps. A longer, high ON time will illuminate the LED brighter. The frequency or period of the PWM does not change. The PWM period is defined as the duration of one cycle or the total amount of ON and OFF time combined. Another important term to take note is the PWM duty cycle which is the ratio of the pulse width to the period and is often expressed by a percentage. A lower duty cycle corresponds to less power applied and a higher duty cycle corresponds to more power applied.
This lab will produce the same output as Lab 3: Rotate. The only difference is that this version uses Timer1 to provide the delay routine.
LEDs rotate from right to left, similar to Lab 3.
Timer1 is a counter module that uses two 8-bit paired registers (TMR1H:TMR1L) to implement a 16-bit timer/counter in the processor. It may be used to count instruction cycles or external events that occur at or below the instruction cycle rate.
This lab configures Timer1 to count instruction cycles and to set a flag when it rolls over. This frees up the processor to do meaningful work rather than wasting instruction cycles in a timing loop. Using a counter provides a convenient method of measuring time or delay loops as it allows the processor to work on other tasks rather than counting instruction cycles.
This lab discusses interrupts; the operation, capabilities and how to set them up. Most interrupts are sourced from MCU peripheral modules. Some I/O pins can also be configured to generate interrupts whenever a change in state is detected. Interrupts usually signal events that require servicing by the software's Interrupt Service Routine (ISR). Once an interrupt occurs, the program counter immediately jumps to the ISR and once the Interrupt Flag is cleared, resumes what it was doing before. It is a rather more efficient way of watching out for events than continuously polling a bit or register.
LEDs D5, D4, D3 and D2 rotate from left to right at a constant rate of 499.712 ms.
This lab demonstrates the advantage of using interrupts over polling. An interrupt is generated whenever the Timer0 (TMR0) register reaches 0xFF and goes back to reset value. This indicates that 500 ms has passed and it is time to rotate the light. This interrupt is serviced by the TMR0_ISR()
function.
*Note: This is the same for Lab 7: Timer1, but this time, the TMR1IF
flag is not continuously monitored.
This lab introduces the Sleep mode. SLEEP()
function is used to put the device into a low-power standby mode.
Once this lab is in RUNNING
state, the WDT will start counting. While in Sleep mode, LEDs D2/D4 and LEDs D3/D5 are turned ON and OFF, respectively. Pressing the switch will not move to the next lab since the PIC is in Sleep mode. After the WDT has reached its period, which is approximately four seconds for this lab, the PIC exits Sleep mode and the four LEDs, D2 through D5, are toggled.
The Power-Down mode is entered by executing the SLEEP instruction. Upon entering Sleep mode, there are different conditions that can exist, such as:
- WDT will be cleared but keeps running, if enabled for operation during Sleep
- PD bit of the STATUS register is cleared
- TO bit of the STATUS register is set
- CPU clock is disabled
Different PICs have different condition once they enter Sleep mode. Refer to the datasheet for more information.
The Watchdog Timer (WDT) is a system timer that generates a Reset if the firmware does not issue a Clear Watchdog Timer (CLRWDT
) instruction within the time-out period. WDT is typically used to recover the system from unexpected events. When the device enters Sleep, the WDT is cleared. If the WDT is enabled during Sleep, the WDT resumes counting. When the device exits Sleep, the WDT is cleared again. When a WDT time-out occurs while the device is in Sleep, no Reset is generated.
This lab provides code for writing and reading a single byte onto the on-board EEPROM. EEPROM is nonvolatile memory, meaning that it does not lose its value when power is shut off. This is unlike RAM, which will lose its value when no power is applied. The EEPROM is useful for storing variables that must still be present when there is no power. A good use case is to store calibration data for the user application and have it loaded on every boot-up. It is also convenient to use if the entire RAM space is used up. Writes and reads to the EEPROM are relatively quick, being much faster than program memory operations.
The top four MSBs of the ADC are written to EEPROM. These are read afterwards and displayed on the LEDs. Rotating the Potentiometer changes ADC value to be written to and read from EEPROM.
This lab has a similar appearance to Lab 4: ADC. Instead of moving the ADC result directly onto the LEDs, it performs a simple "write" and "read" on the EEPROM. As shown on figure below, the top four MSBs of the ADC result is first written to EEPROM, and retrieved later from the same address before moving onto the LEDs.
- Program Device using MPLABX project provided.
- To progress through each Lab, Press S1, and observe the results.
- Rotation of the Potentiometer takes place during the Analog-to-digital Converter (ADC), Variable Speed Rotate, Pulse width modulation (PWM), and EEPROM labs.
After programming the device and completing all the labs, The user has learned:
- Lab 1 - How to setup a IO pin to turn on an LED
- Lab 2 - How to setup and use the timer module using the polling method to blink an LED
- Lab 3 - Show how to rotate a register using the carry bit, to control the rotation of an led through an array of LEDs
- Lab 4 - How to setup and use the ADCC module to do an analog-to-digital conversion
- Lab 5 - How to Combine concepts in Labs 1 through 4 to vary the speed of the LED array rotation.
- Lab 6 - How to setup and use the PWM module to adjust the brightness of an LED
- Lab 7 - How to setup and use the timer to control the rotation of an led through an array of LEDs
- Lab 8 - How to setup and use interrupts for an efficient implementation of the MCU core
- Lab 9 - How to Wake from sleep using the WDT timer
- Lab 10 - How to use the NVM module routines to use on-board EEPROM for NVM storage
Note: For the complete step-by-step guide in making this example, click here and open the Read Me document inside the downloaded folder.