2017年
8月
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

setup diary

2007|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|06|08|11|
2015|01|02|03|04|05|06|07|08|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|07|08|09|10|11|12|
2021|01|02|03|04|05|06|07|08|09|10|11|12|
2022|01|02|03|04|05|06|07|08|09|10|11|12|
2023|01|02|03|04|05|06|07|08|09|10|11|

2017-08-02 用途限定の抵抗測定システム

_ arduino UNO用の電気抵抗測定シールド

電気抵抗を測定するシステムが不安定になっていたので、システムの更新を計画している。そのシステムは、限られた用途にしか使わないので、1ミリオーム程度から1オーム程度まで測定できれば良い。これまでは、GPIBで電源とデジボルを制御して測定していたが、抵抗の値が限定されるのであれば、安価なICを組み合わせれば、ほぼ同等のシステムを構築できるのでは無いかと考えられる。

そこで、計装アンプとADコンバーターとarduino UNOを使って、抵抗測定システムを作ることにした。仕様としては、白金抵抗温度計以外に4つの試料を同時に測定できるようにした。arduinoのピンから供給する0Vと5Vを使って、抵抗と直列に繋いだ試料に電流を流す。電流は標準抵抗にかかっている電圧から求め、それと試料にかかっている電圧から、抵抗が計算できる。熱起電力を打ち消すためには、arduinoのピンの電圧を反転させれば良い。

ADコンバーターとしては、MCP3425を用いた。このICは、プラスマイナスの電圧をそれぞれ15bitで読み取ることが出来、2/4/8倍のアンプも内蔵しているので、ダイナミックレンジは18bitと言える。温度計を測るには十分であるが、試料には5mA程度の電流を流すことにすると、電圧が小さすぎるので、計測アンプで増幅する必要がある。計装アンプはLT1167を使って200倍程度の増幅することにした。

最終的には、MCP3425を10個とLT1167を4個使って、arduinoで4つの試料を同時に測定できるシステムが完成した。測定時間も片側0.5秒ぐらいで測定しても、ノイズはそれほど大きくなかったので、1秒程度で測定ができる。まだ、試運転の段階で、本格稼働はしていないが、予定程度の性能を持つシステムができた気がする。


2017-08-26 GPIB adapter using Arduino Nano

_ 自作USB-GPIBアダプター

少し古い計測装置の多くは、GPIBをインターフェースとして用いている。GPIBボードは高いし、ドライバーを入れるのは面倒なので、これまでにいくつかのGPIBのアダプターを自作してきた。例えば、昔のプリンターポートを使ったり、AVRでシリアルから変換したりした。また、FTDIのFT232Rのbitbangモードを使えば、新しいUSB-GPIBアダプターができるという考えで設計だけして作成をしていないものもある。今回、raspberry piからGPIBを使う必要が出てきたので、USB-GPIBアダプタを作ることにした。raspberry piのGPIOを使って直接GPIBを動かすこともできる気がするが、今回はarduinoを使うことにした。コンパクトに作りたいので、arduino nanoを使うことにしたが、似たようなものを作っている人も沢山いるので、それを真似して作ったが、かなりソースもいじって、ほぼ別物になってしまったので、ここに公開しておこうと思う。 GPIBケーブルを半分に切って、配線を基盤に集合抵抗と一緒に半田付けして、nanoに繋いだ。ケーブルの端にに25mm*25*mm*45mm程度の直方体が付いたような感じの出来上がりになった。それぞれの信号は、6.8kと3.3kでそれぞれGNDと5Vに繋いてあり、inputモードにするとhighになり、outputでlowにすることができる。タイムアウトの処理も入れたし、通常の使用はこれで大丈夫だろう。本当はbinaryを転送できるようにしたいが、0x0aを命令の区切りとして使っているので、これを転送する際の処理を別に考えないといけないのが面倒で、今回はasciiだけの処理にした。arduinoのソースを載せておきます。
#include <string.h>
// GND-6.8kOhm-PIN-3.3kOhm-5V
#define DIO1  2  // GPIB 1  : I/O data bit 1
#define DIO2  4  // GPIB 2  : I/O data bit 2
#define DIO3  6  // GPIB 3  : I/O data bit 3
#define DIO4  8  // GPIB 4  : I/O data bit 4
#define DIO5  3  // GPIB 13 : I/O data bit 5
#define DIO6  5  // GPIB 14 : I/O data bit 6
#define DIO7  7  // GPIB 15 : I/O data bit 7
#define DIO8  9  // GPIB 16 : I/O data bit 8
#define EOI   11 // GPIB 5  : End Or Identify
#define REN   12 // GPIB 17 : Remote ENable
#define DAV   A0 // GPIB 6  : DAta Valid
#define NRFD  A1 // GPIB 7  : Not Ready For Data
#define NDAC  A2 // GPIB 8  : Not Data ACcepted
#define IFC   A3 // GPIB 9  : InterFace Clear
#define SRQ   A4 // GPIB 10 : Service ReQuest
#define ATN   A5 // GPIB 11 : ATteNtion
#define GPIBTIMEOUT 200000 //200ms
char com[256] = "";
char delim[3]="\r\n";
int p=0; // counter
void setup() {
  Serial.begin(115200);
  digitalWrite(DIO1, LOW); digitalWrite(DIO2, LOW);
  digitalWrite(DIO3, LOW); digitalWrite(DIO4, LOW);
  digitalWrite(DIO5, LOW); digitalWrite(DIO6, LOW);
  digitalWrite(DIO7, LOW); digitalWrite(DIO8, LOW);
  digitalWrite(EOI, LOW);  digitalWrite(REN, LOW);
  digitalWrite(DAV, LOW);  digitalWrite(NRFD, LOW);
  digitalWrite(NDAC, LOW); digitalWrite(IFC, LOW);
  digitalWrite(SRQ, LOW);  digitalWrite(ATN, LOW);
  set_num(EOI,0);   set_num(DAV,0);
  set_num(NDAC,1);  set_num(NRFD,1);
}
void loop() {
  if (Serial.available()==0){return;}
  if (0x0a != (com[p++] =Serial.read())) {return;}
  com[p]=0;
  if(com[0]<'a'){ // upper case
    com[3]=0;
         if (0 == strcmp("IFC", com)){ gpibIFC();} // InterFace Clear
    else if (0 == strcmp("SRQ", com)){ gpibSRQ();} // Service ReQuest
    else if (0 == strcmp("REN", com)){ gpibREN(1);} // Remote ENable
    else if (0 == strcmp("RDA", com)){ gpibREN(0);} // Remote DisAble
    else if (0 == strcmp("LLO", com)){ gpibCmd(0x11,"LLO");} // Local Lock Out
    else if (0 == strcmp("DCL", com)){ gpibCmd(0x14,"DCL");} // Device CLear
    else if (0 == strcmp("STA", com)){ gpibLineStatus();}
  }else{ // lower case
    p=(com[1]-'0')*10+com[2]-'0'; //address or paremeter
    if(p<0 || p>31){Serial.println("address error");p=0;return;}
         if ('c' == com[0]){gpibAdr(p,0x04,"SDC");} //c99 Selected Device Clear
    else if ('l' == com[0]){gpibAdr(p,0x01,"GTL");} //l99 Go To Local
    else if ('d' == com[0]){gpibDelim(p);} //d00-02 delimiter
    else if ('w' == com[0]){gpibTalk(p, com+3);} //w99option
    else if ('r' == com[0]){gpibListen(p, com); //r99
      Serial.print(com);
    }
  }
  p=0;
}
void gpibLineStatus(void) {
  Serial.print("ATN=");    Serial.print(set_num(ATN,0));
  Serial.print(", DAV=");  Serial.print(set_num(DAV,0));
  Serial.print(", NRFD="); Serial.print(set_num(NRFD,0));
  Serial.print(", NDAC="); Serial.print(set_num(NDAC,0));
  Serial.print(", EOI=");  Serial.print(set_num(EOI,0));
  Serial.print(", SRQ=");  Serial.print(set_num(SRQ,0));
  Serial.print(", DIO8-1=");
  Serial.print(set_num(DIO8,0)); Serial.print(set_num(DIO7,0));
  Serial.print(set_num(DIO6,0)); Serial.print(set_num(DIO5,0));
  Serial.print(set_num(DIO4,0)); Serial.print(set_num(DIO3,0));
  Serial.print(set_num(DIO2,0)); Serial.println(set_num(DIO1,0));
}
byte get_dio() {
  byte x = 0;
  bitWrite(x, 0, !set_num(DIO1,0)); bitWrite(x, 1, !set_num(DIO2,0));
  bitWrite(x, 2, !set_num(DIO3,0)); bitWrite(x, 3, !set_num(DIO4,0));
  bitWrite(x, 4, !set_num(DIO5,0)); bitWrite(x, 5, !set_num(DIO6,0));
  bitWrite(x, 6, !set_num(DIO7,0)); bitWrite(x, 7, !set_num(DIO8,0));
  return x;
}
void set_dio(byte x) {
  set_num(DIO1,bitRead(x,0)); set_num(DIO2,bitRead(x,1));
  set_num(DIO3,bitRead(x,2)); set_num(DIO4,bitRead(x,3));
  set_num(DIO5,bitRead(x,4)); set_num(DIO6,bitRead(x,5));
  set_num(DIO7,bitRead(x,6)); set_num(DIO8,bitRead(x,7));
}
boolean gpibWrite(byte data) {// true if error
  pinMode(NDAC, INPUT);
  if(gpibWait(NDAC,HIGH)){return true;} //until (LOW == NDAC)
  set_dio(data); // output data to DIO
  pinMode(NRFD, INPUT);
  if(gpibWait(NRFD,LOW)){return true;} //until (HIGH == NRFD)
  set_num(DAV,1); // validate data
  if(gpibWait(NDAC,LOW)){return true;} //until (HIGH == NDAC)
  set_num(DAV,0);
  set_dio(0);
  delayMicroseconds(30);
  return false;
}
boolean gpibRead(byte *data) {
  boolean ret;
  set_num(NRFD,0); // prepare to listen
  pinMode(DAV, INPUT);
  if(gpibWait(DAV,HIGH)){*data=0;return true;} //until (LOW == DAV)
  set_num(NRFD,1); // Ready for data
  *data = get_dio(); // read from DIO
  pinMode(EOI, INPUT);
  ret=(LOW == digitalRead(EOI)); // check EOI
  set_num(NDAC,0); // data accepted
  if(gpibWait(DAV,LOW)){*data=0;return true;} //until (HIGH == DAV)
  set_num(NDAC,1);
  return ret; // return true when EOI==LOW
}
void gpibTalk(byte addr, char *str) {
  set_num(EOI,0);
  gpibAttention();
  if(gpibWrite(0x5F)){gpibAttentionEnd();return;} // untalk
  if(gpibWrite(0x3F)){gpibAttentionEnd();return;} // unlisten
  if(gpibWrite(0x40)){gpibAttentionEnd();return;} // talker address
  if(gpibWrite(0x20+addr)){gpibAttentionEnd();return;} // listener address
  gpibAttentionEnd();
  // write string
  while (0 != *str) {
    if(0==*(str+1)){set_num(EOI,1);}
    if(gpibWrite(*(str++))){set_num(EOI,0);return;};
  }
  set_num(EOI,0);
  Serial.println("OK");
}
void gpibListen(byte addr, char *str) {
  *str=0;
  set_num(EOI,0);
  gpibAttention();
  if(gpibWrite(0x5F)){gpibAttentionEnd();return;} // untalk
  if(gpibWrite(0x3F)){gpibAttentionEnd();return;} // unlisten
  if(gpibWrite(0x40+addr)){gpibAttentionEnd();return;} // talker address
  if(gpibWrite(0x20)){gpibAttentionEnd();return;} // listener address
  set_num(NRFD,1); set_num(NDAC,1);
  delayMicroseconds(10);
  gpibAttentionEnd();
  // recieve data
  p = strlen(delim);
  do {
    if(gpibRead(str++)){*str=0;break;}
    *str=0;
  } while (strcmp(str-p, delim));
}
void gpibIFC(void) {
  set_num(IFC,1); set_num(REN,0);
  delayMicroseconds(128);
  set_num(IFC,0);
  Serial.println("IFC");
}
void gpibREN(int value) {
  set_num(REN,value);
  Serial.println("REN");
}
void gpibSRQ(void) {
  Serial.print("SRQ="); Serial.println(set_num(SRQ,0));
}
void gpibCmd(char cmd,char *str){
  gpibAttention();
  if(gpibWrite(cmd)){gpibAttentionEnd();return;}
  gpibAttentionEnd();
  Serial.println(str);
}
void gpibAdr(char addr,char cmd,char *str){
  gpibAttention();
  if(gpibWrite(0x3F)){gpibAttentionEnd();return;} // unlisten
  if(gpibWrite(0x20+addr)){gpibAttentionEnd();return;} // listener address
  if(gpibWrite(cmd)){gpibAttentionEnd();return;}
  gpibAttentionEnd();
  Serial.println(str);
}
void gpibDelim(char par){
       if(par==0){delim[0]=10,delim[1]=0;} // LF
  else if(par==1){delim[0]=13,delim[1]=0;} // CR
  else if(par==2){delim[0]=13,delim[1]=10;} // CR LF
  Serial.println("change delimiter");
}
void gpibAttention(){ // attention
  set_num(ATN,1); delayMicroseconds(20);
}
void gpibAttentionEnd(){ // end of attention
  set_num(ATN,0); delayMicroseconds(20);
}
boolean gpibWait(int ch, char hl){
  unsigned long count=GPIBTIMEOUT;
  while(hl == digitalRead(ch) && --count){delayMicroseconds(1);}
  if(count==0){Serial.println("timeout error");}
  return count==0;
}
int set_num(uint8_t ch,char num){
 if(num==0){pinMode(ch, INPUT); return digitalRead(ch);} //high
 else      {pinMode(ch, OUTPUT);return 0;} //low
}