Pages: [1]   Go Down
Author Topic: servo interference with SPI  (Read 229 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

So for a project I am working on I am using sensor to control a servo. The sensor's data is read using SPI. Currently I am able to get the servo and the sensor to run independently. My problem is getting them to run together in the same sketch, even if they are running independently. After the first instance I attach the servo, the sensor data maxes out. I looked with an oscilloscope and saw that the SPI output is always high after I attach a servo, detaching does not help either.

I was wondering if anyone had any ideas, reference material I could look through, or any similar experiences.

Thanks

Code:
// include library:
#include <SPI.h>
#include <LiquidCrystal.h>
#include <Servo.h>

// generate a MCKL signal pin
const int clock = 9;
LiquidCrystal lcd(7,6,5,4,3,2);//8,6,5,4,3,2);
Servo myservo;

//the present depth of the sensor in meters
int present_depth = 0;
//the density of water in kilograms/(meters^3)
int density = 1.275; //freshwater = 1000, saltwater = 1020-1029, air = 1.275
//gravity in meters/(seconds^2)
int gravity = 9.81;
//the desired depth for trolling in meters, this value should be set by the user
int desired_depth = 10;

void resetsensor() //this function keeps the sketch a little shorter
{
  SPI.setDataMode(SPI_MODE0);
  SPI.transfer(0x15);
  SPI.transfer(0x55);
  SPI.transfer(0x40);
}

int servo_left(int x) // this function turns the servo left to 45 degrees
{
  Serial.print("servo_left running for: ");
  Serial.println(x);
  //the servo is connected to pin A0; servo calibrated for 90 degrees
  delay(1000);
  myservo.attach(14);
  delay(100);
  myservo.write(0);
  delay(x);
  myservo.detach();
  delay(100);
}

void setup() {
  //serial prints to the serial port window
  Serial.begin(9600);
  Serial.println("Display_Sensor_Readings Running!!");
  
  //SPI setup
  SPI.begin(); //start the SPI library
  SPI.setBitOrder(MSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV32); //divide 16 MHz to communicate on 500 kHz
  pinMode(clock, OUTPUT);
  delay(100);
  
  // Start LCD*******
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("Starting");  
  
  delay(1000); // give sensor/servo time to set up
  lcd.clear();
}

void loop()
{      
  TCCR1B = (TCCR1B & 0xF8) | 1 ; //generates the MCKL signal
  analogWrite(clock, 128) ;

  resetsensor();//resets the sensor - caution: afterwards mode = SPI_MODE0!

  //Calibration word 1
  unsigned int result1 = 0;
  unsigned int inbyte1 = 0;
  SPI.transfer(0x1D); //send first byte of command to get calibration word 1
  SPI.transfer(0x50); //send second byte of command to get calibration word 1
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  result1 = SPI.transfer(0x00); //send dummy byte to read first byte of word
  result1 = result1 << 8; //shift returned byte
  inbyte1 = SPI.transfer(0x00); //send dummy byte to read second byte of word
  result1 = result1 | inbyte1; //combine first and second byte of word
  Serial.print("Calibration word 1 = ");
  Serial.println(result1);

  resetsensor();//resets the sensor

  //Calibration word 2; see comments on calibration word 1
  unsigned int result2 = 0;
  byte inbyte2 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0x60);
  SPI.setDataMode(SPI_MODE1);
  result2 = SPI.transfer(0x00);
  result2 = result2 <<8;
  inbyte2 = SPI.transfer(0x00);
  result2 = result2 | inbyte2;
  Serial.print("Calibration word 2 = ");
  Serial.println(result2);  

  resetsensor();//resets the sensor

  //Calibration word 3; see comments on calibration word 1
  unsigned int result3 = 0;
  byte inbyte3 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0x90);
  SPI.setDataMode(SPI_MODE1);
  result3 = SPI.transfer(0x00);
  result3 = result3 <<8;
  inbyte3 = SPI.transfer(0x00);
  result3 = result3 | inbyte3;
  Serial.print("Calibration word 3 = ");
  Serial.println(result3);  

  resetsensor();//resets the sensor

  //Calibration word 4; see comments on calibration word 1
  unsigned int result4 = 0;
  byte inbyte4 = 0;
  SPI.transfer(0x1D);
  SPI.transfer(0xA0);
  SPI.setDataMode(SPI_MODE1);
  result4 = SPI.transfer(0x00);
  result4 = result4 <<8;
  inbyte4 = SPI.transfer(0x00);
  result4 = result4 | inbyte4;
  Serial.print("Calibration word 4 = ");
  Serial.println(result4);
    
  //now we do some bitshifting to extract the calibration factors
  //out of the calibration words; read datasheet AN510 for better understanding
  long c1 = result1 >> 3 & 0x1FFF;
  long c2 = ((result1 & 0x07) << 10) | ((result2 >> 6) & 0x03FF);
  long c3 = (result3 >> 6) & 0x03FF;
  long c4 = (result4 >> 7) & 0x07FF;
  long c5 = ((result2 & 0x003F) << 6) | (result3 & 0x003F);
  long c6 = result4 & 0x007F;

  resetsensor();//resets the sensor

  //Temperature:
  unsigned int tempMSB = 0; //first byte of value
  unsigned int tempLSB = 0; //last byte of value
  //unsigned int D2 = 0;
  SPI.transfer(0x0F); //send first byte of command to get temperature value
  SPI.transfer(0x20); //send second byte of command to get temperature value
  delay(35); //wait for conversion end
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  tempMSB = SPI.transfer(0x00); //send dummy byte to read first byte of value
  tempMSB = tempMSB << 8; //shift first byte
  tempLSB = SPI.transfer(0x00); //send dummy byte to read second byte of value
  D2 = tempMSB | tempLSB; //combine first and second byte of value
  Serial.print("Temperature raw = ");
  Serial.println(D2); //voilá!

  resetsensor();//resets the sensor
  
  //Pressure:
  unsigned int presMSB = 0; //first byte of value
  unsigned int presLSB = 0; //last byte of value
  //unsigned int D1 = 0;
  SPI.transfer(0x0F); //send first byte of command to get pressure value
  SPI.transfer(0x40); //send second byte of command to get pressure value
  delay(35); //wait for conversion end
  SPI.setDataMode(SPI_MODE1); //change mode in order to listen
  presMSB = SPI.transfer(0x00); //send dummy byte to read first byte of value
  presMSB = presMSB << 8; //shift first byte
  presLSB = SPI.transfer(0x00); //send dummy byte to read second byte of value
  D1 = presMSB | presLSB; //combine first and second byte of value
  Serial.print("Pressure raw = ");
  Serial.println(D1);
 
  //calculation of the real values by means of the calibration factors and the maths
  //in the datasheet. const MUST be long
  const long UT1 = (c5 << 3) + 10000;
  const long dT = D2 - UT1;
  const long TEMP = 200 + ((dT * (c6 + 100)) >> 11);
  const long OFF  = c2 + (((c4 - 250) * dT) >> 12) + 10000;
  const long SENS = (c1/2) + (((c3 + 200) * dT) >> 13) + 3000;
  long PCOMP = (SENS * (D1 - OFF) >> 12) + 1000;
  float TEMPREAL = TEMP/10;
  
  //prints the pressure in mbar to the serial port
  Serial.print("Compensated pressure in mbar = ");
  Serial.println(PCOMP);
  //prints the pressure in psi to the lcd
  lcd.setCursor(0,0);
  lcd.print("P: "); //Pressure
  lcd.print(PCOMP*0.0145037738);
  lcd.print(" psi");
    
  //pressure is converted from mbar to Pa, and the present depth of the sensor is calculated in meters
  present_depth = (PCOMP * 100) / (density * gravity);// ((Pressure/0.0145037738)*100)/(1000*9.81)
  //present_depth = (pow((14.6959 / (PCOMP*0.0145037738)), (1 / 5.257)) - 1) * (TEMP + 273.15) / 0.0065; // abose sea level

  //prints tge present depth in meters to the serial port
  Serial.print("Present Depth in m = ");
  Serial.println(present_depth);
  //prints the present depth in meters to the lcd. Temp needs to be commented out.
  lcd.setCursor(0,1);
  lcd.print("Depth: ");
  lcd.print(present_depth);
  lcd.print(" m");
  
  //prints the temperature in degrees celsius to the serial port
  Serial.print("Real Temperature in °C = ");
  Serial.println(TEMPREAL);
  //prints the temperature in degrees celsius to the lcd
  
  servo_left(125);
  
  delay(1000);
}
Logged

Offline Offline
Edison Member
*
Karma: 36
Posts: 1213
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the Servo library uses TIMER1, why do you write to a register of TIMER1 ?

You run servo_left in the loop(), and you attach and detach it every time.
Normally the attach is done only once in the setup() function. Perhaps for some power saving the detach can be used, but not every servo motor likes that.

You have to power the servo motor with a seperate power supply. The Arduino board can not supply enough current. When a servo motor starts turning, it might request a peak of 500mA, or even up to 1A. That causes a voltage drop, and that might cause sensors to stop working.
Logged

0
Online Online
Shannon Member
****
Karma: 162
Posts: 10460
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Servo library definitely uses timer1 - this means that pins 9 and 10 are not
available for PWM on the Uno so you cannot use pin 9 for clock....
Logged

[ I won't respond to messages, use the forum please ]

Pages: [1]   Go Up
Jump to: