Created
November 15, 2023 16:42
-
-
Save ajarmst/55676d620a906e8ccb53f179a35e3087 to your computer and use it in GitHub Desktop.
Demonstration of using the ECT to control a HC-SR04 ultrasonic distance sensor
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///////////////////////////////////////////////////////////////////////////// | |
// HC12 Program: Exam 1 - Solution | |
// Processor: MC9S12XDP512 | |
// Bus Speed: 20 MHz (Requires Active PLL) | |
// Author: AJ Armstrong, based on work by Carlos Estay | |
// Details: Demo of using the ECT for an HC-SR04 ultrasonic distance snsr | |
// Date: Nov 2023 | |
// Revision History : | |
///////////////////////////////////////////////////////////////////////////// | |
#include <stdio.h> // For sprintf, etc | |
#include <ctype.h> // For character utilities | |
#include <string.h> // Various string utilities | |
#include <hidef.h> // Common defines and macros | |
#include "derivative.h" // Derivative-specific definitions | |
#include "pll.h" // Phase-locked loop clock control | |
#include "swled.h" // GPIO switches and LEDs | |
#include "segs.h" // 7-Segment Displays | |
#include "timer.h" // Enhanced capture timer | |
#include "portj.h" // Interrupt buttons | |
#include "pit.h" // Periodic Interrupt timer | |
#include "rti.h" // Realtime interrupts | |
#include "lcd.h" // LCD Display | |
#include "sci.h" // Serial communications interface (EIA/TIA-232) | |
///////////////////////////////////////////////////////////////////////////// | |
// Local Prototypes | |
///////////////////////////////////////////////////////////////////////////// | |
void SegsUpdate(void); //RTI event | |
///////////////////////////////////////////////////////////////////////////// | |
// Global Variables | |
///////////////////////////////////////////////////////////////////////////// | |
volatile unsigned int rEdge = 0, fEdge = 0; | |
volatile char update = 0; //Do I need to update my range (controlled by RTI) | |
///////////////////////////////////////////////////////////////////////////// | |
// Constants | |
///////////////////////////////////////////////////////////////////////////// | |
//I use constants for parameters that would otherwise be magic numbers. | |
int const gkiTriggerPeriod = 65000; //usec between trigger pulses | |
int const gkiTriggerDuration = 12; //usec duration of trigger pulse | |
double const gkdSndSpd = 1.7241e-4; // m/s (58 usec/cm) for calc. distance | |
///////////////////////////////////////////////////////////////////////////// | |
// Main Entry | |
///////////////////////////////////////////////////////////////////////////// | |
void main(void) | |
{ | |
// Variables | |
int pWidth = 0; //Return pulse width in uS | |
double distance = 0.0; //Calculated distance in mm | |
_DISABLE_COP(); // No watchdog | |
///////////////////////////////////////////////////////////////////////////// | |
// One-Time Initializations | |
///////////////////////////////////////////////////////////////////////////// | |
PLL_To20MHz(); // Configure the main clock to 20 MHz (implications for timers) | |
SWL_Init(); // Standard initialization for switches and LEDs | |
SEG_Init(); // Standard initializaton for 7-seg displays | |
RTI_Init(); // Initialize RTI timer | |
//Configure RTI to trigger the update flag every 500 msec | |
RTI_RegisterEvent(0,SegsUpdate,500); | |
//Configure a 1 uSec tick time (1 MHz is 20 MHz / 20) | |
TSCR1 |= TSCR1_PRNT_MASK; //Enable precision timer | |
PTPSR = 20 - 1; //Prescale by 20 - tick timer @1us; | |
////////////////////////////////////////////////////// | |
// Use Output Compare to create a very specific pulse | |
// to trigger my HC-SR04 device | |
///////////////////////////////////////////////////// | |
//Configure OC Timer on pins 1,7 for my triggering pulse | |
TIOS_IOS7 = 1; //enable channel 7 as output | |
TIOS_IOS1 = 1; //enable channel 1 as output | |
//I want my output pulse to be 12 uSec, every 65 msec. | |
//See the datasheet for my sensor. | |
TC7 = gkiTriggerPeriod; //65 ms after TCNT = 0 (TC1 to go high) | |
TC1 = TC7 + gkiTriggerDuration; //12 us after that (TC1 to go back low) | |
//I'm not actually going to use Pin PT7, but I can set it to | |
//toggle for testing purposes | |
TCTL1_OM7 = 0; | |
TCTL1_OL7 = 1; | |
//TC1 I do want to toggle (although, in practice, because TC7 will | |
//be forcing it up to a one, it will always be toggling down) | |
TCTL2_OM1 = 0; | |
TCTL2_OL1 = 1; | |
//This is the fun bit: I'm going to use TC7 to drag the pin for TC1 high | |
//before the toggle event on TC1 drags TC1 low 12 uSec later | |
OC7M |= OC7M_OC7M1_MASK; //Affect PT1 on CH7 compare event | |
OC7D |= OC7M_OC7M1_MASK; //Transfer a high to PT1 on event | |
//Turn on interrupts for the pins I care about | |
TIE_C7I = 1; //Pin 7 | |
TIE_C1I = 1; //Pin 1 | |
////////////////////////////////////////////////////// | |
// Use Input Capture to measure exactly when the HC-SR04 | |
// detects the return pulse. | |
///////////////////////////////////////////////////// | |
//Configure TC0 to use input capture | |
TIOS_IOS0 = 0; | |
//Capture any edge (rising or falling) | |
//BA = 00 (No capture), 01 (Rising), 10 (falling), 11 (both) | |
TCTL4_EDG0B = 1; | |
TCTL4_EDG0A = 1; | |
//Turn on interrupts on the channel I care about | |
TIE_C0I = 1; | |
// Enable entire timer subsystem | |
TSCR1 |= TSCR1_TEN_MASK; | |
///////////////////////////////////////////////////////////////////////////// | |
// Main Program Loop | |
///////////////////////////////////////////////////////////////////////////// | |
EnableInterrupts; // Ensure our board will respond to interrupt signals. | |
for (;;) | |
{ | |
//Based on my RTI event, I'm going to update the distance on my 7 Segs | |
if(update) | |
{ | |
update = 0; | |
pWidth = fEdge - rEdge; // width of pulse in uSec | |
distance = pWidth * gkdSndSpd * 1000.0; //Calculate distance in mm | |
SEG_16D(pWidth,0); // Width of pulse in uSec | |
SEG_16D((int)distance,1); // Distance in mm | |
} | |
} | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// Functions | |
///////////////////////////////////////////////////////////////////////////// | |
void SegsUpdate(void) | |
{ | |
update = 1; // Trigger an update | |
} | |
///////////////////////////////////////////////////////////////////////////// | |
// Interrupt Service Routines | |
///////////////////////////////////////////////////////////////////////////// | |
//Timer 7 will trigger the start of arming pulse, every 65 ms | |
interrupt VectorNumber_Vtimch7 void Vtimch7_ISR(void) | |
{ | |
TC7 += gkiTriggerPeriod; //Re-arm | |
TFLG1 = TFLG1_C7F_MASK; //Clear flag (not using FFC this time) | |
} | |
//Timer 1 will trigger the end of arming pulse, every 12 uSec later | |
//Timer 1 and 7 already offset by 12 usec, so just add 65000 | |
interrupt VectorNumber_Vtimch1 void Vtimch1_ISR(void) | |
{ | |
TC1 += gkiTriggerPeriod; //Re-arm | |
TFLG1 = TFLG1_C1F_MASK; //Clear flag | |
} | |
//Timer 0 will capture every edge of the returning pulse. | |
//Capturing both edges allows me to measure width of return pulse | |
interrupt VectorNumber_Vtimch0 void Vtimch0_ISR(void) | |
{ | |
// I Can figure out if it was leading or trailing by just reading the pin value | |
if(PTT & PTT_PTT0_MASK) // PT0 is currently High, must have been leading edge | |
rEdge = TC0; //Time of rising edge | |
else // must have been low | |
fEdge = TC0; //That was the falling edge | |
TFLG1 = TFLG1_C0F_MASK; //Clear flag | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment