Serial ADC-16

Post your Linux discussions here
Post Reply
Wipster
User
User
Posts: 3
Joined: Fri Oct 02, 2009 3:24 pm

Serial ADC-16

Post by Wipster »

Hi,

I am a linux user with an ADC-16 and I have a query about what I can and cannot do, and what I can and cannot post. I see there is a linux server application available where you read off that programs memory to get the results from the adc but for me this approach seems a bit hacks. Am I allowed to write my own program to open more of the functionality (ie full 8bit - 16bit) and get the results from the datalogger? and if so can I post the source here for anyone interested?

I have noticed that the specs of how to communicate is defined in the datasheet so does this mean I am fine?

Thanks and best regards,
Wip

ziko
Advanced User
Advanced User
Posts: 1705
Joined: Fri Dec 01, 2006 10:03 am
Location: St Neots

Post by ziko »

Hi there are two ways to access the ADC16, either via the serial port as a normal RS232 device using no drivers. Or you can use the drivers we provide, if you go to our software download page you will find some Linux drivers also available.

The user manual will give you information on both the serial protocol and the function calls if you choose to use the drivers.

Kind regards
Ziko

Technical Specialist

Wipster
User
User
Posts: 3
Joined: Fri Oct 02, 2009 3:24 pm

Post by Wipster »

Thanks ziko

I have made my own, however I have run into a confusing issue. I am running my channels in differential mode, do both inputs have to be below 2.5V to give an accurate difference or does the difference just have to be less then 2.5V?
The reason for asking this is I have differing results in linux windows and on my volt meter.
I have checked with my driver and your driver in linux and they get the same results (330mv ish) however picolog in windows gets 190mv ish, despite the fact all are sending the same request bytes.
And just to mix it up my volt meter which is usualy spoton with single ended readings in windows and linux, reports 210mv diference.

Best regards,
Wip

Wipster
User
User
Posts: 3
Joined: Fri Oct 02, 2009 3:24 pm

Post by Wipster »

Anyone seen this issue with their ADC-16 or other device?

ziko
Advanced User
Advanced User
Posts: 1705
Joined: Fri Dec 01, 2006 10:03 am
Location: St Neots

Re: Serial ADC-16

Post by ziko »

Hi Wipster,

Sorry for the delay, forums were going through some modifications recently and I am just catching up.

The difference can be 5V there is a CMMR that you have to take into account, and it looks to me that as long as you do not exceed either +/-3.5V you should be ok.

Also are you using the Linux driver or are you communicating with the device using the serial protocol?

What are your input voltages?

Kind regards
Ziko

Technical Specialist

Wipster
User
User
Posts: 3
Joined: Fri Oct 02, 2009 3:24 pm

Re: Serial ADC-16

Post by Wipster »

Hi,

I was comparing the readings from picolog in windows and the linux driver and the serial implementation I wrote. Both linux readings where the same but the windows one was different.
The voltage inputs where higher then the picolog can read in reference to ground, probably around the 5-6v mark if I remember correctly but only had a small difference between them.
It might be an issue with power from the port with the higher voltages it was comparing, it was two different laptops one linux and one windows.

For those of you who are interested bellow is my serial code, it uses one thread to read the datalogger as fast as possible and the main thread to output from the register. Its a bit crude but works and was my first experiment with threads.

Code: Select all

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct {
	int *results, *chanres;
	char *chanmode;
	char model, version;
} container;

int open_link(int fd) {
	
	int status, bits;
	struct termios options;
	char buf[3];

	fcntl(fd, F_SETFL, 0);
	tcgetattr(fd, &options);
	// Get attributes

	cfsetispeed(&options, B9600);
	cfsetospeed(&options, B9600);		

	options.c_cflag |= (CLOCAL | CREAD);
	options.c_cflag &= ~PARENB;
	options.c_cflag &= ~CSTOPB;
	options.c_cflag &= ~CSIZE;
	options.c_cflag |= CS8;
	options.c_cflag &= ~CRTSCTS;

	//options.c_lflag &= ~(ICANON | ECHO | ISIG);

	options.c_lflag = 0;

	options.c_iflag = 0;
	options.c_oflag = 0;

	options.c_cc[VTIME] = 6;
	options.c_cc[VMIN] = 3;
	// Generated Attributes

	tcflush(fd, TCIFLUSH);
	tcsetattr(fd, TCSANOW, &options);
	// Flush things and set the attribs

	ioctl(fd, TIOCMGET, &status);
	// Get Status	

	status |= TIOCM_RTS;
	status &= ~TIOCM_DTR;
	ioctl(fd, TIOCMSET, &status);
	// Set RTS high and DTR low

	sleep(2); 	

	bits=read(fd,&buf,sizeof(buf));
	if ((buf[0] != 0x2B) || (bits != 3)) {
		return -1;
	}

	return 0;
}

int get_channel(int fd,
		int *voltage,
		unsigned char channel,
		unsigned char res,
		unsigned char single) {

	union {
		struct {
			unsigned char lbyte;
			unsigned char hbyte;
		} bytes;
	unsigned int returned;
	} numbers;

	unsigned char request;
	unsigned char buf[3]="";
	int bits;

	request = (channel) << 5; //Generate the channel

	request |= (res-1) << 1; //Resolution for that channel

	request |= (single); // If the channel is single ended

	write(fd, &request, 1);
	

	bits=read(fd,&buf,sizeof(buf));
	if (bits != 3) {
		return -1;
	}

	numbers.bytes.hbyte = buf[1];
	numbers.bytes.lbyte = buf[2];
	
	if (buf[0] == 0x2B) {
		(*voltage) = (numbers.returned*2500)/(pow(2,res)-1); // Positive number, do the adc math
	}	
	else {
		(*voltage) = 0-(numbers.returned*2500)/(pow(2,res)-1);	// Negative number, "
	}

return 0;
}

void *picoreader(void *args) {
	int i, fd, req;
	char buf[2];
	container *params =(container*)args;

	fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY);
	if (fd == -1) {
		printf("Unable to open /dev/ttyS0\n");
	}

	fcntl(fd, F_SETFL, 0);
	
	if (open_link(fd) == -1) {
		printf("Opening link failed\n");
	}

	req=0x01;

	write(fd, &req, 1);
	read(fd, &buf, sizeof(buf));

	params->model=buf[0];
	params->version=buf[1];

	while(1) {
		for (i=0; i<8; i++) {
			switch (params->chanmode[i]) {
				case 'S':
					get_channel(fd, &params->results[i], i, params->chanres[i], 1);
					break;
				case 'D':
					get_channel(fd, &params->results[i], i, params->chanres[i], 0);
					break;
				default:
					break;
			}
		}
	}

	close(fd);
	printf("Port closed\n");
}

void initparams(container *params) {
	params->results=(int*)malloc(sizeof(int) * 8);
	memset(params->results, 0, sizeof(int) * 8);

	params->chanres=(int*)malloc(sizeof(int) * 8);
	memset(params->chanres, 16, sizeof(int) * 8);

	params->chanmode=(char*)malloc(sizeof(char) * 8);
	memset(params->chanmode, '-', sizeof(char) * 8);

	params->model=0;
	params->version=0;
}

int main (void) {

	int i;	
	container params;
	pthread_t thread1;

	initparams(&params);	

	params.chanmode[0]='D'; //For testing perposes, set the first channel to difference mode (options are S for single end and D)
	
	printf("Starting\n");
	pthread_create(&thread1, NULL, picoreader, &params); // Spawn picoreader on a new thread and pass it the address of the results var

	sleep(8); // Sleep so the thread can stabilise and get first data. This could be replaced with a ready flag from the other thread.
	printf("Started\n");	

	printf("ADC-%i, Version:%i\n", params.model, params.version);

	while(1) {
		for (i=0; i<8; i++) {
			printf("%i ", params.results[i]); // Print what is in the variable
		}
		printf("\n");	
		sleep(1);
	}

	return 0;
}

Post Reply