\documentclass[letterpaper]{article} \author{Jonathan Chan (15354146)} \title{PHYS 319\\Labs 5 and 6 Notes} \usepackage{fullpage} \usepackage{minted} \usepackage{siunitx} \usepackage{hyperref} \begin{document} \maketitle The goal of this lab is to measure distances with the ultrasonic ranger. References to specific values and other documentation notes refer to \url{http://www.robot-electronics.co.uk/htm/srf04tech.htm}. The steps to achieve this can be outlined as follows: \begin{enumerate} \item Send a trigger pulse to the ranger. According to the documentation, this pulse needs to be $\SI{10}{\micro s}$ long. \item Wait for the echo input to be raised. This can be done by setting a low-to-high interrupt on the echo pin. \item Time the length of the echo pulse sent by the ranger. We will set \texttt{TAR} to 0 and retrieve the value of \texttt{TAR} when the echo pin is lowered, which can be done by setting a high-to-low interrupt on the echo pin. We will use the SMCLK timer, which runs at $\SI{1}{M\hertz}$, meaning that the maximum length that can be measured without overflowing is $\SI{65 535}{\micro s}$. However, according to the documentation, the ranger will time out and lower the echo pin after $\SI{30 000}{\micro s}$, so we aren't in danger of overflowing. \item Convert the measurement to distance in centimetres. According to the documentation, we need to divide by $58$. Since we're limited to sending one byte at a time, we can also set the value to $0$ if the distance exceeds $\SI{255}{cm}$ to prevent the plot from graphing meaningless overflowed values. \item Send the data to the Python plot. This portion of the code will come from the provided temperature measurement program. \item Repeat the measurement. According to the documentation, we need to wait $\SI{10}{ms}$ to allow the ranger to recharge. I've set the delay to $\SI{100}{ms}$ to smooth out the data and prevent rapid changes in the position of the ranger from being recorded. \end{enumerate} With some measurements using a metre stick, the distances measured by the ranger are indeed accurate to the centimetre. It also appears that it cannot measure anything closer than $\SI{3}{cm}$. Of course, we are also upper-bounded at $\SI{255}{cm}$ by the size of one byte, even if the limit of the ranger itself is $\SI{30 000}{\micro s} / \SI{58}{\micro s*cm^{-1}} \approx \SI{517}{cm}$. We can circumvent this by dividing the the value by $2$ in the C program then multiplying it by $2$ again in the Python program, so that the maximum measurable distance is $\SI{510}{cm}$, at the cost of decreasing the precision to a granularity of $\SI{2}{cm}$. Below is the modified \texttt{main.c} file, with the remaining files unchanged from \url{http://www.phas.ubc.ca/~michal/phys319/temperature_demo4.zip}. Of course, the axis ranges and labels of the plot should be adjusted accordingly. After the C program has been written to the microprocessor, connect P1.4 to the ranger's trigger pin, connect P1.6 to the ranger's echo pin through a $\SI{1}{k\ohm}$ resistor, connect the ranger to $\SI{5}{V}$ and ground, connect the microprocessor to ground, and run \texttt{python python-serial-plot.py}. \newpage \noindent \textit{\texttt{main.c}}: \begin{minted}{c} #include "msp430.h" #define TXD BIT2 #define RXD BIT1 #define TRIG BIT4 #define ECHO BIT6 #define CM 58 unsigned int TXByte; void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop WDT BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; BCSCTL2 &= ~(DIVS_3); // SMCLK = DCO = 1 MHz P1SEL = BIT1 + BIT2; // P1.1 = RXD, P1.2=TXD P1SEL2 = BIT1 + BIT2; // P1.1 = RXD, P1.2=TXD UCA0CTL1 |= UCSSEL_2; // Use SMCLK UCA0BR0 = 104; // Set baud rate to 9600 with 1MHz clock (Data Sheet 15.3.13) UCA0BR1 = 0; // Set baud rate to 9600 with 1MHz clock UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1 UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine P1DIR |= TXD; P1OUT |= TXD; P1DIR |= TRIG; // set trigger output P1DIR &= ~ECHO; // set echo input P1IE |= ECHO; // use echo input as interrupt TACTL = TACLR; // reset clock TACTL = TASSEL_2 | MC_2; // set SMCLK timer to count up at 1 MHz __enable_interrupt(); while (1) { P1OUT |= TRIG; // start trigger signal __delay_cycles(10); // we need a >10 us pulse and one clock cycle is 1 us P1OUT &= ~TRIG; // end trigger signal P1IES &= ~ECHO; // interrupt on low to high __bis_SR_register(LPM0_bits + GIE); TAR = 0; P1IES |= ECHO; // interrupt on high to low __bis_SR_register(LPM0_bits + GIE); TXByte = TAR / CM; // distance in cm TXByte = (TXByte <= 0xFF) * TXByte; // set to 0 if beyond range while (!(IFG2 & UCA0TXIFG)); // wait for TX buffer to be ready for new data UCA0TXBUF = TXByte; __delay_cycles(100000); // wait >10 ms before measuring again } } // handle P1.3 interrupts #if defined(__TI_COMPILER_VERSION__) #pragma vector=PORT1_VECTOR __interrupt void port1_isr(void) #else void __attribute__ ((interrupt(PORT1_VECTOR))) port1_isr (void) #endif { P1IFG = 0; // reset interrupt flag __bic_SR_register_on_exit(LPM0_bits); // take us out of low power mode } \end{minted} \noindent \textit{\texttt{serial-python-plot.py}}: \begin{minted}{python} ... ax = fig.add_subplot(111,xlabel='Time Step',ylabel='Distance (cm)') ax.set_ylim(0,255) # set limits of y axis. ... \end{minted} \end{document}