Things used in this project

Hardware components:
R8326274 01
Raspberry Pi 2 Model B
×1
Msp exp430g2 msp exp30g2
TI LaunchPad MSP-EXP430G2 MSP430 LaunchPad
×1
51gzz5eu9pl. sx425
Ultrasonic Sensor - HC-SR04 (Generic)
ultrasonic range finder
×1
28BYJ48
Stepper Motor (optional)
×1
JY-MCU
Bluetooth uart
×1
X113647
×1
11026 02
Jumper wires (generic)
×1
12002 04
Breadboard (generic)
×1
resistor 10K
×2
Software apps and online services:
10
Microsoft Windows 10 IoT Core
Vs2015logo
Microsoft Visual Studio 2015
Hand tools and fabrication machines:
Code Composer Studio

Schematics

Schematic
Launchpad bb

Code

main.cC/C++
MSP430 code for the launchpad
#include "msp430g2553.h"

#define LED1 BIT0
#define TXD BIT2
#define RXD BIT1
#define SWITCH BIT7

#define STEPPER_orange BIT1
#define STEPPER_yellow BIT2
#define STEPPER_pink BIT3
#define STEPPER_blue BIT4

#define INTERRUPT_SIGNAL BIT5

#define ULTRASONIC_INPUT 0x1
#define ULTRASONIC_OUTPUT 0x10



/*
 * main.c
 * p1.0 led indicator
 * p1.1 uart
 * p1.2 uart
 * p1.6 i2c SCL clock
 * p1.7 i2c SDA data
 * p1.3 input switch (stop/start)
 * p1.4 ultrasonic trigger
 * p2.0 ultrasonic capture timer A1
 * p2.1-p2.4 stepper 0-3 timer A0 software gpio
 * p1.5 interrupt - data ready
 */

static char tx_buffer[16] = "XXXX_XX\r";
static char i2c_tx_buffer[3] = { 0 };
static char i2c_rx_address = 0;
unsigned int tx_buffer_i = 0;
unsigned int ultrasonic_start = 0;
unsigned int ultrasonic_period = 0;
unsigned int state = 0;

char ConvertIntToAscii(unsigned int v, unsigned int offset)
{
	v >>= offset;
	v &= 0xF;
	if(v < 10)
		return v + '0';
	else
		return (v-10) + 'A';
}

#define DELAY_100ms (50000)
#define DELAY_10ms (5000)
#define DELAY_60ms (30000)
#define DELAY_1ms (500)
#define DELAY_2ms (500)
#define DELAY_100us (50)

void delayUnits(unsigned int delay)
{
	TAR = 0;
	TACCR0 = delay;
	TACCTL0 = CCIE;                         // Compare-mode interrupt.
	TACTL = TASSEL_2 | MC_1 | ID_3;         // TACLK = SMCLK, Up mode, 4Mhz / 8 = 500kHz clock
	volatile unsigned int tactl;
	do
	{
		__bis_SR_register(CPUOFF + GIE); 		// Enter LPM0
		tactl =(TACTL & MC_3);
	}while(tactl != 0);
	TACCTL0 &= ~CCIE;
}

#define STEPPER_STEP(on, off, port) ((on) | (port & ~(off)))

void StepClockwise(unsigned int delay)
{
	// step 1
	P2OUT = STEPPER_STEP(STEPPER_orange, STEPPER_yellow | STEPPER_pink | STEPPER_blue, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_orange | STEPPER_yellow, STEPPER_pink | STEPPER_blue, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_yellow, STEPPER_pink | STEPPER_blue | STEPPER_orange, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_yellow | STEPPER_pink, STEPPER_blue | STEPPER_orange, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_pink, STEPPER_blue | STEPPER_orange | STEPPER_yellow, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_pink | STEPPER_blue, STEPPER_orange | STEPPER_yellow, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_blue, STEPPER_orange | STEPPER_yellow | STEPPER_pink, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_blue | STEPPER_orange, STEPPER_yellow | STEPPER_pink, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(0, STEPPER_blue | STEPPER_orange | STEPPER_yellow | STEPPER_pink, P2OUT);
}

void StepAntiClockwise(unsigned int delay)
{
	// step 1
	P2OUT = STEPPER_STEP(STEPPER_blue, STEPPER_orange | STEPPER_yellow | STEPPER_pink, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_pink | STEPPER_blue, STEPPER_orange | STEPPER_yellow, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_pink, STEPPER_blue | STEPPER_orange | STEPPER_yellow, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_yellow | STEPPER_pink, STEPPER_blue | STEPPER_orange, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_yellow, STEPPER_pink | STEPPER_blue | STEPPER_orange, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_orange | STEPPER_yellow, STEPPER_pink | STEPPER_blue, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_orange, STEPPER_yellow | STEPPER_pink | STEPPER_blue, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(STEPPER_blue | STEPPER_orange, STEPPER_yellow | STEPPER_pink, P2OUT);
	delayUnits(delay);
	P2OUT = STEPPER_STEP(0, STEPPER_blue | STEPPER_orange | STEPPER_yellow | STEPPER_pink, P2OUT);
}

void init_I2C()
{
    // pin 1.6 and 1.7 as i2C input for scl
	P1REN &= ~0xC0;
    P1DIR &= ~0xC0;
    P1SEL |= 0xC0;
    P1SEL2 |= 0xC0;
    P1REN &= ~0xC0;

    UCB0CTL1 = UCSWRST;
    UCB0CTL0 = UCMODE_3 + UCSYNC;     		// slave mode
    UCB0I2COA = 0x48; 						// address == 0x48
    UCB0CTL1 &= ~UCSWRST;
    UC0IE |= UCB0RXIE | UCB0TXIE;
    UCB0I2CIE |= UCSTTIE;
}

void ProcessState()
{
	int j;
	if((state < 10) || (state >= 30))
	{
		for(j=16;j>0;j--)
		{
			StepClockwise(DELAY_2ms);
		}
	}
	else
	{
		for(j=16;j>0;j--)
		{
			StepAntiClockwise(DELAY_2ms);
		}
	}
	state = state + 1;
	if(state >= 40)
	{
		state = 0;
	}
}


int main(void) {
    WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer

    WDTCTL = WDTPW + WDTHOLD; // Stop WDT
    DCOCTL = 0; // Select lowest DCOx and MODx settings
    BCSCTL1 = CALBC1_16MHZ; // Set DCO
    BCSCTL2 = DIVS1; // SMCLK runs at 16/4 = 4Mhz
    DCOCTL = CALDCO_16MHZ;

    // configure uart
    P2DIR |= 0xFF; // All P2.x outputs
    P2OUT &= 0x00; // All P2.x reset
    P1SEL |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
    P1SEL2 |= RXD + TXD ; // P1.1 = RXD, P1.2=TXD
    //P1DIR |= RXLED + TXLED;
    P1OUT &= 0x00;
    UCA0CTL1 |= UCSSEL_2; // SMCLK

    // pin 1.0 as output led
    P1DIR |= LED1;
    P1SEL &= ~LED1;

    // pin 1.5 interrupt signal data ready
    P1DIR |= INTERRUPT_SIGNAL;
	P1SEL &= ~INTERRUPT_SIGNAL;
	P1SEL2 &= ~INTERRUPT_SIGNAL;
	P1OUT &= ~INTERRUPT_SIGNAL;

    // pin 1.4 as ultrasonic output trigger
    P1DIR |= ULTRASONIC_OUTPUT;
    P1OUT &= ~ULTRASONIC_OUTPUT;
    P1SEL &= ~ULTRASONIC_OUTPUT;
    P1SEL2 &= ~ULTRASONIC_OUTPUT;

    // configure switch
    P1DIR &= ~SWITCH;
    P1OUT |= SWITCH;
    P1SEL &= ~SWITCH;
    P1SEL2 &= ~SWITCH;
    P1REN |= SWITCH;

    // pin 2.0 ultrasonic input
    P2DIR &= ~ULTRASONIC_INPUT;
    P2OUT &= ~ULTRASONIC_INPUT;
    P2SEL |= ULTRASONIC_INPUT;
    P2SEL2 &= ~ULTRASONIC_INPUT;
    P2REN |= ULTRASONIC_INPUT;

    // pin 2.1-2.4 stepper
    P2DIR |= (STEPPER_orange | STEPPER_yellow | STEPPER_pink | STEPPER_blue);
    P2OUT &= ~(STEPPER_orange | STEPPER_yellow | STEPPER_pink | STEPPER_blue);
    P2REN &= ~(STEPPER_orange | STEPPER_yellow | STEPPER_pink | STEPPER_blue);
    P2SEL2 &= ~(STEPPER_orange | STEPPER_yellow | STEPPER_pink | STEPPER_blue);
    P2SEL2 &= ~(STEPPER_orange | STEPPER_yellow | STEPPER_pink | STEPPER_blue);

    // uart
    // set to 115200 baud, UCBRx = 8, UCBRSx = 0, UCBRFx=11, UCOS16 = 1
    //UCA0BR0 = 8;
    //UCA0BR1 = 0;
    //UCA0MCTL = UCBRF3 | UCBRF1 | UCBRF0 | UCOS16; // UCBRSx = 0, UCBRFx=1, UCOS16 = 1
    // set to 115200 baud, UCBRx = 2, UCBRSx = 3, UCBRFx=2, UCOS16 = 1
    UCA0BR0 = 2;
    UCA0BR1 = 0;
    UCA0MCTL = UCBRS1 | UCBRS0 | UCBRF1 | UCOS16; // UCBRSx = 0, UCBRFx=1, UCOS16 = 1
    UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**

    // ultrasonic capture
    TA1CTL = TASSEL_2 | MC_2 | ID_0; // SMCLK, up mode, clock running at 4MHz
    TA1CCTL0 = CM_3 | CCIS_0 | SCS | CAP | OUTMOD_0 | CCIE ; // capture both, CCIxA, synchronised capture, capture mode SCCI

    init_I2C();

    // enable uart interrupts
    UC0IE |= UCA0TXIE;
    UC0IE |= UCA0RXIE; // Enable USCI_A0 RX interrupt

    while (1)
    {
    	// trigger
    	P1OUT |= ULTRASONIC_OUTPUT;
    	delayUnits(DELAY_100us);
    	P1OUT &= ~ULTRASONIC_OUTPUT;

    	delayUnits(DELAY_100ms);

    	__disable_interrupt();
    	i2c_tx_buffer[0] = (ultrasonic_period >> 8);
		i2c_tx_buffer[1] = (ultrasonic_period & 0xFF);
		i2c_tx_buffer[2] = state;
		tx_buffer[0] = ConvertIntToAscii(ultrasonic_period, 12);
		tx_buffer[1] = ConvertIntToAscii(ultrasonic_period, 8);
		tx_buffer[2] = ConvertIntToAscii(ultrasonic_period, 4);
		tx_buffer[3] = ConvertIntToAscii(ultrasonic_period, 0);
		tx_buffer[5] = ConvertIntToAscii(state, 4);
		tx_buffer[6] = ConvertIntToAscii(state, 0);
		if(tx_buffer_i == 0)
			UC0IE |= UCA0TXIE;
		__enable_interrupt();

		// signal data ready
		P1OUT |= INTERRUPT_SIGNAL;
		delayUnits(DELAY_1ms);
		P1OUT &= ~INTERRUPT_SIGNAL;

    	ProcessState();
    }
}

#pragma vector=USCIAB0TX_VECTOR
__interrupt void USCI0TX_ISR(void)
{
	// uart
	if(UC0IFG & UCA0TXIFG)
	{
		char txb = tx_buffer[tx_buffer_i++]; // TX next character
		UCA0TXBUF = txb;
		txb = tx_buffer[tx_buffer_i];
		if (txb == 0) // TX over?
		{
			tx_buffer_i = 0;
			UC0IE &= ~UCA0TXIE; // Disable USCI_A0 TX interrupt
		}
	}
    // i2c
    if (UC0IFG & UCB0TXIFG)
    {
    	 UCB0TXBUF = i2c_tx_buffer[i2c_rx_address];
    	 i2c_rx_address++;
    	 if(i2c_rx_address >= 3)
    	 {
    		 i2c_rx_address = 0;
    	 }
    }
    if (UC0IFG & UCB0RXIFG)
    {
    	char rx = UCB0RXBUF;
    }
}

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void)
{
	// uart
	if(UC0IFG & UCA0RXIFG)
	{
		char rx_char = UCA0RXBUF;
		//if (rx_char == 'r') // 'r' received?
		//{
		//   tx_buffer_i = 0;
		//   UC0IE |= UCA0TXIE; // Enable USCI_A0 TX interrupt
		//}
	}
    // i2c
    if (UCB0STAT & UCSTTIFG)
    {
    	i2c_rx_address = 0;
    	UCB0STAT &= ~UCSTTIFG;
    }
    if(UCB0STAT & UCSTPIFG)
    {
    	UCB0STAT &= ~UCSTPIFG;
    }
}

#pragma vector=TIMER1_A0_VECTOR
__interrupt void TIMER1_A0_ISR(void)
{
	volatile unsigned int tacct = TA1CCTL0;
	if(tacct & COV) // overflow
	{
		// just clear it
		TA1CCTL0 &= ~COV;
	}
	if((tacct & CCI) != 0)
	{
		// start of ultrasound
		ultrasonic_start = TA1CCR0;
		P1OUT |= 1;
	}
	else
	{
		ultrasonic_period = TA1CCR0 - ultrasonic_start;
		P1OUT &= ~1;
	}
}

#pragma vector=TIMER0_A0_VECTOR
__interrupt void ta0_isr(void)
{
	TACTL &= ~MC_3;
	__bic_SR_register_on_exit(CPUOFF);
}
Driver CodeC#
C# driver code for the raspberry pi
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;
using Windows.Devices.Gpio;

namespace LaunchPadMsp430
{
    public class SonarEventArgs : EventArgs
    {
        public double Range { get; set; }
        public double Yaw { get; set; }
    }

    public partial class LaunchPadMsp430 : IDisposable
    {
        public event EventHandler<SonarEventArgs> SensorInterruptEvent;

        #region Constants

        public const byte ADDRESS = 0x48;

        #endregion

        private const Int32 INTERRUPT_PIN = 18; // GPIO_GEN1)
        I2cDevice _launchPadDevice = null;
        private GpioController IoController;
        private GpioPin InterruptPin;

        #region 12c

        private byte ReadByte(byte regAddr)
        {
            byte[] buffer = new byte[1];
            buffer[0] = regAddr;
            byte[] value = new byte[1];
            _launchPadDevice.WriteRead(buffer, value);
            return value[0];
        }

        private byte[] ReadBytes(byte regAddr, int length)
        {
            byte[] values = new byte[length];
            byte[] buffer = new byte[1];
            buffer[0] = regAddr;
            _launchPadDevice.WriteRead(buffer, values);
            return values;
        }

        void WriteByte(byte regAddr, byte data)
        {
            byte[] buffer = new byte[2];
            buffer[0] = regAddr;
            buffer[1] = data;
            _launchPadDevice.Write(buffer);
        }

        void writeBytes(byte regAddr, byte[] values)
        {
            byte[] buffer = new byte[1 + values.Length];
            buffer[0] = regAddr;
            Array.Copy(values, 0, buffer, 1, values.Length);
            _launchPadDevice.Write(buffer);
        }

        #endregion

        public async void InitHardware()
        {
            try
            {
                IoController = GpioController.GetDefault();
                InterruptPin = IoController.OpenPin(INTERRUPT_PIN);
                InterruptPin.Write(GpioPinValue.Low);
                InterruptPin.SetDriveMode(GpioPinDriveMode.Input);
                InterruptPin.ValueChanged += Interrupt;

                string aqs = I2cDevice.GetDeviceSelector();
                DeviceInformationCollection collection = await DeviceInformation.FindAllAsync(aqs);

                I2cConnectionSettings settings = new I2cConnectionSettings(ADDRESS);
                settings.BusSpeed = I2cBusSpeed.FastMode; // 400kHz clock
                settings.SharingMode = I2cSharingMode.Exclusive;
                _launchPadDevice = await I2cDevice.FromIdAsync(collection[0].Id, settings);

                await Task.Delay(100); // wait power up sequence
            }
            catch (Exception ex)
            {
                string error = ex.ToString();
            }
        }

        private void Interrupt(GpioPin sender, GpioPinValueChangedEventArgs args)
        {
            if (_launchPadDevice != null)
            {
                SonarEventArgs ea = new SonarEventArgs();
                ea.Range = 0;
                ea.Yaw = 0;
                byte[] data = ReadBytes(0x5A, 3);
                int raw = (data[0] << 8) + data[1];
                double microSeconds = raw / 4;
                ea.Range = microSeconds / 5800;
                ea.Yaw = data[2] * 5.625/64;

                if(SensorInterruptEvent != null)
                {
                    SensorInterruptEvent(this, ea);
                }
            }
        }

        #region IDisposable Support
        private bool disposedValue = false; // To detect redundant calls

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                InterruptPin.Dispose();
                if (_launchPadDevice != null)
                {
                    _launchPadDevice.Dispose();
                    _launchPadDevice = null;
                }
                disposedValue = true;

            }
        }

        ~LaunchPadMsp430()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(false);
        }

        // This code added to correctly implement the disposable pattern.
        public void Dispose()
        {
            // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion

    }
}
Main for the Raspberry PIC#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace LaunchPadMsp430
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        LaunchPadMsp430 msp430 = new LaunchPadMsp430();
        double[] value = new double[256];
        int i = 0;

        public MainPage()
        {
            this.InitializeComponent();
            msp430.InitHardware();
            msp430.SensorInterruptEvent += Msp430_SensorInterruptEvent;
        }

        private void Msp430_SensorInterruptEvent(object sender, SonarEventArgs e)
        {
            var task = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                textBlock.Text = String.Format("stats: {0} {1}", e.Range, e.Yaw);
                value[i++] = e.Range;
                if(i >= value.Length)
                {
                    double mean = 0;
                    foreach (double v in value)
                        mean += v;
                    mean /= value.Length;

                    double sd = 0;
                    foreach (double v in value)
                        sd += (v - mean) * (v - mean);

                    sd /= value.Length;
                    sd = Math.Sqrt(sd);

                    i = 0;
                }
            });
        }
    }
}

Credits

Logo 300x300
Graham Chow
14 projects • 64 followers
I'm a software developer on a long sabbatical. I've had wide experience from banking to underwater military sonar systems.
Contact

Replications

Did you replicate this project? Share it!

I made one

Love this project? Think it could be improved? Tell us what you think!

Give feedback

Comments

Add projectSign up / Login