Many sensors have an analog output that must be digitized using an Analog to Digital converter (ADC) in order to use them in a microcontroller. The PIC’s ADC subsystem is the peripheral used to read analog values and convert it into a digital number for use in your program. It can be configured in a variety of ways. In this assignment, you will create an ADC subsystem and program your microcontroller to transmit the result of reading an analog voltage measured at an input pin, using the ADC subsystem in one of its simplest configurations.
Likewise, PWM signals are often used to control a variety of actuators (e.g., servo motors), and, because they provide a proportional time-based signal, can be used in certain circumstances, as an analog output from a microcontroller. In this assignment, you will also program your microcontroller to generate a PWM signal using the measured ADC value, and demonstrate modifying the output of the PWM signal in two key ways.
The goal of this assignment is to introduce you to the MPLAB® X IDE, and to verify that you can create a project, add peripherals (ADC, PWM, EUSART), and use them together. By the end of this assignment you should be able to demonstrate proficiency in:
Item | Quantity | Value(s) |
---|---|---|
PIC18F47Q10 Curiosity Nano | 1 | |
Breadboard | 1 | |
Resistors | 1 | TBD by student |
LED | 1 | Any color |
Jumper wires | Several |
You may use your Nano board or a breadboard with your microcontroller on it.
Critical Information and Concepts | Importance |
---|---|
a. The name of the virtual COM port that communicates over the Curiosity Nano’s USB to your computer. | Needed in order to connect PuTTY to the Curiosity Nano |
b. Which EUSART subsystem connects to it | Needed to determine which EUSART port to connect the PIC to in order to communicate with the debugger and computer |
c. Which specific pins are used for receive and transmit on the PIC | Needed to assign the correct pins to the EUSART component |
d. How much current can a digital I/O pin safely source or sink? (Hint: See the PIC18F47Q10 Datasheet) | Needed to match the current needs of external loads (e.g., LEDs) with the IC and determine whether you need interface circuitry (e.g., a transistor) |
e. Which pin of the Curiosity Nano board outputs the regulated power used by the “target” (the PIC18F47Q10) | Needed to know where you can access power and ground on the Curiosity Nano board |
f. Which pins of the Curiosity Nano connect to ground? | |
g. How many bits wide is the result of an ADC read? h. How many bits wide is the PWM timer register? |
Needed to read, interpret, and write data to and from the ADC and PWM peripherals. Can be found in the PIC18F47Q10 Datasheet |
i. How to shift bits of a number or variable (needed to manipulate data in an 8-bit variable) j. How to mask bits of a number or variable (needed to read or write specific bits in an 8-bit variable) k. How to cast a variable as a different data type (needed to convert variables from one data type to another) |
Needed to manipulate data in variables. Can be found in a C programming reference, such as the GNU C Reference Manual |
Open the Curiosity Nano box and the two antistatic bags inside. Solder the headers into the PCB so that the long side can be plugged into a breadboard and the short side goes through the PCB and can be soldered on the top.
Follow the instructions in the Quick Start section of the Hardware User Guide to download and install the MPLAB® X IDE (including IPE and 8 bit MCU support), XC8 compiler, and MPLAB® Code Configurator (MCC). Note: The free compiler license is sufficient for this course.
Open MPLAB® X IDE and plug the Curiosity Nano board into the USB port of your computer
In MPLAB X, create a new project for the PIC18F47Q10. Ensure the curiosity nano is connected over usb before starting project setup so you can select it as the programming “tool” during setup.
Open MCC, and select the default file location when prompted.
Please use MCC Classic. We can support it better, it has more advanced configuration options, but is also still relatively easy to use.
Open the project in MPLAB® X and MCC, then add and configure the following peripherals:
Pay attention to and follow all instructions provided by the MCC’s warnings and errors in the Notifications [MCC] window
Open up the pin manager grid
In the Pin settings(in the resources window), ensure that
Generate the MCC configuration
Open EUSARTX.h (where “X” is the correct EUSART peripheral) in the MCC-generated header files within the project explorer. Read through this document, Identify each function and determine what the purpose of each is. Then find the function that initializes this EUSART subsystem and note it.
Open up ADCX.h
Find the function that permits you read a single ADC value (conversion). Copy the example code into main.c
Hint: Pay attention to the number of bits in adc_result_t in the typedef statement. This will be important later.
Note: The example code has an error. The following line:
adcX_channel_t convertedValue;
should be as follows instead:
adc_result_t convertedValue;
Find the declared constant for the ADC input pin you have configured (hint: check the Pin Module). Supply this value as the input to the ADC single-read function.
You will need to define a new variable to use the output of this function. Refer to the commented out example code to determine the appropriate data type for the variable.
Open up PWMX.h
Open up TMRX.h
Now tie these new functions together into your main.c:
Add a new line of code to read a single value from the ADC and store it in a variable of the correct type. Refer to the adc subsystem header file generated by MCC to find the correct data type.
Next, add a new line of code to output the data stored in that variable to EUSART using printf(). Make sure to add carriage return and newline characters to clean up your transmission so that each new ADC value is output on a new line in Putty.
Hint: Remember that X bit variables will have values between 0 and 2^X^-1. If you are printing numbers outside of that range then something is incorrect with your conversion. See Microchip’s documentation on printf() for more information.
Next, add a new variable with type float and use it to translate the integer ADC value to a decimal value that represents the voltage read on the ADC pin. Output that floating point value using the printf() function and the format specifier section of the printf()documentation linked in the previous step and as seen in the MPLABX tutorial. Your data should print on two lines, e.g.:
ADC value: 255
ADC voltage: 3.300
NOTE: This may require a brush up on data types and converting or type casting from int to float in C.
Add a new line of code for using the ADC value you read and converted previously to change the PWM duty cycle. This is the raw ADC value before you converted it again to voltage.
Context: Changing the duty cycle changes the percentage of the time a square wave is low or high. Variable duty cycles are often used for driving RC Servos or -- in conjunction with a low pass filter -- for approximating a simple and low-fidelity digital to analog converter(DAC).
Ensure you are converting the X-bit ADC value to a properly-formatted Y-bit duty cycle value. (Though the functions that operate on these two registers accept 16-bit variables, they only use the least significant / bottom X and Y bits of each 16-bit variable). The information about the size of X and Y was found by you in the first steps of this assignment.
More Context: The X-bit resolution(see PIC18F47Q10 Datasheet) ADC result is stored in a 16-bit variable of type adc_result_t, which is wider (more bits) than the resolution of the ADC result. Furthermore, the PWM duty cycle register holds fewer bits than the resolution of the ADC. Thus, we want to transfer the most significant bits of the ADC’s reading into the PWM’s duty cycle register. The least significant bits of the ADC represent such a small difference in the final result that they can be truncated (cut off).
Write a line of code that uses a C bit shifting operator to shift the ADC result so that the most significant 8 bits of the ADC’s output are used as an input to the PWM subsystem’s duty cycle update function (look in the PWM header file). Be sure to “cast” this variable into the correct type declared by that function.\
After shifting, the lower 8 bits of your adc_result_t variable should look like this (where x is the number of resolution bits for the ADC):
… | ADC |
ADC |
ADC |
ADC |
ADC |
ADC |
ADC |
ADC |
And that’s it!