Here is some code I put together for myself to interface with the Parallax 27911-RT 3-Axis gyroscope with a PIC16F690. I organized it in a header and source file so that it could be included within another project. It uses I2C communication, and the pins must be configured in the header file.
Here is the header file:
#ifndef GYRO_H
#define GYRO_H
/* Parallax Gyro 27911-RT
Pins:
GND -> GND
VIN -> 5V
CS -> 5V (I2C Mode)
SCL -> I2C CLK
SDA -> I2C DATA
SDO -> GND (LSB of Slave Address)
INT1 -> EMPTY
INT2 -> OPTIONAL (Data Ready Interrupt)
*/
int xen,yen,zen;
// I2C Bit Configuration
sbit Soft_I2C_Scl at RC4_bit;
sbit Soft_I2C_Scl_Direction at TRISC4_bit;
sbit Soft_I2C_Sda at RC5_bit;
sbit Soft_I2C_Sda_Direction at TRISC5_bit;
#define GYRO_WRITE_ADDRESS 0xD0
#define GYRO_READ_ADDRESS 0xD1
#define X_MSB 0x29
#define X_LSB 0x28
#define Y_MSB 0x2B
#define Y_LSB 0x2A
#define Z_MSB 0x2D
#define Z_LSB 0x2C
#define CTRL_REG1 0x20
#define CTRL_REG2 0x21
#define CTRL_REG3 0x22
#define CTRL_REG4 0x23
#define CTRL_REG5 0x24
#define FIFO_CTRL_REG 0x2E
#define WHO_AM_I 0x0F
#define TEMPERATURE 0x26
#define STATUS 0x27
void initGyro();
void writeGyro(unsigned short reg, unsigned short val);
unsigned short getGyroReg(unsigned char regAddress);
void getGyroX();
void getGyroY();
void getGyroZ();
#include "gyro.c"
#endif
Here is the source file. Note: You can comment out the TEST_MAIN if you want to add into another project.
#ifndef GYRO_C
#define GYRO_C
#define TEST_MAIN
/* Parallax Gyro 27911-RT
Pins:
GND -> GND
VIN -> 5V
CS -> 5V (I2C Mode)
SCL -> I2C CLK
SDA -> I2C DATA
SDO -> GND (LSB of Slave Address)
INT1 -> EMPTY
INT2 -> OPTIONAL (Data Ready Interrupt)
*/
#include "gyro.h"
#ifndef bit
#define bit(n) (1 << (n))
#endif
unsigned short LSB, MSB;
unsigned short ack;
int start_gyro(unsigned short id) {
int attempts;
for (attempts=0; attempts<25;attempts++) {
Soft_I2C_start();
ack=Soft_I2C_Write(id);
if(ack==0) return 1;
}
return 0;
}
void writeGyro(unsigned short reg, unsigned short val){
start_gyro(GYRO_WRITE_ADDRESS);
ack = Soft_I2C_Write(reg);
ack = Soft_I2C_Write(val);
Soft_I2C_stop();
}
unsigned short recieved;
unsigned short getGyroReg(unsigned char regAddress){
start_gyro(GYRO_WRITE_ADDRESS);
ack = Soft_I2C_Write(regAddress);
Soft_I2C_stop();
start_gyro(GYRO_READ_ADDRESS);
recieved = Soft_I2C_Read(0);
Soft_I2C_stop();
return recieved;
}
void initGyro() {
delay_ms(10); // Wait for device to completely power up
Soft_I2C_Init(); // Initiate I2C Connection
writeGyro(CTRL_REG1,0b00001111); //Turn on all axis's, turn of power down mode
writeGyro(CTRL_REG2,0b00000000); // No filtering
writeGyro(CTRL_REG3,0b00001000); // Initialize data ready interrupt on INT2
writeGyro(CTRL_REG4,0b00000000); // Little Endian
writeGyro(CTRL_REG5,0b00000000); // Disable the FIFO
writeGyro(FIFO_CTRL_REG,0b00000000);
}
void getGyroX(){
MSB = getGyroReg(X_MSB);
LSB = getGyroReg(X_LSB);
xen = ((MSB << 8) | LSB);
}
void getGyroY(){
MSB = getGyroReg(Y_MSB);
LSB = getGyroReg(Y_LSB);
yen = ((MSB << 8) | LSB);
}
void getGyroZ(){
MSB = getGyroReg(Z_MSB);
LSB = getGyroReg(Z_LSB);
zen = ((MSB << 8) | LSB);
}
#ifdef TEST_MAIN
//function for outputing string to uart
void outstr(char s[])
{
int k;
for (k = 0; s[k] != 0; k++)
Uart1_Write(s[k]);
Uart1_Write(' ');
}
char tempstring[10];
void main() {
ANSEL = ANSELH = 0;
PORTA = PORTB = PORTC = 0;
TRISA = TRISB = TRISC = 0xFF;
TRISA.F0 = 1; // So UART Tool will work with Programmer
TRISB.F4 = 0; // LED
PORTB.F4 = 1;
UART1_Init(1200);
initGyro();
while(1){
getGyroX();
IntToStr((int)xen,tempstring);
outstr(tempstring);
getGyroY();
IntToStr((int)yen,tempstring);
outstr(tempstring);
getGyroZ();
IntToStr((int)zen,tempstring);
outstr(tempstring);
UART1_Write('\n');
delay_ms(100);
}
}
#endif
#endif
Hope this can help someone. I believe the code should be pretty portable, at least across the PIC devices.