ECE 3567
Lab 4
Analog-to-Digital Converters
Dr. Gregg J ChapmanAutumn 2019
1
The Users Manual
Chapter 33 REF_A………………………………….pp 858-864Chapter 34 ADC12_B……………………………..pp 865-911
2
Laboratory #4 Goals
1. Implement a TWO channel conversion sequence, one channel for the RC_Voltage (A5), and a second channel for the internal Temperature Sensor (A30).
2. Display the temperature in Fahrenheit on the Liquid Crystal Display.
3. Measure the RC filtered voltage and set the LED color according to voltage values.
4. Display the RC filtered voltage on the Liquid Crystal Display.
5. Configure a Pushbutton to change the LCD display to either temperature or voltage.
The RC Circuit
fcutoff = 6 Hz
ADC A5
A5 input on ADC12
RC charging circuit P2.1 PWM output
The Temperature Sensor
LaunchPad LCD Display
6
LaunchPad Pushbuttons
Lab #4 Downloaded Files
NOTE: Save the RC voltage functions that you wrote last week and add them to the RCMode.c if necessary.
8
ADC12.c
void Init_ADC12(void)__interrupt void ADC12_ISR(void)
Template with declarations and headers is included in the Lab 4 Code Additions download. Copy and ADD all files to your existing project directory.
9
ADC12.cvoid Init_ADC12(void)
10
ADC12 InitializationInit_ADC12()
1. Set pin 8.6 as the ANALOG INPUT for A-to-D channel A52. Configure the Internal Voltage Reference.3. Set up Timer A1 as the ADC SAMPLE CLOCK4. Activate the internal Temperature Sensor (must ne on ADC12 channel A30)5. Configure the ADC12 for a 2-channel repeated sequence, beginning with A30 and
ending with A5.6. Set up MEM0 buffer to receive channel A30 data values.7. Set up MEM1 buffer to receive channel A5 data values.8. Generate the ADC12 Interrupt whenever MEM1 receives a new conversion value.9. Clear any pending interrupts, enable interrupts, and start the repeated conversion
sequence.
NOTE: Don’t forget to call Init_ADC12() at the beginning of main().
11
1. Set-up P8.6 as Channel A5
12
1 1 Tertiary
Note: It is not necessary to set the P8DIR register, bit 6, as an input when you select the A5 (Tertiary) function.
2. Configure Internal Voltage Reference
14
2. Configure Internal Voltage ReferenceRegister – ADC12MCTLx
VCC - Positive Voltage, AnalogVEE - Negative Voltage (or GND), Analog
VDD - Positive Voltage, DigitalVSS - Negative Voltage (or GND), Digital
De-Mystifying Voltage Labels
1. Clear TA1CTL2. Select ACLK and No Pre-Divide in TA1CTL
3. Set-up Timer A1 as Sample Clock
3. In TA1CCTL1, Select Compare Mode, Reset/Set Output Mode, Interrupts Disabled
17
3. Set-up Timer A1 as Sample Clock
4. In TA1CCR0, Set Period for a Frequency of 32 Hz. This gets /8 later for a 4Hz sample rate5. In TA1CCR1, Set Duty Cycle to 50%
18
3. Set-up Timer A1 as Sample Clock
6. Start Timer in UP Mode by writing Bits 5-4 to [01]3. Set-up Timer A1 as Sample Clock
4. Activate Internal Temperature Sensor5. Configure ADC12 for 2-Channel Repeated Sequence
There are FOUR Configuration Registers for the ADC12_B:
ADC12CTL0 – ADC12CTL3.
ADC12 ConfigurationRegister – ADC12CTL0
1. Set the clock cycles for sample-and-hold for MEM8-MEM23 to 256 (Bits 15-12) 1000
21
ADC12 ConfigurationRegister – ADC12CTL0
2. Set the clock cycles for sample-and-hold for MEM0-MEM7 to 4 (Bits 11-8) 0000
22
ADC12 ConfigurationRegister – ADC12CTL0
3. Set Bit 7 to cause the first rising edge of the SHI to initiate sampling and continue automatically4. Turn on the ADC12 Module (Bit 4)XX1X5. Disable Conversion (Bit 1)
23
ADC12 ConfigurationRegister – ADC12CTL1
24
1. Pre-divide the clock source by 4 (Bit 14-13)
ADC12 ConfigurationRegister – ADC12CTL1
25
1. Pre-divide the clock source by 4 (Bit 14-13)2. Select Timer A1 as the clock source by configuring Bits 12-10 to [100] *
* SEE NEXT SLIDE for this incredible example of the inefficiency in the TI documentation!
Register – ADC12CTL1
• This setting depends on which microcontroller model you have. • The setting is in a completely different manual for each MCU!!• I have placed a copy of the MSP430FR6989.PDF on the course website
Page 88
* ADC12SHSx - Select Timer A1 as the clock source by configuring Bits 12-10 to [100] *
= 0x100
ADC12 Configuration
26
ADC12 ConfigurationRegister – ADC12CTL1
27
1. Pre-divide the clock source by 4 (Bit 14-13)2. Select Timer A1 as the clock source by configuring Bits 12-10 to [100] *3. Configure the ADC12_B clock divider to 2 (Bits 7-5)
ADC12 ConfigurationRegister – ADC12CTL1
28
1. Pre-divide the clock source by 4 (Bit 14-13)2. Select Timer A1 as the clock source by configuring Bits 12-10 to [100] *3. Configure the ADC12_B clock divider to 2 (Bits 7-5)4. Configure Bits 4-3 to select ACLK as the source clock
ADC12 ConfigurationRegister – ADC12CTL1
29
1. Pre-divide the clock source by 4 (Bit 14-13)2. Select Timer A1 as the clock source by configuring Bits 12-10 to [100] *3. Configure the ADC12_B clock divider to 2 (Bits 7-5)4. Configure Bits 4-3 to select ACLK as the source clock5. Select the Repeated-Sequence-of-Channels option for Bits 2-1
ADC12 ConfigurationRegister – ADC12CTL2
30
This register controls bit resolution and data readback format.There are no changes from the default values in this register
Register – ADC12CTL31. Set Bit 7. This selects the Temperature Sensor for ADC channel A30
ADC12 Configuration
31
Register – ADC12MCTL0
1. Disable the Comparator Window2. Enable Single-ended Mode
32
6. Set MEM0 Buffer for A30 Data
Register – ADC12MCTL03. Set voltage source combination to VR+ = VREF buffered, VR- = AVSS
33
6. Set MEM0 Buffer for A30 Data
Register – ADC12MCTL0
4. MEM0 is NOT the end of the sequence
34
6. Set MEM0 Buffer for A30 Data
Register – ADC12MCTL05. Select A30 (the temperature probe) as the Input Source.
6. Set MEM0 Buffer for A30 Data
Register – ADC12MCTL1
36
7. Set MEM1 Buffer for A5 Data
1. Disable the Comparator Window2. Enable Single-ended Mode
Register – ADC12MCTL1
3. Set voltage source combination to VR+ = AVCC, VR- = AVSS
7. Set MEM1 Buffer for A5 Data
Register – ADC12MCTL14. MEM1 IS the end of the sequence
38
7. Set MEM1 Buffer for A5 Data
Register – ADC12MCTL15. Select A5 as the Input Source.
39
7. Set MEM1 Buffer for A5 Data
9a. Clear Interrupts (write 0)
8. Generate the ADC12 Interrupt whenever MEM1 receives a new conversion value.
9b. Enable Interrupts
9c. Enable Conversion
Please have your Init_ADC12() checked before proceeding
43
Checkpoint #1
1. In the ADC12 Interrupt Service Routine, for the ADCMEM1 interrupt case:
a. Clear the Interrupt:
ADC12_B_clearInterrupt(ADC12_B_BASE, 0, ADC12_B_IFG1);
b. Transfer MEM0 and MEM1 values to the following variables:
ADCValue0 = ADC12MEM0;
ADCValue1 = ADC12MEM1;
2. Comment out the #pragma for the Timer A1 vector and the ADC12 vector
ADC12 Configuration – Interrupt Service Routine
44
The ADC12 Interrupt Service Routine
45
ADC12 Configuration – Don’t forget to comment out used #pragmasin unused_interrupts.c
46
TempSensorMode.c
47
TempSensorMode.c Functions
48
TempSensorMode.c Functions
49
void displayTemp(){
clearLCD();if (tempUnit == 0){
showChar('C',pos6);}else{
showChar('F',pos6);}
// Handles displaying up to 999.9 degreesif (deg>=1000)
showChar((deg/1000)%10 + '0',pos3);if (deg>=100)
showChar((deg/100)%10 + '0',pos4);if (deg>=10)
showChar((deg/10)%10 + '0',pos5);
// Degree symbolLCDMEM[pos5+1] |= 0x04;
}
50
//Uses Modulo Division to get Remainder// then adds 48 (‘0’) to convert to ASCII// One decimal place at a time
TempSensorMode.c Functions
myLcd.c
51
LaunchPad LCD Display
52
myLcd.c Character Maps
53
// LCD memory map for uppercase lettersconst char alphabetBig[26][2] ={
{0xEF, 0x00}, /* "A" LCD segments a+b+c+e+f+g+m */
{0xF1, 0x50}, /* "B" */{0x9C, 0x00}, /* "C" */{0xF0, 0x50}, /* "D" */{0x9F, 0x00}, /* "E" */{0x8F, 0x00}, /* "F" */{0xBD, 0x00}, /* "G" */{0x6F, 0x00}, /* "H" */{0x90, 0x50}, /* "I" */{0x78, 0x00}, /* "J" */{0x0E, 0x22}, /* "K" */{0x1C, 0x00}, /* "L" */{0x6C, 0xA0}, /* "M" */{0x6C, 0x82}, /* "N" */{0xFC, 0x00}, /* "O" */{0xCF, 0x00}, /* "P" */{0xFC, 0x02}, /* "Q" */{0xCF, 0x02}, /* "R" */{0xB7, 0x00}, /* "S" */{0x80, 0x50}, /* "T" */{0x7C, 0x00}, /* "U" */{0x0C, 0x28}, /* "V" */{0x6C, 0x0A}, /* "W" */{0x00, 0xAA}, /* "X" */{0x00, 0xB0}, /* "Y" */{0x90, 0x28} /* "Z" */
};
// LCD memory map for numeric digitsconst char digit[10][2] ={
{0xFC, 0x28}, /* "0" LCD segments a+b+c+d+e+f+k+q */{0x60, 0x20}, /* "1" */{0xDB, 0x00}, /* "2" */{0xF3, 0x00}, /* "3" */{0x67, 0x00}, /* "4" */{0xB7, 0x00}, /* "5" */{0xBF, 0x00}, /* "6" */{0xE4, 0x00}, /* "7" */{0xFF, 0x00}, /* "8" */{0xF7, 0x00} /* "9" */
};
myLcd.c Functions
54
void Init_LCD(){
LCD_C_initParam initParams = {0};initParams.clockSource = LCD_C_CLOCKSOURCE_ACLK;initParams.clockDivider = LCD_C_CLOCKDIVIDER_1;initParams.clockPrescalar = LCD_C_CLOCKPRESCALAR_16;initParams.muxRate = LCD_C_4_MUX;initParams.waveforms = LCD_C_LOW_POWER_WAVEFORMS;initParams.segments = LCD_C_SEGMENTS_ENABLED;
LCD_C_init(LCD_C_BASE, &initParams);// LCD Operation - VLCD generated internally, V2-V4 generated internally, v5 to ground
LCD_C_setPinAsLCDFunctionEx(LCD_C_BASE, LCD_C_SEGMENT_LINE_0,LCD_C_SEGMENT_LINE_21);
LCD_C_setPinAsLCDFunctionEx(LCD_C_BASE, LCD_C_SEGMENT_LINE_26,LCD_C_SEGMENT_LINE_43);
LCD_C_setVLCDSource(LCD_C_BASE, LCD_C_VLCD_GENERATED_INTERNALLY,LCD_C_V2V3V4_GENERATED_INTERNALLY_NOT_SWITCHED_TO_PINS,LCD_C_V5_VSS);
// Set VLCD voltage to 3.20vLCD_C_setVLCDVoltage(LCD_C_BASE,
LCD_C_CHARGEPUMP_VOLTAGE_3_02V_OR_2_52VREF);
// Enable charge pump and select internal reference for itLCD_C_enableChargePump(LCD_C_BASE);LCD_C_selectChargePumpReference(LCD_C_BASE,
LCD_C_INTERNAL_REFERENCE_VOLTAGE);
LCD_C_configChargePump(LCD_C_BASE, LCD_C_SYNCHRONIZATION_ENABLED, 0);
// Clear LCD memoryLCD_C_clearMemory(LCD_C_BASE);
//Turn LCD onLCD_C_on(LCD_C_BASE);
}
myLcd.c Functions
55
void showChar(char c, int position){
if (c == ' '){
// Display spaceLCDMEM[position] = 0;LCDMEM[position+1] = 0;
}else if (c >= '0' && c = 'A' && c
myLcd.c Functions
56
/** Clears memories to all 6 digits on the LCD*/void clearLCD(){
LCDMEM[pos1] = LCDBMEM[pos1] = 0;LCDMEM[pos1+1] = LCDBMEM[pos1+1] = 0;LCDMEM[pos2] = LCDBMEM[pos2] = 0;LCDMEM[pos2+1] = LCDBMEM[pos2+1] = 0;LCDMEM[pos3] = LCDBMEM[pos3] = 0;LCDMEM[pos3+1] = LCDBMEM[pos3+1] = 0;LCDMEM[pos4] = LCDBMEM[pos4] = 0;LCDMEM[pos4+1] = LCDBMEM[pos4+1] = 0;LCDMEM[pos5] = LCDBMEM[pos5] = 0;LCDMEM[pos5+1] = LCDBMEM[pos5+1] = 0;LCDMEM[pos6] = LCDBMEM[pos6] = 0;LCDMEM[pos6+1] = LCDBMEM[pos6+1] = 0;
LCDM14 = LCDBM14 = 0x00;LCDM18 = LCDBM18 = 0x00;LCDM3 = LCDBM3 = 0x00;
// LCDMEM[12] = LCDMEM[13] = 0;}
myLcd.c Functions
57
Quiz Question
What number do you subtract from the ASCII character for a number to convert from ASCII code to an actual numeric value?
What is the number in Hexadecimal?
What is the number in Decimal?
What ASCII number can you subtract from another ASCII number to convert it to a decimal value?
What do you add to a number to convert to the ASCII character?
58
void displayTemp(){
clearLCD();if (tempUnit == 0){
showChar('C',pos6);}else{
showChar('F',pos6);}
// Handles displaying up to 999.9 degreesif (deg>=1000)
showChar((deg/1000)%10 + '0',pos3);if (deg>=100)
showChar((deg/100)%10 + '0',pos4);if (deg>=10)
showChar((deg/10)%10 + '0',pos5);
// Degree symbolLCDMEM[pos5+1] |= 0x04;
}
59
//Uses Modulo Division to get Remainder// then adds 48 (‘0’) to convert to ASCII// One decimal place at a time
TempSensorMode.c Functions
Checkpoint #2
Demonstrate the temperature sensor on the LCD (display) in Fahrenheit with 16 averages and updating once every second. You may use the cold spray to change the temperature rapidly.
60
RCMode.c
61
RCMode.c
62
void RC_Voltage(){
ISR_Flag = 0;// Calculate voltage from A5 ADC dataunsigned int tempRC = (ADCValue1);tempRC = ((((unsigned long)tempRC)*4/5) + 28);
// Averaging Routinek2++;sum2 = sum2 + tempRC;if(k2 >= Vsize) // Vsize is the number of values to average. In 3567.h{
volts = sum2/(Vsize);sum2 = 0;k2 = 0;
// Display Voltageif(LCD_Control == TRUE)
displayVolts();}
}
RCMode.c
63
Demonstrate the filtered RC voltage with 2 digits after the decimal, an average of 16 value, and updating once per second.
64
Checkpoint #3
//*********************The Initializations*************************************/Init_LCD();Init_GPIO();Init_Clocks();Init_PWM(); // This was written for you and should be in TempSensorMode.ctempSensorModeInit(); // Given. Add this.Init_ADC12(); // New. You write thisInit_RC(); // You wrote this last weekInit_LCD(); // Given. Add this.
Update the main() Initializations
65
Pushbutton Bounce
• Software must require button to remain in a stable logic state for at least the duration of a worst case observed for switch bounce.
• Multiple transitions causes many state changes or PB Interrupts.
• Use multiple pin reads and a counter to verify that the logic level of the button has remained stable for the debounce duration.
• Measure worst case with oscilloscope
• Use delays, with or without ISR, to verify bounce duration has ended.
66
6 mS 6 mSTransition Verified
INTERRUPTS
Pushbutton Code
67
1. Use BOTH pushbuttons. One to change the LCD to RC_Voltage and the other pushbutton to change the LCD to display temperature.
2. Clear the LED and LCD when either button is pressed and held.
3. Use the Booleans RC_Control and T_Control to select which process is displayed.
if(Temp_Button_Press >=5) // Detect 500 mSec button press.{
RC_Control= FALSE;T_Control = TRUE;PWM_null(); // Turn off LEDclearLCD(); // Clear out LCDTemp_Button_Press = 0;Volt_Button_Press = 0;while((P1IN & BIT1) == 0x00);
}else if(Volt_Button_Press >=5){
RC_Control= TRUE;T_Control = FALSE;
PWM_null(); // Turn off LEDclearLCD(); // Clear out LCDTemp_Button_Press = 0;Volt_Button_Press = 0;while((P1IN & BIT2) == 0x00);
}
Pushbutton Code
68
4. “Debounce” the button press by delaying action for 500 milliseconds. Note that this is 5 executions of the Timer A0 ISR.
Pushbutton Code
69
5. Comment out the Interrupt configurations for P1.1 and P1.2 in Init_GPIO():
Pushbutton Code
70
6. IN unused_interrupts.c, make sure the #pragma vector = PORT1_VECTOR // Port 1 is NOT commented out
7. Configure BOTH pushbuttons as INPUTS with PULL_UP Resistors at the beginning of main():
P1DIR &= ~BIT1; // Set as InputP1REN |= BIT1; // Configure Pull-up ResistorP1OUT |= BIT1; // Completes Pull-up Configuration
NOTE: No Pull-up Rs here unless configured!
Pushbutton CodePolling Method
71
8. Modify main() to conditionally execute the RC voltage or Temperature Measurement using Booleans. Toggle the two control Booleans in main if the pushbutton is pressed. e.g.:
if(RC_Control == TRUE) // Change PWM, measure voltage and display color range{
update_RC();RC_Voltage();update_RGB();
}else if(T_Control == TRUE) // Temperature in Fahrenheit on displayed on LCD{
tempSensor();}
If-else for LED Color
72
1. Add if-else code to update_RGB() change the LED color every 500 mV.
2. The voltage should be calculated from the AVERAGED A5 A-to-D value. This variable is called volts
3. Use the following table:
COLORVoltage Range
Min Voltage (mV) Max Voltage (mV)
RED 0 500
ORANGE 501 1000
YELLOW 1001 1500
GREEN 1501 2000
BLUE 2001 2500
PURPLE 2501 3000
WHITE > 3000 NA
Checkpoint #4 and #5
#4 - Demonstrate that the two pushbuttons select either the RC_Voltage or the Temperature (F) function. The LED and LCD should remain off if either button is pressed and held.
#5 - In the RC_Voltage mode, demonstrate that the LED changes color based on the filtered RC voltage according to the table provided.
73
ECE 3567��Lab 4��Analog-to-Digital Converters�The Users Manual�Laboratory #4 GoalsSlide Number 4The Temperature SensorLaunchPad LCD DisplayLaunchPad PushbuttonsLab #4 Downloaded FilesADC12.c�ADC12.c�ADC12 Initialization�Init_ADC12()Slide Number 12Slide Number 13Slide Number 14Slide Number 15Slide Number 16Slide Number 17Slide Number 18Slide Number 19Slide Number 20ADC12 ConfigurationADC12 ConfigurationADC12 ConfigurationADC12 ConfigurationADC12 ConfigurationSlide Number 26ADC12 ConfigurationADC12 ConfigurationADC12 ConfigurationADC12 ConfigurationADC12 ConfigurationSlide Number 32Slide Number 33Slide Number 34Slide Number 35Slide Number 36Slide Number 37Slide Number 38Slide Number 39Slide Number 40Slide Number 41Slide Number 42Checkpoint #1ADC12 Configuration – Interrupt Service RoutineSlide Number 45ADC12 Configuration – Don’t forget to comment out used #pragmas� in unused_interrupts.cSlide Number 47TempSensorMode.c FunctionsTempSensorMode.c FunctionsTempSensorMode.c FunctionsSlide Number 51LaunchPad LCD DisplaymyLcd.c Character MapsmyLcd.c FunctionsmyLcd.c FunctionsmyLcd.c FunctionsmyLcd.c FunctionsQuiz QuestionTempSensorMode.c FunctionsCheckpoint #2Slide Number 61Slide Number 62Slide Number 63Checkpoint #3Slide Number 65Slide Number 66Slide Number 67Slide Number 68Slide Number 69Slide Number 70Slide Number 71Slide Number 72Checkpoint #4 and #5