MSP430 SPI-Master IO without interrupt
/**
* @file SPI.h
* Control's for the SPI
*/
#ifndef FILE_SPI_H
#define FILE_SPI_H
class SPI
{
public:
/**
* @brief Init for SPI
* @details
* @param void
* @return void
*/
static void _Init(void);
/**
* @brief Send data to Display
* @details
* @param unsigned char msg - Message send to Display
* @return void
*/
static void LCD_DataOut(unsigned char msg);
/**
* @brief Send data to Display
* @details Display mode must be set
* @param char* msg - Message send to Display
* @param int Length - Length of message send to Display
* @return void
*/
static void LCD_DataOut(char *msg, int Length);
/**
* @brief Send command to Display
* @details
* @param unsigned char msg - Message send to Display
* @return void
*/
static void LCD_CommOut(unsigned char msg);
private:
typedef enum {ModeIdle, ModeLCD, ModeMem} SPI_Modes;
static SPI_Modes SPI_Mode;
/**
* It configures SPI in a mode to communicate to the selected device
* @param Mode This defines the mode to configure.
*/
static void ConfigSPI(SPI_Modes Mode);
/**
* It performs data exchange via SPI for a given number of inputs and outputs
* @param TX pointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81)
* @param RX pointer to receive buffer or 0
* @param IOcount total number of receive and transmit bytes
*/
static void DoSPI_IO(char* TX, char* RX, int IOcount);
};
#############################################
/**
* @file SPI.c
* Control's for the SPI
*/
#include "SPI.h"
#include "msp430.h"
#define ArrayLength(array) (sizeof(array)/sizeof(array[0]))
/// Macro to set a bit y in variable x
#define SETB(x,y) (x |= (1 << y))
/// Macro to reset a bit y in variable x
#define CLRB(x,y) (x &= ~(1 << y))
SPI::SPI_Modes SPI::SPI_Mode;
/**
* @brief Init for SPI
* @details
* @param void
* @return void
*/
void SPI::_Init(void)
{
SPI_Mode = ModeIdle;
}
/**
* @brief Send data to Display
* @details Display mode must be set
* @param unsigned char msg - Message send to Display
* @return void
*/
void SPI::LCD_DataOut(unsigned char msg) //Data Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
SETB(P2OUT,7); //A0 = Data, A0 = 1
/* Software delay for selection line to settle */
__delay_cycles(25);
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
UCB0TXBUF = msg; // Transmit Message
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS =1
}
/**
* @brief Send data to Display
* @details Display mode must be set
* @param char* msg - Message send to Display
* @param int Length - Length of message send to Display
* @return void
*/
void SPI::LCD_DataOut(char *msg, int Length) //Data Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
SETB(P2OUT,7); //A0 = Data, A0 = 1
/* Software delay for selection line to settle */
__delay_cycles(25);
DoSPI_IO(msg, 0, Length);
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS =1
}
/**
* @brief Send command to Display
* @details Display mode must be set
* @param unsigned char msg - Message send to Display
* @return void
*/
void SPI::LCD_CommOut(unsigned char msg) //Command Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
CLRB(P2OUT,7); //A0 = Command, A0 = 0
/* Software delay for selection line to settle */
__delay_cycles(25);
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
UCB0TXBUF = msg; // Transmit Message
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS = 1
}
/**
* It configures SPI in a mode to communicate to the selected device
* @param Mode This defines the mode to configure.
*/
void SPI::ConfigSPI(SPI_Modes Mode)
{
if(SPI_Mode == Mode)
return;
switch(Mode)
{
case ModeLCD:
/*******************************************************
* USCI - SPI configuration for LCD *
*******************************************************/
UCB0CTL1 = UCSWRST; // **Reset USCI state machine**
// UCMST = Master Mode Selected
// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.
// ~UCCKPL = The inactive state is low.
// UCMSB = MSB first
// UCSYNC = Synchronous mode
// 8 bit data, 3 pin SPI
UCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;
UCB0CTL1 |= UCSSEL_2; // SMCLK clock source
UCB0BR0 |= 0x03; // SPI Clk = SMCLK / 3 = 1 MHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
break;
case ModeMem:
/*******************************************************
* USCI - SPI configuration for Memory *
*******************************************************/
UCB0CTL1 = UCSWRST; // **Reset USCI state machine**
// UCMST = Master Mode Selected
// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.
// ~UCCKPL = The inactive state is low.
// UCMSB = MSB first
// UCSYNC = Synchronous mode
// 8 bit data, 3 pin SPI
UCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;
UCB0CTL1 |= UCSSEL_2; // SMCLK clock source
UCB0BR0 |= 0x01; // SPI Clk = SMCLK / 1 = 3 MHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
break;
case ModeIdle:
default:
Mode = ModeIdle;
break;
}
SPI_Mode = Mode;
}
/**
* It performs data exchange via SPI for a given number of inputs and outputs
* @param TX pointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81)
* @param RX pointer to receive buffer or 0
* @param IOcount total number of receive and transmit bytes
*/
void SPI::DoSPI_IO(char* TX, char* RX, int IOcount)
{
volatile int dummy = 0x81;
if((TX == 0) && (RX == 0)) return;
while(IOcount > 0)
{
if(UCB0IFG & UCTXIFG)
{
if(TX == 0)
UCB0TXBUF = dummy; // dummy write
else
{
UCB0TXBUF = *TX++;
IOcount--;
}
}
if(UCB0IFG & UCRXIFG)
{
if(RX == 0)
dummy = UCB0RXBUF; // dummy read
else
{
*RX++ = UCB0RXBUF;
IOcount--;
}
}
}
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
dummy = UCB0RXBUF; // dummy read to empty any remaining data in RX buffer
}
Stepper motor controller for precise movement
/*
* IBM-PC Parallel Printer Port Data & Status Registers
* ====================================================
* 7 6 5 4 3 2 1 0 I/O Port
* +---+---+---+---+---+---+---+---+ ========
* Data | C8| C7| C6| C5| C4| C3| C2| C1| Base = 278/378/3BC Hex
* +---+---+---+---+---+---+---+---+ +---+
*/
#include<sys/io.h>
#include<unistd.h>
#include<stdlib.h>
#include<math.h> //for floor()
#include<iostream>
using namespace std;
#define BASEPORT 0x378 //SPP - Standard Parallel port base address
class stepper
{
private:
long delay; //delay betn each step
float pi; //constant
float acf, lcf; //angle and length correction factors in percentage
float r, c; // radius and circumerence of wheel
float ns;
int nfsc, nhs;
float residue;
// number of total steps, full step cycles and number of half steps
float step_rating; //number of steps per revolution
float speed; //speed of stepper in cm/sec
float l,w; //length and width of robocar
public:
stepper(float spd);
void specification();
void length2steps(float len, int& nfsc, int& nhs);//conversion
void angle2steps(float angle, int& nfsc, int& nhs);//conversion
void move(int nfsc, int nhs, int leftw, int rightw); //move
void fwd(float len); //length in cm
void bkwd(float len); //length in cm
void righturn(float degree, int degree_of_freedom); //number of degree turns
void lefturn(float degree, int degree_of_freedom); // -- do --
};
stepper:: stepper(float spd=7)
{
speed=spd;
l=18; //length of car
w=17-2; //width of car
acf=-2; //angle correction factor in percentage
lcf=-4; //angle correction factor in percentage
pi=3.14159; //costant
step_rating=200.5; //step rating
r=3.448; //radius of wheel in cm
c=2*pi*r; //circumference
residue=0;
//speed being in cm/s
delay=long(1/(step_rating/c*speed)*1000*1000); //in microsecond
}
void stepper::specification()
{
cout<<"\n\n\n\t\tF R O N T I E R\n";
cout<<"\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
cout<<"\n\n\nDesigned by: Amit Kumar Karna";
cout<<"\n\n\nMission: Vitrubio, Technozion'06 @ NIT Warangal";
cout<<"\n\n\nROBOCAR specifications...";
cout<<"\nDimensions = "<<l<<"cm x"<<w<<"cm";
cout<<"\nWheel Dia = "<<2*r<<"cm";
cout<<"\nStepper motor: 12V-0.33A \t"<<step_rating<<" steps/revolution";
cout<<"\nLength n Angle correction factors: "<<lcf<<"% & "<<acf<<"% respectively";
cout<<"\nSpeed selected : "<<speed<<"cm/sec";
cout<<"\ndelay between each step = "<<delay/1000.0<<"ms";
cout<<endl<<endl<<endl;
}
void stepper::length2steps(float len, int& nfsc, int& nhs)//conversion
{
ns=step_rating/c*len+residue;
nfsc=int(ns/4);
nhs=int(floor((ns-nfsc*4)/0.5)); //rounding
if(nhs==8) //may result after rounding
nhs=7;
residue=ns-(nfsc*4+nhs*0.5);
}
void stepper::angle2steps(float angle, int& nfsc, int& nhs)//conversion
{
float arclen=(pi*w)/360.0*angle;
length2steps(arclen, nfsc, nhs);
}
void stepper::move(int nfsc, int nhs, int leftw, int rightw) //move
{
int i;
int cnt;
outb(0x00, BASEPORT);
if(leftw==1 && rightw==1)
{
for(i=0; i<nfsc; i++)
{
outb(0x59, BASEPORT);
usleep(delay);
outb(0x6A, BASEPORT);
usleep(delay);
outb(0xA6, BASEPORT);
usleep(delay);
outb(0x95, BASEPORT);
usleep(delay);
if(i%50==0 && i!=0)
outb(0x81, BASEPORT); //one half step - as a compensation
}
//sequence after 5 i.e. 0100 is 1 for half step
//sequence after 9 i.e. 1001 is 8 for half step
for(i=0; i<1; i++) //dummy loop to use break;
{
cnt=0;
if(nhs==0)
break;
outb(0x81, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA9, BASEPORT);
if(++cnt==nhs)
break;
outb(0x28, BASEPORT);
if(++cnt==nhs)
break;
outb(0x6A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x42, BASEPORT);
if(++cnt==nhs)
break;
outb(0x56, BASEPORT);
if(++cnt==nhs)
break;
outb(0x14, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==-1 && rightw==-1)
{
for(i=0; i<nfsc; i++)
{
outb(0x95, BASEPORT);
usleep(delay);
outb(0xA6, BASEPORT);
usleep(delay);
outb(0x6A, BASEPORT);
usleep(delay);
outb(0x59, BASEPORT);
usleep(delay);
if(i%50==0 && i!=0)
outb(0x81, BASEPORT); //one half step - as a compensation
}
//sequence after 5 i.e. 0100 is 1 for half step
//sequence after 9 i.e. 1001 is 8 for half step
for(i=0; i<1; i++) //dummy loop
{
cnt=0;
if(nhs==0)
break;
outb(0x81, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA9, BASEPORT);
if(++cnt==nhs)
break;
outb(0x28, BASEPORT);
if(++cnt==nhs)
break;
outb(0x6A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x42, BASEPORT);
if(++cnt==nhs)
break;
outb(0x56, BASEPORT);
if(++cnt==nhs)
break;
outb(0x14, BASEPORT);
if(++cnt==nhs)
break;
}
}
else if(leftw==-1 && rightw==1) //left turn 2 wheels
{
for(i=0;i<nfsc;i++)
{
outb(0x99, BASEPORT);
usleep(delay);
outb(0xAA, BASEPORT);
usleep(delay);
outb(0x66, BASEPORT);
usleep(delay);
outb(0x55, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x11, BASEPORT);
if(++cnt==nhs)
break;
outb(0x99, BASEPORT);
if(++cnt==nhs)
break;
outb(0x88, BASEPORT);
if(++cnt==nhs)
break;
outb(0xAA, BASEPORT);
if(++cnt==nhs)
break;
outb(0x22, BASEPORT);
if(++cnt==nhs)
break;
outb(0x66, BASEPORT);
if(++cnt==nhs)
break;
outb(0x44, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==1 && rightw==-1) //right turn with 2 wheels
{
for(i=0;i<nfsc;i++)
{
outb(0x55, BASEPORT);
usleep(delay);
outb(0x66, BASEPORT);
usleep(delay);
outb(0xAA, BASEPORT);
usleep(delay);
outb(0x99, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x44, BASEPORT);
if(++cnt==nhs)
break;
outb(0x66, BASEPORT);
if(++cnt==nhs)
break;
outb(0x22, BASEPORT);
if(++cnt==nhs)
break;
outb(0xAA, BASEPORT);
if(++cnt==nhs)
break;
outb(0x88, BASEPORT);
if(++cnt==nhs)
break;
outb(0x99, BASEPORT);
if(++cnt==nhs)
break;
outb(0x11, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==0 && rightw==1) //left turn with one wheel
{
for(i=0;i<nfsc;i++)
{
outb(0x09, BASEPORT);
usleep(delay);
outb(0x0A, BASEPORT);
usleep(delay);
outb(0x06, BASEPORT);
usleep(delay);
outb(0x05, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x01, BASEPORT);
if(++cnt==nhs)
break;
outb(0x09, BASEPORT);
if(++cnt==nhs)
break;
outb(0x08, BASEPORT);
if(++cnt==nhs)
break;
outb(0x0A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x02, BASEPORT);
if(++cnt==nhs)
break;
outb(0x06, BASEPORT);
if(++cnt==nhs)
break;
outb(0x04, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==1 && rightw==0) //right turn with one wheel
{
for(i=0;i<nfsc;i++)
{
outb(0x50, BASEPORT);
usleep(delay);
outb(0x60, BASEPORT);
usleep(delay);
outb(0xA0, BASEPORT);
usleep(delay);
outb(0x90, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x40, BASEPORT);
if(++cnt==nhs)
break;
outb(0x60, BASEPORT);
if(++cnt==nhs)
break;
outb(0x20, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA0, BASEPORT);
if(++cnt==nhs)
break;
outb(0x80, BASEPORT);
if(++cnt==nhs)
break;
outb(0x90, BASEPORT);
if(++cnt==nhs)
break;
outb(0x10, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
outb(0x00, BASEPORT);
}
void stepper::fwd(float len=0)
{
float tlen=len;
if(len==0)
return;
tlen=tlen+tlen*lcf/100;
length2steps(tlen, nfsc, nhs);
cout<<"\nMoving forward by "<<len<<"cms... \t[\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
move(nfsc, nhs, 1, 1);//leftw=1 & rightw=1
}
void stepper::bkwd(float len=0)
{
float tlen=len;
if(len==0)
return;
tlen=tlen+tlen*lcf/100;
length2steps(tlen, nfsc, nhs);
cout<<"\nMoving backward by "<<len<<"cms... \t[\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
move(nfsc, nhs, -1, -1);//leftw=-1 & rightw=-1
}
void stepper::lefturn(float angle, int dof=2) //degree of freedom
{
float tangle=angle;
tangle=tangle*2/dof;
tangle=tangle+tangle*acf/100;
angle2steps(tangle, nfsc, nhs);
cout<<"\nTaking left turn by "<<angle<<"degrees... [\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
if(dof==1)
move(nfsc, nhs, 0, 1); //leftwheel=off, rightwheel=on
else
move(nfsc, nhs, -1, 1);
}
void stepper::righturn(float angle, int dof=2)
{
float tangle=angle;
tangle=tangle*2/dof;
tangle=tangle+tangle*acf/100;
angle2steps(tangle, nfsc, nhs);
cout<<"\nTaking right turn by "<<angle<<"degrees... [\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
if(dof==1)
move(nfsc, nhs, 1, 0); //leftwheel=on, rightwheel=off
else
move(nfsc, nhs, 1, -1);
}
main()
{
system("clear");
if(ioperm(BASEPORT,3,1))
{
cout<<"\nThe parallel port accessing error!";
exit(1);
}
float speed; //in cm/s
float len, la, ra; //in cm
float angle;
long wait=10000;
//cout<<"\nEnter speed in cm/s (eg. 10cm/s) : ";
//cin>>speed;
speed=10;
stepper sm(speed);
sm.specification();
cout<<"\nScanning the problem...";usleep(wait);
cout<<"...";usleep(wait);cout<<"...";usleep(wait);cout<<"...";cout<<"Done!";
cout<<"\n\n\nStarting the voyage...\n\n\n";
float l1=20, l2=28.284;
float a1=45, a2=90, a3=135;
int i;
for(i=0; i<3; i++)
{
sm.fwd(l1);
usleep(wait);
sm.lefturn(a3);
usleep(wait);
sm.fwd(l2);
usleep(wait);
sm.righturn(a3);
}
}
MSP430 SPI-Master IO without interrupt
/**
* @file SPI.h
* Control's for the SPI
*/
#ifndef FILE_SPI_H
#define FILE_SPI_H
class SPI
{
public:
/**
* @brief Init for SPI
* @details
* @param void
* @return void
*/
static void _Init(void);
/**
* @brief Send data to Display
* @details
* @param unsigned char msg - Message send to Display
* @return void
*/
static void LCD_DataOut(unsigned char msg);
/**
* @brief Send data to Display
* @details Display mode must be set
* @param char* msg - Message send to Display
* @param int Length - Length of message send to Display
* @return void
*/
static void LCD_DataOut(char *msg, int Length);
/**
* @brief Send command to Display
* @details
* @param unsigned char msg - Message send to Display
* @return void
*/
static void LCD_CommOut(unsigned char msg);
private:
typedef enum {ModeIdle, ModeLCD, ModeMem} SPI_Modes;
static SPI_Modes SPI_Mode;
/**
* It configures SPI in a mode to communicate to the selected device
* @param Mode This defines the mode to configure.
*/
static void ConfigSPI(SPI_Modes Mode);
/**
* It performs data exchange via SPI for a given number of inputs and outputs
* @param TX pointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81)
* @param RX pointer to receive buffer or 0
* @param IOcount total number of receive and transmit bytes
*/
static void DoSPI_IO(char* TX, char* RX, int IOcount);
};
#############################################
/**
* @file SPI.c
* Control's for the SPI
*/
#include "SPI.h"
#include "msp430.h"
#define ArrayLength(array) (sizeof(array)/sizeof(array[0]))
/// Macro to set a bit y in variable x
#define SETB(x,y) (x |= (1 << y))
/// Macro to reset a bit y in variable x
#define CLRB(x,y) (x &= ~(1 << y))
SPI::SPI_Modes SPI::SPI_Mode;
/**
* @brief Init for SPI
* @details
* @param void
* @return void
*/
void SPI::_Init(void)
{
SPI_Mode = ModeIdle;
}
/**
* @brief Send data to Display
* @details Display mode must be set
* @param unsigned char msg - Message send to Display
* @return void
*/
void SPI::LCD_DataOut(unsigned char msg) //Data Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
SETB(P2OUT,7); //A0 = Data, A0 = 1
/* Software delay for selection line to settle */
__delay_cycles(25);
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
UCB0TXBUF = msg; // Transmit Message
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS =1
}
/**
* @brief Send data to Display
* @details Display mode must be set
* @param char* msg - Message send to Display
* @param int Length - Length of message send to Display
* @return void
*/
void SPI::LCD_DataOut(char *msg, int Length) //Data Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
SETB(P2OUT,7); //A0 = Data, A0 = 1
/* Software delay for selection line to settle */
__delay_cycles(25);
DoSPI_IO(msg, 0, Length);
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS =1
}
/**
* @brief Send command to Display
* @details Display mode must be set
* @param unsigned char msg - Message send to Display
* @return void
*/
void SPI::LCD_CommOut(unsigned char msg) //Command Output Serial Interface
{
ConfigSPI(ModeLCD);
CLRB(P3OUT,4); //Chip Select = Active, CS = 0
CLRB(P2OUT,7); //A0 = Command, A0 = 0
/* Software delay for selection line to settle */
__delay_cycles(25);
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
UCB0TXBUF = msg; // Transmit Message
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
SETB(P3OUT,4); //after 1 byte, Chip Select = inactive, CS = 1
}
/**
* It configures SPI in a mode to communicate to the selected device
* @param Mode This defines the mode to configure.
*/
void SPI::ConfigSPI(SPI_Modes Mode)
{
if(SPI_Mode == Mode)
return;
switch(Mode)
{
case ModeLCD:
/*******************************************************
* USCI - SPI configuration for LCD *
*******************************************************/
UCB0CTL1 = UCSWRST; // **Reset USCI state machine**
// UCMST = Master Mode Selected
// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.
// ~UCCKPL = The inactive state is low.
// UCMSB = MSB first
// UCSYNC = Synchronous mode
// 8 bit data, 3 pin SPI
UCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;
UCB0CTL1 |= UCSSEL_2; // SMCLK clock source
UCB0BR0 |= 0x03; // SPI Clk = SMCLK / 3 = 1 MHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
break;
case ModeMem:
/*******************************************************
* USCI - SPI configuration for Memory *
*******************************************************/
UCB0CTL1 = UCSWRST; // **Reset USCI state machine**
// UCMST = Master Mode Selected
// UCCKPH = Data is captured on the first UCLK edge and changed on the following edge.
// ~UCCKPL = The inactive state is low.
// UCMSB = MSB first
// UCSYNC = Synchronous mode
// 8 bit data, 3 pin SPI
UCB0CTL0 = UCMST+UCCKPH+UCMSB+UCSYNC;
UCB0CTL1 |= UCSSEL_2; // SMCLK clock source
UCB0BR0 |= 0x01; // SPI Clk = SMCLK / 1 = 3 MHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // **Initialize USCI state machine**
break;
case ModeIdle:
default:
Mode = ModeIdle;
break;
}
SPI_Mode = Mode;
}
/**
* It performs data exchange via SPI for a given number of inputs and outputs
* @param TX pointer to transmit buffer or 0. if 0 then a dummy byte is sent (0x81)
* @param RX pointer to receive buffer or 0
* @param IOcount total number of receive and transmit bytes
*/
void SPI::DoSPI_IO(char* TX, char* RX, int IOcount)
{
volatile int dummy = 0x81;
if((TX == 0) && (RX == 0)) return;
while(IOcount > 0)
{
if(UCB0IFG & UCTXIFG)
{
if(TX == 0)
UCB0TXBUF = dummy; // dummy write
else
{
UCB0TXBUF = *TX++;
IOcount--;
}
}
if(UCB0IFG & UCRXIFG)
{
if(RX == 0)
dummy = UCB0RXBUF; // dummy read
else
{
*RX++ = UCB0RXBUF;
IOcount--;
}
}
}
while (UCBUSY & UCB0STAT); // Wait until SPI is no longer busy
dummy = UCB0RXBUF; // dummy read to empty any remaining data in RX buffer
}
Stepper motor controller for precise movement
/*
* IBM-PC Parallel Printer Port Data & Status Registers
* ====================================================
* 7 6 5 4 3 2 1 0 I/O Port
* +---+---+---+---+---+---+---+---+ ========
* Data | C8| C7| C6| C5| C4| C3| C2| C1| Base = 278/378/3BC Hex
* +---+---+---+---+---+---+---+---+ +---+
*/
#include<sys/io.h>
#include<unistd.h>
#include<stdlib.h>
#include<math.h> //for floor()
#include<iostream>
using namespace std;
#define BASEPORT 0x378 //SPP - Standard Parallel port base address
class stepper
{
private:
long delay; //delay betn each step
float pi; //constant
float acf, lcf; //angle and length correction factors in percentage
float r, c; // radius and circumerence of wheel
float ns;
int nfsc, nhs;
float residue;
// number of total steps, full step cycles and number of half steps
float step_rating; //number of steps per revolution
float speed; //speed of stepper in cm/sec
float l,w; //length and width of robocar
public:
stepper(float spd);
void specification();
void length2steps(float len, int& nfsc, int& nhs);//conversion
void angle2steps(float angle, int& nfsc, int& nhs);//conversion
void move(int nfsc, int nhs, int leftw, int rightw); //move
void fwd(float len); //length in cm
void bkwd(float len); //length in cm
void righturn(float degree, int degree_of_freedom); //number of degree turns
void lefturn(float degree, int degree_of_freedom); // -- do --
};
stepper:: stepper(float spd=7)
{
speed=spd;
l=18; //length of car
w=17-2; //width of car
acf=-2; //angle correction factor in percentage
lcf=-4; //angle correction factor in percentage
pi=3.14159; //costant
step_rating=200.5; //step rating
r=3.448; //radius of wheel in cm
c=2*pi*r; //circumference
residue=0;
//speed being in cm/s
delay=long(1/(step_rating/c*speed)*1000*1000); //in microsecond
}
void stepper::specification()
{
cout<<"\n\n\n\t\tF R O N T I E R\n";
cout<<"\t~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~";
cout<<"\n\n\nDesigned by: Amit Kumar Karna";
cout<<"\n\n\nMission: Vitrubio, Technozion'06 @ NIT Warangal";
cout<<"\n\n\nROBOCAR specifications...";
cout<<"\nDimensions = "<<l<<"cm x"<<w<<"cm";
cout<<"\nWheel Dia = "<<2*r<<"cm";
cout<<"\nStepper motor: 12V-0.33A \t"<<step_rating<<" steps/revolution";
cout<<"\nLength n Angle correction factors: "<<lcf<<"% & "<<acf<<"% respectively";
cout<<"\nSpeed selected : "<<speed<<"cm/sec";
cout<<"\ndelay between each step = "<<delay/1000.0<<"ms";
cout<<endl<<endl<<endl;
}
void stepper::length2steps(float len, int& nfsc, int& nhs)//conversion
{
ns=step_rating/c*len+residue;
nfsc=int(ns/4);
nhs=int(floor((ns-nfsc*4)/0.5)); //rounding
if(nhs==8) //may result after rounding
nhs=7;
residue=ns-(nfsc*4+nhs*0.5);
}
void stepper::angle2steps(float angle, int& nfsc, int& nhs)//conversion
{
float arclen=(pi*w)/360.0*angle;
length2steps(arclen, nfsc, nhs);
}
void stepper::move(int nfsc, int nhs, int leftw, int rightw) //move
{
int i;
int cnt;
outb(0x00, BASEPORT);
if(leftw==1 && rightw==1)
{
for(i=0; i<nfsc; i++)
{
outb(0x59, BASEPORT);
usleep(delay);
outb(0x6A, BASEPORT);
usleep(delay);
outb(0xA6, BASEPORT);
usleep(delay);
outb(0x95, BASEPORT);
usleep(delay);
if(i%50==0 && i!=0)
outb(0x81, BASEPORT); //one half step - as a compensation
}
//sequence after 5 i.e. 0100 is 1 for half step
//sequence after 9 i.e. 1001 is 8 for half step
for(i=0; i<1; i++) //dummy loop to use break;
{
cnt=0;
if(nhs==0)
break;
outb(0x81, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA9, BASEPORT);
if(++cnt==nhs)
break;
outb(0x28, BASEPORT);
if(++cnt==nhs)
break;
outb(0x6A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x42, BASEPORT);
if(++cnt==nhs)
break;
outb(0x56, BASEPORT);
if(++cnt==nhs)
break;
outb(0x14, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==-1 && rightw==-1)
{
for(i=0; i<nfsc; i++)
{
outb(0x95, BASEPORT);
usleep(delay);
outb(0xA6, BASEPORT);
usleep(delay);
outb(0x6A, BASEPORT);
usleep(delay);
outb(0x59, BASEPORT);
usleep(delay);
if(i%50==0 && i!=0)
outb(0x81, BASEPORT); //one half step - as a compensation
}
//sequence after 5 i.e. 0100 is 1 for half step
//sequence after 9 i.e. 1001 is 8 for half step
for(i=0; i<1; i++) //dummy loop
{
cnt=0;
if(nhs==0)
break;
outb(0x81, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA9, BASEPORT);
if(++cnt==nhs)
break;
outb(0x28, BASEPORT);
if(++cnt==nhs)
break;
outb(0x6A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x42, BASEPORT);
if(++cnt==nhs)
break;
outb(0x56, BASEPORT);
if(++cnt==nhs)
break;
outb(0x14, BASEPORT);
if(++cnt==nhs)
break;
}
}
else if(leftw==-1 && rightw==1) //left turn 2 wheels
{
for(i=0;i<nfsc;i++)
{
outb(0x99, BASEPORT);
usleep(delay);
outb(0xAA, BASEPORT);
usleep(delay);
outb(0x66, BASEPORT);
usleep(delay);
outb(0x55, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x11, BASEPORT);
if(++cnt==nhs)
break;
outb(0x99, BASEPORT);
if(++cnt==nhs)
break;
outb(0x88, BASEPORT);
if(++cnt==nhs)
break;
outb(0xAA, BASEPORT);
if(++cnt==nhs)
break;
outb(0x22, BASEPORT);
if(++cnt==nhs)
break;
outb(0x66, BASEPORT);
if(++cnt==nhs)
break;
outb(0x44, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==1 && rightw==-1) //right turn with 2 wheels
{
for(i=0;i<nfsc;i++)
{
outb(0x55, BASEPORT);
usleep(delay);
outb(0x66, BASEPORT);
usleep(delay);
outb(0xAA, BASEPORT);
usleep(delay);
outb(0x99, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x44, BASEPORT);
if(++cnt==nhs)
break;
outb(0x66, BASEPORT);
if(++cnt==nhs)
break;
outb(0x22, BASEPORT);
if(++cnt==nhs)
break;
outb(0xAA, BASEPORT);
if(++cnt==nhs)
break;
outb(0x88, BASEPORT);
if(++cnt==nhs)
break;
outb(0x99, BASEPORT);
if(++cnt==nhs)
break;
outb(0x11, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==0 && rightw==1) //left turn with one wheel
{
for(i=0;i<nfsc;i++)
{
outb(0x09, BASEPORT);
usleep(delay);
outb(0x0A, BASEPORT);
usleep(delay);
outb(0x06, BASEPORT);
usleep(delay);
outb(0x05, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x01, BASEPORT);
if(++cnt==nhs)
break;
outb(0x09, BASEPORT);
if(++cnt==nhs)
break;
outb(0x08, BASEPORT);
if(++cnt==nhs)
break;
outb(0x0A, BASEPORT);
if(++cnt==nhs)
break;
outb(0x02, BASEPORT);
if(++cnt==nhs)
break;
outb(0x06, BASEPORT);
if(++cnt==nhs)
break;
outb(0x04, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
else if(leftw==1 && rightw==0) //right turn with one wheel
{
for(i=0;i<nfsc;i++)
{
outb(0x50, BASEPORT);
usleep(delay);
outb(0x60, BASEPORT);
usleep(delay);
outb(0xA0, BASEPORT);
usleep(delay);
outb(0x90, BASEPORT);
usleep(delay);
}
//sequence after 5 i.e. 0100 is 1 for half step
cnt=0;
for(i=0; i<1; i++)
{
if(nhs==0)
break;
outb(0x40, BASEPORT);
if(++cnt==nhs)
break;
outb(0x60, BASEPORT);
if(++cnt==nhs)
break;
outb(0x20, BASEPORT);
if(++cnt==nhs)
break;
outb(0xA0, BASEPORT);
if(++cnt==nhs)
break;
outb(0x80, BASEPORT);
if(++cnt==nhs)
break;
outb(0x90, BASEPORT);
if(++cnt==nhs)
break;
outb(0x10, BASEPORT);
if(++cnt==nhs)
break;
//max of 7 half steps only possible
}
}
outb(0x00, BASEPORT);
}
void stepper::fwd(float len=0)
{
float tlen=len;
if(len==0)
return;
tlen=tlen+tlen*lcf/100;
length2steps(tlen, nfsc, nhs);
cout<<"\nMoving forward by "<<len<<"cms... \t[\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
move(nfsc, nhs, 1, 1);//leftw=1 & rightw=1
}
void stepper::bkwd(float len=0)
{
float tlen=len;
if(len==0)
return;
tlen=tlen+tlen*lcf/100;
length2steps(tlen, nfsc, nhs);
cout<<"\nMoving backward by "<<len<<"cms... \t[\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
move(nfsc, nhs, -1, -1);//leftw=-1 & rightw=-1
}
void stepper::lefturn(float angle, int dof=2) //degree of freedom
{
float tangle=angle;
tangle=tangle*2/dof;
tangle=tangle+tangle*acf/100;
angle2steps(tangle, nfsc, nhs);
cout<<"\nTaking left turn by "<<angle<<"degrees... [\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
if(dof==1)
move(nfsc, nhs, 0, 1); //leftwheel=off, rightwheel=on
else
move(nfsc, nhs, -1, 1);
}
void stepper::righturn(float angle, int dof=2)
{
float tangle=angle;
tangle=tangle*2/dof;
tangle=tangle+tangle*acf/100;
angle2steps(tangle, nfsc, nhs);
cout<<"\nTaking right turn by "<<angle<<"degrees... [\t"<<nfsc<<" "<<nhs<<" ]"<<endl;
if(dof==1)
move(nfsc, nhs, 1, 0); //leftwheel=on, rightwheel=off
else
move(nfsc, nhs, 1, -1);
}
main()
{
system("clear");
if(ioperm(BASEPORT,3,1))
{
cout<<"\nThe parallel port accessing error!";
exit(1);
}
float speed; //in cm/s
float len, la, ra; //in cm
float angle;
long wait=10000;
//cout<<"\nEnter speed in cm/s (eg. 10cm/s) : ";
//cin>>speed;
speed=10;
stepper sm(speed);
sm.specification();
cout<<"\nScanning the problem...";usleep(wait);
cout<<"...";usleep(wait);cout<<"...";usleep(wait);cout<<"...";cout<<"Done!";
cout<<"\n\n\nStarting the voyage...\n\n\n";
float l1=20, l2=28.284;
float a1=45, a2=90, a3=135;
int i;
for(i=0; i<3; i++)
{
sm.fwd(l1);
usleep(wait);
sm.lefturn(a3);
usleep(wait);
sm.fwd(l2);
usleep(wait);
sm.righturn(a3);
}
}