Code/Analog to Digital Conversion

Old abandoned gas pump

Always remember:

Binary String

Volts to bits:

So finally we are at the point where we need to come up with a way to make our microcontroller alter the PWM signal which will control the switching of the MOSFETS in our h-bridge. The method of doing so will involve converting the analog voltage of a 10 kOhm potentiometer into a digital value that is converted to a specific pulse width. Furthermore, the overall range of possible voltage values of the potentiometer (0v-5v) will be split into two halves. The upper half of the values will represent a forward rotation of the motor (increasing in speed as the voltage output of the potentiometer increases) and the lower half will represent a reverse direction of the motor (increasing in speed as the voltage output of the potentiometer decreases).

As was mentioned before, I will assume this is not your first time programming in PIC assembly language and I will cover the main points that are relevant to this application while skipping over some basic concepts that are assumed to be known already (the overall instruction set and basic configuration of a PIC MCU etc..) My personal method of doing this is to use MPLABX in Linux to write my programs. The physical programming of the MCU is done via the terminal/command line using another Linux program called "pk2cmd". My programmer of choice is a PICKIT2 clone I found on Amazon which has worked great for me so far. Additionally, the instructions I post here are for the PIC16F1937. If you are using a different MCU you may or may not have to tweak the instructions. (There are differences amongst devices.). The advice that follows covers the key apsects and ideas behind the instructions used. A copy of the entire program will be made available as a text file at the end of the tutorial.

There is a lot going on here in setting up the ADC module. Since this isn't a tutorial on ADC, explaining everything in full detail would drag on for quite a bit and deviate from the main topic so I will cover the configuration in a brief manner.

In order to use the potentiometer as an input device I first configured PORTA, 0 (pin #2) to be an input pin through the TRIS registers as is done with any I/O pin.

movlw   b'00000001'

movwf   (TRISA ^ BANK1)

Although PORTA, 0 is now configured as an input pin, it is configured as a DIGITAL input. (Not what we want.) To configure it as an ANALOG input we need to set up the ANSELA register. For each bit set to "1" of this register, the corresponding physical pin of PORTA will be designated as an analog input. Hence:

movlw     b'00000001'

banksel   ANSELA

movwf     ANSELA

sets PORTA, 0 to an analog input pin.

Storing the ADC result (ADRESH and ADRESL registers):

The result of our analog to digital conversion is a 10 bit number that is stored in the ADRESH and ADRESL registers. We can specify that the result be left-justified (8 most significant bits in ADRESH and 2 least significant bits in ADRESL) or right-justified (8 least significant bits in ADRESL and 2 most significant bits in ADRESH).

Left-Justification:

ADDRESH (Contains 8 MSB) ADDRESL (Contains 2 LSB)
1 1 1 1 1 1 1 1 1 1 - - - - - -

Right-Justification:

ADDRESH (Contains 2 MSB) ADDRESL (Contains 8 LSB)
- - - - - - 1 1 1 1 1 1 1 1 1 1

For our purposes we will not be utilizing the full 10-bit resolution of the ADC conversion. 8-bits is plenty sufficient for the purposes of driving our h-bridge. Therefore we will use left-Justification and simply discard the 2 least significant bits held in register ADRESL during our calculations. To specify left-justification, we need to visit the ADCON1 register.

Setting up the ADCON1 register:

ADCON1 Register
7 6 5 4 3 2 1 0
ADFM ADCS2 ADCS1 ADCS0 -NOT USED ADNREF ADPREF1 ADPREF0

When ADFM (bit #7) is set to zero, we get left-justification. Set it to one and we get right-justification. In addition to left-justifying the result we will also set the conversion clock for the ADC module. The minimum amount of time required for an ADC conversion is 1.6 microseconds (uS) for each bit that is converted. We want to set the clock to perform the conversion as quick as possible, but with enough margin for error above 1.6 uS in order to avoid the possibility of inaccurate results

Without explaining all of the options available for the ADC conversion clock and how the calculations are performed, the brief explanation is as follows: We will be running the processor at a speed of 4Mhz. The PIC 16 series MCUs divide this by 4 and obtain an instruction speed of one instruction every microsecond. By setting bits 4, 5, and 6 of ADCON1 to 1, 0, and 0 respecively, we arrive at an ADC conversion clock speed that is double the instruction cycle speed of 1uS (2uS). This is safely above the required 1.6uS. Therefore, the entire 10 bits will be converted in 22uS which includes a 2uS period to start the conversion process. More detailed information can be found in the datasheet as well as the excellent documentation on Microchip's website and the Googlium tutorials.

We will specify left-justification and a 2uS conversion clock speed by configuring ADCON1 as follows (additionally, bits 0-2 of ADCON1 will be cleared):

movlw     b'00010000'

banksel   ADCON1

movwf     ADCON1

Along with the ADCON1 register, we need to take a look at the ADCON0 register as well.

Setting up the ADCON0 register:

ADCON0 Register
7 6 5 4 3 2 1 0
NOT USED CHS4 CHS3 CHS2 CHS1 CHS0 GO/DONE ADON

The ADCON0 register allows us to specify which pins of the device will be utilized in the ADC process. The section of the datasheet which deals with ADC shows all of the different bit combinations for the CHS4-0 field and the corresponding pin assignments. By setting the CHS field to "00000" (all zeros for CHS0-4), we are designating AN0 (pin #2 of the device) as the analog input pin whose signal will be input into the ADC conversion module. Additionally, bit #0 of this register turns the ADC module on when it is set. Furthermore, bit #1 starts the ADC process when it is set and is automatically cleared by the hardware when the ADC process is complete.

The following 3 instructions accomplish all of the above:

movlw     b'00000001'

banksel   ADCON0

movwf     ADCON0

With the above steps, we have accomplished our goal of setting up the ADC module for the PIC16F1937. We can now proceed to configure the microcontroller to handle the PWM output that will drive our H-bridge.

Continue on to PWM code