Debian編
前記事
で、Arduino nanoが使えるという話を書きましたが、センサーADT7410の出力を捉えて、日変化を記録しようとする試みです。Debianが動いてるマシンですが、ここにはArduino IDEはインストールしていません。一旦WindowsサイドのPCのArduino IDEからスケッチをコンパイルして、動作していれば、そのArduino nanoをUSB-I/F的に一旦切り離し、今度はDebianなマシンに接続してもちゃんとスケッチはResumeする。しかもArduino nanoの出力はシリアルポート経由で受け取れるというのがポイントです。結構便利かな?Debianマシンが直接I2Cを話さなくても、間に入れたAruduino nano経由でI2Cのセンサーが使えるということです。
さてまず接続してみましょうかね。Debian側から認識されるはずですね。システムコンソールを凝視していなくても、dmesg -Tでおけです。認識してるあたりは、
[金 7月 3 08:46:08 2026] usb 6-1: new full-speed USB device number 2 using uhci_hcd
[金 7月 3 08:46:08 2026] usb 6-1: New USB device found, idVendor=1a86, idProduct=7523, bcdDevice= 2.54
[金 7月 3 08:46:08 2026] usb 6-1: New USB device strings: Mfr=0, Product=2, SerialNumber=0
[金 7月 3 08:46:08 2026] usb 6-1: Product: USB2.0-Serial
[金 7月 3 08:46:09 2026] usbcore: registered new interface driver usbserial_generic
[金 7月 3 08:46:09 2026] usbserial: USB Serial support registered for generic
[金 7月 3 08:46:09 2026] usbcore: registered new interface driver ch341
[金 7月 3 08:46:09 2026] usbserial: USB Serial support registered for ch341-uart
[金 7月 3 08:46:09 2026] ch341 6-1:1.0: ch341-uart converter detected
[金 7月 3 08:46:09 2026] usb 6-1: ch341-uart converter now attached to ttyUSB0
/dev/ttyUSB0としてアクセスできるということですね。
シリアルデバイスは、cuとかscreenで読み取れます。筆者の環境では双方ともにinstallする必要がありました。といっても、screenは常用していますから、cuのみ新たにinstallしたのでした。
root@debianalt:~# cu -s 9600 -l /dev/ttyUSB0
cu: open (/dev/ttyUSB0): Permission denied
cu: /dev/ttyUSB0: Line in use
rootなんですけど…..。screenを試してみます。
root@debianalt:~# screen /dev/ttyUSB0 9600
25.7500
25.7500
25.6875
25.6875
25.6875
25.6875
25.6875
25.6875
25.7500
25.6875
25.6875
25.6875
25.6875
25.6875
25.6875
25.7500
25.6875
25.6875
動作してますね。cuでなんとかしたいわけですが、/dev/ttyUSB0のパーミッションの問題だろうということで、
chmod 666 /dev/ttyUSB0
します。で、
root@debianalt:~# cu -s 9600 -l /dev/ttyUSB0
Connected.
25.6250
25.6250
25.6250
25.6250
25.6250
25.6250
25.6250
25.6875
25.6250
25.6250
25.6250
25.6875
25.6250
25.6875
動いていますね。切断するのは、”~.”を入れます。
cu -s 9600 -l /dev/ttyUSB0
Connected.
25.6250
25.6250
25.6250
25.6250
25.6250
25.6250
~25.6250
.
Disconnected.
“~.”を入れる間に”25.6250″という出力が混ざりました。screenの場合は、ctrl-A Kです。
bashスクリプトで温度データを1個(以上)取得して戻るということをやりたいわけですが、”cu”ないし”screen”ではやりにくいので、C++でプログラム作ります。え、ほんと?って、Copilot様にお願いすれば、テキトーな例を提示してくれます。それが、
#include <iostream>
#include <string>
#include <fcntl.h> // open()
#include <termios.h> // termios, tcgetattr(), tcsetattr()
#include <unistd.h> // read(), write(), close()
#include <cstring> // memset()
#include <errno.h> // errno
// Function to configure the serial port
bool configureSerialPort(int fd, speed_t baudRate) {
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
std::cerr << "Error getting terminal attributes: " << strerror(errno) << "\n";
return false;
}
// Set baud rate
cfsetospeed(&tty, baudRate);
cfsetispeed(&tty, baudRate);
// Configure 8N1 (8 data bits, no parity, 1 stop bit)
tty.c_cflag &= ~PARENB; // No parity
tty.c_cflag &= ~CSTOPB; // 1 stop bit
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; // 8 bits per byte
tty.c_cflag &= ~CRTSCTS; // No hardware flow control
tty.c_cflag |= CREAD | CLOCAL; // Enable receiver, ignore modem control lines
// Raw input mode (no processing)
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // No software flow control
tty.c_oflag &= ~OPOST; // Raw output
// Set read timeout
tty.c_cc[VMIN] = 0; // Minimum number of characters to read
tty.c_cc[VTIME] = 10; // Timeout in deciseconds (1s)
// Apply settings
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
std::cerr << "Error setting terminal attributes: " << strerror(errno) << "\n";
return false;
}
return true;
}
int main() {
const char* portName = "/dev/ttyUSB0"; // Change to your serial port
int fd = open(portName, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
std::cerr << "Error opening " << portName << ": " << strerror(errno) << "\n";
return 1;
}
// Configure the serial port
if (!configureSerialPort(fd, B9600)) { // Baud rate: 9600
close(fd);
return 1;
}
// Example: Write data
std::string outData = "Hello Serial\n";
int bytesWritten = write(fd, outData.c_str(), outData.size());
if (bytesWritten < 0) {
std::cerr << "Error writing to serial port: " << strerror(errno) << "\n";
} else {
std::cout << "Sent: " << outData;
}
// Example: Read data
char buffer[256];
int bytesRead = read(fd, buffer, sizeof(buffer) - 1);
if (bytesRead > 0) {
buffer[bytesRead] = '\0'; // Null-terminate
std::cout << "Received: " << buffer << "\n";
} else if (bytesRead == 0) {
std::cout << "No data received (timeout)\n";
} else {
std::cerr << "Error reading from serial port: " << strerror(errno) << "\n";
}
close(fd);
return 0;
}
なんとも都合のいいことに、デバイスは”/dev/ttyUSB0″で、ボーレートは9600というラッキー。なので、ほぼそのまま動かせますね。上記コードが”sample.cpp”というfileならば、
g++ -o sample sample.cpp
でbuildできます。g++はGnu C++コンパイラです。Cコンパイラはgccです。動かすと、
nao@ghost:~$ ./sample
Sent: Hello Serial
Received: 25.9375
25.9375
25.9375
25.9375
25.93
ソースコードを読めばお分かりのように、256バイトのレシーブバッファが満杯になるまで/dev/ttyUSB0から読み出して、それを文字列として出力するというものです。受信の前に”Hello Serial”という文字列を送っていますが、無視されてるので、ここは削除。また1個のデータを抜き出すためのルーチンを作って足したものが、
cat ext.cpp
#include <iostream>
#include <string>
#include <fcntl.h> // open()
#include <termios.h> // termios, tcgetattr(), tcsetattr()
#include <unistd.h> // read(), write(), close()
#include <cstring> // memset()
#include <errno.h> // errno
// Function to configure the serial port
bool configureSerialPort(int fd, speed_t baudRate) {
struct termios tty;
if (tcgetattr(fd, &tty) != 0) {
std::cerr << "Error getting terminal attributes: " << strerror(errno) << "\n";
return false;
}
// Set baud rate
cfsetospeed(&tty, baudRate);
cfsetispeed(&tty, baudRate);
// Configure 8N1 (8 data bits, no parity, 1 stop bit)
tty.c_cflag &= ~PARENB; // No parity
tty.c_cflag &= ~CSTOPB; // 1 stop bit
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; // 8 bits per byte
tty.c_cflag &= ~CRTSCTS; // No hardware flow control
tty.c_cflag |= CREAD | CLOCAL; // Enable receiver, ignore modem control lines
// Raw input mode (no processing)
tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // No software flow control
tty.c_oflag &= ~OPOST; // Raw output
// Set read timeout
tty.c_cc[VMIN] = 0; // Minimum number of characters to read
tty.c_cc[VTIME] = 10; // Timeout in deciseconds (1s)
// Apply settings
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
std::cerr << "Error setting terminal attributes: " << strerror(errno) << "\n";
return false;
}
return true;
}
char* extract(char* input)
{
char delimiter[] = "\n\n";
char *start,*end;
start = strstr(input,delimiter);
start += 2; // skip \n\n
end = strstr(start,delimiter);
if( end )
*end = '\0';
else
return nullptr;
return start;
}
int main() {
const char* portName = "/dev/ttyUSB0"; // Change to your serial port
int fd = open(portName, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
std::cerr << "Error opening " << portName << ": " << strerror(errno) << "\n";
return 1;
}
// Configure the serial port
if (!configureSerialPort(fd, B9600)) { // Baud rate: 9600
close(fd);
return 1;
}
// Example: Write data
/*
std::string outData = "Hello Serial\n";
int bytesWritten = write(fd, outData.c_str(), outData.size());
if (bytesWritten < 0) {
std::cerr << "Error writing to serial port: " << strerror(errno) << "\n";
} else {
std::cout << "Sent: " << outData;
}
*/
// Example: Read data
char buffer[256];
char* extdata;
int bytesRead = read(fd, buffer, sizeof(buffer) - 1);
if (bytesRead > 0) {
buffer[bytesRead] = '\0'; // Null-terminate
// std::cout << "Received: " << buffer << "\n";
extdata = extract(buffer);
std::cout << extdata << "\n";
} else if (bytesRead == 0) {
std::cout << "No data received (timeout)\n";
} else {
std::cerr << "Error reading from serial port: " << strerror(errno) << "\n";
}
close(fd);
return 0;
}
これを動かすと、
./ext
25.9375
のように温度データ1個だけが得られます。これに日付を足して、ログに書き加えていけばよさそうですね。具体的なスクリプトや、記録結果は別記事で。1日の変化が出ればいいんだけど。



コメント