직렬 구현을 테스트하고 있는데 직렬 포트를 열면 (Arduino가 나침반 데이터 줄을 뱉어냅니다.) 때때로 처음에 0이 표시됩니다. 나는 이것이 이전의 남은 데이터라고 생각했지만 그렇지 않은 것 같습니다 (flushing IO는 도움이되지 않는 것 같습니다)
이것은 C로 작성된 프로그래밍 언어 직렬 구현이며 Linux에서 테스트하고 있지만 Windows에서도 비슷한 결과를 얻었습니다.
strace
출력은 제 1 판독에를 나타낸다 :
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 34815) = 1544
write(1, "== ", 3== ) = 3
write(1, "#{\n00000000000000000000000000000"..., 503#{
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000583A20353333202020593A20313020
20205A3A2033313920202058733A2033393520202059733A203136312020205A
733A20323933202020483A20302E3436202020413A...) = 503
포트가 닫히기 직전, 열린 후 및 설정된 속성 뒤에이 데이터를 지우려면 다음 줄을 추가하려고했습니다.
tcflush(ttyfd, TCIOFLUSH);
하지만이 문제에 도움이되지 않는 것 같습니다. 이것을 정리하는 방법에 대해 생각하십니까?
코드는 대규모 프로젝트에서 가져온 것이며 아래 관련 부분 중 일부를 수집했습니다. 변수는 표시되지 않아도 선언되지만 충분히 명확해야합니다.
포트 열기 :
ttyfd = open(&devpath[0], O_RDWR | O_NOCTTY | O_NONBLOCK); // ttyUSB0 in this case
설정 변경 :
if (speeds[n] == 0) speed = B115200; // invalid, use default
cfsetospeed (&attr, speed);
cfsetispeed (&attr, speed);
// C-flags - control modes:
attr.c_cflag |= CREAD | CS8 | CLOCAL;
// L-flags - local modes:
attr.c_lflag = 0; // raw, not ICANON
// I-flags - input modes:
attr.c_iflag |= IGNPAR;
// O-flags - output modes:
attr.c_oflag = 0;
// Control characters:
// device is non-blocking (polled for changes):
attr.c_cc[VMIN] = 0;
attr.c_cc[VTIME] = 0;
// Make sure OS queues are empty:
tcflush(ttyfd, TCIOFLUSH);
// Set new attributes:
if (tcsetattr(ttyfd, TCSANOW, &attr)) return 2;
OSEPP Compass 모듈에서 데이터를 보내는 Arduino 코드입니다.
// OSEPP Compass Sensor Example Sketch
// by OSEPP <http://www.osepp.com>
// Modifications by Chris W. to accommodate declination, scaling and origin adjustment 2013-02-13
// This sketch demonstrates interactions with the Compass Sensor
#include <Wire.h>
const uint8_t sensorAddr = 0x1E; // Sensor address (non-configurable)
const float xOffset = 103.0; // Offset required to adjust x coordinate to zero origin
const float yOffset = -165.0; // Offset required to adjust y coordinate to zero origin
const float declination = 70.1; // Enter magnetic declination mrads here (local to your geo area)
// One-time setup
void setup()
{
// Start the serial port for output
Serial.begin(115200);
// Join the I2C bus as master
Wire.begin();
// Configure the compass to default values (see datasheet for details)
WriteByte(sensorAddr, 0x0, 0x70);
WriteByte(sensorAddr, 0x1, 0x20); // +1.3Ga
// Set compass to continuous-measurement mode (default is single shot)
WriteByte(sensorAddr, 0x2, 0x0);
}
// Main program loop
void loop()
{
uint8_t x_msb; // X-axis most significant byte
uint8_t x_lsb; // X-axis least significant byte
uint8_t y_msb; // Y-axis most significant byte
uint8_t y_lsb; // Y-axis least significant byte
uint8_t z_msb; // Z-axis most significant byte
uint8_t z_lsb; // Z-axis least significant byte
int x;
int y;
int z;
// Get the value from the sensor
if ((ReadByte(sensorAddr, 0x3, &x_msb) == 0) &&
(ReadByte(sensorAddr, 0x4, &x_lsb) == 0) &&
(ReadByte(sensorAddr, 0x5, &z_msb) == 0) &&
(ReadByte(sensorAddr, 0x6, &z_lsb) == 0) &&
(ReadByte(sensorAddr, 0x7, &y_msb) == 0) &&
(ReadByte(sensorAddr, 0x8, &y_lsb) == 0))
{
x = x_msb << 8 | x_lsb;
y = y_msb << 8 | y_lsb;
z = z_msb << 8 | z_lsb;
int xs;
int ys;
int zs;
float gScale = .92; // Scale factor for +1.3Ga setting
float adjx = x - xOffset;
float adjy = y - yOffset;
xs = adjx * gScale;
ys = adjy * gScale;
zs = z * gScale;
float heading = atan2(ys, xs);
heading += declination / 1000; // Declination for geo area
if (heading < 0);
heading += 2*PI;
if (heading > 2*PI)
heading -= 2*PI;
float angle = heading * 180/M_PI;
Serial.print("X: ");
Serial.print(x);
Serial.print(" Y: ");
Serial.print(y);
Serial.print(" Z: ");
Serial.print(z);
Serial.print(" Xs: ");
Serial.print(xs);
Serial.print(" Ys: ");
Serial.print(ys);
Serial.print(" Zs: ");
Serial.print(zs);
Serial.print(" H: ");
Serial.print(heading);
Serial.print(" A: ");
Serial.println(angle);
}
else
{
Serial.println("Failed to read from sensor");
}
// Run again in 1 s (1000 ms)
delay(500);
}
// Read a byte on the i2c interface
int ReadByte(uint8_t addr, uint8_t reg, uint8_t *data)
{
// Do an i2c write to set the register that we want to read from
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.endTransmission();
// Read a byte from the device
Wire.requestFrom(addr, (uint8_t)1);
if (Wire.available())
{
*data = Wire.read();
}
else
{
// Read nothing back
return -1;
}
return 0;
}
// Write a byte on the i2c interface
void WriteByte(uint8_t addr, uint8_t reg, byte data)
{
// Begin the write sequence
Wire.beginTransmission(addr);
// First byte is to set the register pointer
Wire.write(reg);
// Write the data byte
Wire.write(data);
// End the write sequence; bytes are actually transmitted now
Wire.endTransmission();
}
이 문제를 해결할 수 있으므로 arduino 코드에서 지연 순서와 직렬 쓰기를 전환 해 보겠습니다.하지만 유사한 미래 시나리오에서는 코드가 비효율적입니다.
IC의 데이터 시트를 살펴 보았습니다.
14 페이지 참조 : 링크
연속 측정 모드. 연속 측정 모드에서 장치는 지속적으로 측정을 수행하고 결과를 데이터 레지스터에 배치합니다. 새 데이터가 세 레지스터 모두에 배치되면 RDY가 높아 집니다. 전원을 켜거나 모드 또는 구성 레지스터에 기록한 후 2 / f_DO 기간 후 세 데이터 출력 레지스터 모두에서 첫 번째 측정 세트를 사용할 수 있으며 후속 측정은 f_DO의 주파수에서 사용할 수 있습니다. 여기서 f_DO는 주파수입니다. 데이터 출력
Arduino 문서에 따르면 Wire 라이브러리는 100KHz에서 실행됩니다. 2 / 100KHz == 20uS. Arduino가 16MHz (1주기 == 62.5ns)에서 실행된다고 가정하면 레지스터를 읽을만큼 오래 기다리지 않을 것입니다.
코드를 더 견고하게 만들려면 읽기를 수행하기 전에 상태 레지스터의 RDY 비트를 확인하는 것이 좋습니다. 데이터는 정확할 수 있지만 IC에 걸리는 시작 시간을 고려해야합니다.
이 작업을 수행하고 동일한 문제가 계속 발생하는 경우 적어도 문제를 추가로 격리 한 것입니다.
또는 빠른 해킹을 원한다면 메인 루프 하단에 500ms 지연을 배치 할 수 있습니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다