/* * rpi_iic.c - rs232 code to drive robot electronics IIC module. * modified from MD49.c * * * robot electronics rpi_iic example code for raspberry pi. * * By James Henderson, 2012, * Modified Doug Rice 2014 * * Useful documentation:- * http://en.wikibooks.org/wiki/Serial_Programming/termios * * Useful documentation about the IIC and ultrasound modules. * http://www.robot-electronics.co.uk/htm/raspberry_pi_examples.htm * * http://www.robot-electronics.co.uk/htm/usb_i2c_tech.htm * * http://www.robot-electronics.co.uk/acatalog/Ultrasonic_Rangers.html * http://www.robot-electronics.co.uk/htm/srf02tech.htm * http://www.robot-electronics.co.uk/htm/srf02techI2C.htm */ #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <termios.h> #include <errno.h> void writeBytes(int descriptor, int count); void readBytes(int descriptor, int count); void setModeIIC(int fd, char mode); void setModeIICatod(int fd, char mode); void setModeIICultraSound(int fd, char mode); int aatoint(char hi,char lo); char serialBuffer[100]; // Serial buffer sto store data for I/O int main(int argc, char **argv) { int fd; // File descriptor of port we will talk to //char *portName = "/dev/ttyAMA0"; // Name of the UART port on the Raspberry pi //char *portName = "/dev/ttyACM0"; // Name of the UART port on the Raspberry pi char *portName = "/dev/ttyUSB0"; // Name of the IIC module struct termios options; // Port options printf(" sizeof: %d aatoInt: %d", sizeof( fd ), aatoint( '1','2' ) ); fd = open(portName, O_RDWR | O_NOCTTY); // Open port for read and write not making it a controlling terminal if (fd == -1) { perror("openPort: Unable to open port "); // If open() returns an error } else { printf("\n usb iic usb open \n"); } // setModeIIC(fd, 1); // Set the mode of the MD49 to 1 tcgetattr(fd, &options); cfsetispeed(&options, B19200); // Set baud rate cfsetospeed(&options, B19200); cfmakeraw(&options); tcflush(fd, TCIFLUSH); // http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html // printf("c_cc[VMIN] %04X\n",options.c_cc[VMIN]); // printf("c_cc[VTIME] %04X\n",options.c_cc[VTIME]); options.c_cc[VMIN] = 6; // wait for atleast these CHARs options.c_cc[VTIME] = 3; // wait deci seconds. tcsetattr(fd, TCSANOW, &options); usleep(1000); // Sleep for UART to power up and set options tcflush(fd, TCIFLUSH); cfsetospeed(&options, B19200); cfmakeraw(&options); tcflush(fd, TCIFLUSH); // http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html usleep(1000); // Sleep for UART to power up and set options // displaySoftwareValue(fd); // Display the software version of the MD49 printf("\n ==================== \n"); setModeIICultraSound( fd, 1 ); usleep(100000); // Sleep for UART to power up and set options setModeIICultraSound( fd, 1 ); while(1){ setModeIICultraSound( fd, 1 ); } usleep(100000); // Sleep for UART to power up and set options close(fd); // Close port return 0; } void writeBytes(int descriptor, int count) { int cnt; if (( cnt = write(descriptor, serialBuffer, count)) == -1) { // Send data out perror("Error writing"); close(descriptor); // Close port if there is an error exit(1); } } void readBytes(int descriptor, int count) { int count_rd; if (count_rd = read(descriptor, serialBuffer, count) == -1) { // Read back data into buf[] perror("Error reading "); close(descriptor); // Close port if there is an error exit(1); } // printf(" count: %d %d ", count_rd , count ); } void setModeIIC(int fd, char mode) { int count,cp3; // serialBuffer[0] = 0x5A; serialBuffer[1] = 0x10; // Mode we wish to set serialBuffer[2] = mode ; // Mode we wish to set serialBuffer[3] = 0x00; // Mode we wish to set writeBytes(fd, 4); readBytes( fd,1); printf("%02X \n", serialBuffer[0] ); } void setModeIICatod(int fd, char mode) { setModeIIC( fd, 0x0C ); usleep(100000); // Sleep for UART to power up and set options serialBuffer[0] = 0x5A; serialBuffer[1] = 0x12; // Mode we wish to set serialBuffer[2] = 0x00; // Mode we wish to set serialBuffer[3] = 0x00; // Mode we wish to set writeBytes(fd, 4); usleep( 600000 ); readBytes( fd,8); printf( "%02X %02X %02X %02X \n", serialBuffer[0] , serialBuffer[1], serialBuffer[2], serialBuffer[3] ); } void setModeIICultraSound(int fd, char mode) { /* 82 0x52 Real Ranging Mode - Result in micro-seconds */ /* The SRF02 appears as a set of 6 registers. Location Read Write 0 Software Revision Command Register 1 Unused (reads 0x80) N/A 2 Range High Byte N/A 3 Range Low Byte N/A 4 Autotune Minimum - High Byte N/A 5 Autotune Minimum - Low Byte N/A */ /* Writing to I2C devices with a 1 byte internal address register This includes almost all I2C devices. Following the I2C_AD1 command you send the device I2C address, then the devices internal register address you want to write to and the number of bytes you're writing. The maximum number of data bytes should not exceed 64 so as not to overflow the USB-I2C's internal buffer. Primary USB-I2C command Device Address + R/W bit Device internal register Number of data bytes The data bytes Byte Type I2C_AD1 Addr+R/W Reg Byte Count Data Example 0x55 0xE0 0x00 0x01 0x51 Meaning Primary USB-I2C command SRF08 I2C address SRF08 command Reg One command byte follows Start ranging in cm This 5 byte sequence starts an SRF08 at address 0xE0 ranging. All 5 bytes should be sent to the USB-I2C in one sequence. A gap will result in the USB-I2C re-starting its internal command synchronization loop and ignoring the message. After all bytes have been received the USB-I2C performs the IC2 write operation out to the SRF08 and sends a single byte back to the PC. This returned byte will be 0x00 (zero) if the write command failed and non-zero if the write succeeded. The PC should wait for this byte to be returned (timing out after 500mS) before proceeding with the next transaction. */ /* I2C_AD1 0x55 Read/Write single or multiple bytes for 1 byte addressed devices (the majority of devices will use this one) */ int aai, aaat ; serialBuffer[0] = 0x55; // iic command to do iic serialBuffer[1] = 0xE0; // iic address serialBuffer[2] = 0x00; // device internal reg serialBuffer[3] = 0x01; // number of bytes to write serialBuffer[4] = 0x51; // 0x52 Real Ranging Mode - Result in micro-seconds writeBytes(fd, 5); readBytes( fd,1); /* if ( serialBuffer[0] == 0 ) { printf( "not ok: %02X ", serialBuffer[0] ); } */ usleep( 100000 ); // Set up the iic for a read operation. serialBuffer[0] = 0x55; // iic command to do iic serialBuffer[1] = 0xE1; // iic address serialBuffer[2] = 0x00; // device internal reg serialBuffer[3] = 0x06; // number of bytes to read writeBytes(fd, 4); readBytes( fd,6); // au.b1[0] = serialBuffer[3]; // au.b1[1] = serialBuffer[2]; aai = aatoint( serialBuffer[3], serialBuffer[2]); aaat = aatoint( serialBuffer[5], serialBuffer[4]); // printf( "ver: %02X %02X range: %04X cm %06d cm ", serialBuffer[0], serialBuffer[1], aai,aai ); // serialBuffer[2], serialBuffer[3] // printf( "AT: %04X cm %06d cm \n", aaat, aaat ); // printf( "srf08:range %06d cm, autoTune: %06d \n", aai,aaat ); // printf( "srf08: %06d cm, %06d cm \n", aaat,aai ); printf( "srf08: %06d cm, %06d cm %0*d+\n", aaat,aai,(int)(aai/4),1 ); } int aatoint(char hi,char lo){ union ua{ int i; char a[2]; // lo-hi } u; if ( sizeof( u.i ) == 4 ) { u.a[0]=hi; u.a[1]=lo; u.a[2]=0; u.a[3]=0; } else { printf( "sizeof( int ) != 4 - needs little enden numbers\n" ); exit(1); } return u.i; } /* END */