BASIC4MCU | 질문게시판 | I2C통신 연결 시리얼값오류 도와주세요
페이지 정보
작성자 매드닥터 작성일2023-08-12 20:07 조회1,736회 댓글12건본문
현재 저는 마이크로아두이노를사용하여 통신을하고있습니다 현재 마스터쪽과 슬레이브는 서로같은 I2C핀인 0번과 1번을 연결해놓았고 저항을 5K옴으로 풀업을주었습니다 물론 마스터와 슬레이브가 같은 곳에 GND를연결해주었습니다. 그리고 슬레이브쪽은 현제 초음파센서와 서보모터를연결해놓았습니다 밑에 현재사용중인 마스터아두이노의코딩과 슬레이브아두이노코딩을 오려두겠습니다 그리고 각자의 시리얼모니터로 어떻게 출력되고있는지 올려드리겠습니다.원인을아시는분은 알려주세요
마스터아두이노코딩
#include <Wire.h>#define SLAVE_ADDRESS 10int startAngle;int endAngle;float objectSize;float averageDistance;void setup() {Wire.begin();Serial.begin(9600);}void loop() {Wire.requestFrom(SLAVE_ADDRESS, sizeof(startAngle) + sizeof(endAngle) + sizeof(objectSize) + sizeof(averageDistance));if (Wire.available() >= (sizeof(startAngle) + sizeof(endAngle) + sizeof(objectSize) + sizeof(averageDistance))) {Wire.readBytes((uint8_t *)&startAngle, sizeof(startAngle));Wire.readBytes((uint8_t *)&endAngle, sizeof(endAngle));Wire.readBytes((uint8_t *)&objectSize, sizeof(objectSize));Wire.readBytes((uint8_t *)&averageDistance, sizeof(averageDistance));Serial.print("Start Angle: ");Serial.print(startAngle);Serial.print(" degrees, End Angle: ");Serial.print(endAngle);Serial.print(" degrees, Object Size: ");Serial.print(objectSize);Serial.print(" cm, Average Distance: ");Serial.print(averageDistance);Serial.println(" cm");}}
슬레이브아두이노 코딩
#include <Wire.h>#include <Servo.h>#define TRIGGER_PIN 6#define ECHO_PIN 7#define SERVO_PIN 9#define SLAVE_ADDRESS 10Servo servo;long duration;int distance;float objectSize;float averageDistance;int startAngle;int endAngle;bool detectionStarted = false;bool objectDetected = false;const int maxDetectedAngles = 50;int detectedAngles[maxDetectedAngles];int detectedAngleCount = 0;void setup() {pinMode(TRIGGER_PIN, OUTPUT);pinMode(ECHO_PIN, INPUT);servo.attach(SERVO_PIN);servo.write(0);Wire.begin(SLAVE_ADDRESS);Serial.begin(9600);}void loop() {for (int angle = 0; angle <= 90; angle += 5) {servo.write(angle);delay(1000);if (angle >= 0 && angle <= 90) {distance = measureDistance();if (distance <= 150) {if (!detectionStarted) {startAngle = angle;detectionStarted = true;objectDetected = true;}if (detectedAngleCount < maxDetectedAngles) {detectedAngles[detectedAngleCount] = distance;detectedAngleCount++;}} else {if (detectionStarted) {endAngle = angle - 5;detectionStarted = false;measureObjectSize();sendInformation();objectDetected = false;}}}}}int measureDistance() {digitalWrite(TRIGGER_PIN, LOW);delayMicroseconds(2);digitalWrite(TRIGGER_PIN, HIGH);delayMicroseconds(10);digitalWrite(TRIGGER_PIN, LOW);duration = pulseIn(ECHO_PIN, HIGH);distance = duration * 0.034 / 2;return distance;}void measureObjectSize() {float totalDistance = 0;for (int i = 0; i < detectedAngleCount; i++) {totalDistance += detectedAngles[i];}if (detectedAngleCount > 0) {averageDistance = totalDistance / detectedAngleCount;objectSize = averageDistance * (endAngle - startAngle) / 150.0;} else {objectSize = 0;}detectedAngleCount = 0;}void sendInformation() {Wire.beginTransmission(0); // 0은 브로드캐스트 주소Wire.write((uint8_t *)&startAngle, sizeof(startAngle));Wire.write((uint8_t *)&endAngle, sizeof(endAngle));Wire.write((uint8_t *)&objectSize, sizeof(objectSize));Wire.write((uint8_t *)&averageDistance, sizeof(averageDistance));Wire.endTransmission();Serial.print("Start Angle: ");Serial.print(startAngle);Serial.print(" degrees, End Angle: ");Serial.print(endAngle);Serial.print(" degrees, Object Size: ");Serial.print(objectSize);Serial.print(" cm, Average Distance: ");Serial.print(averageDistance);Serial.println(" cm");}
마스터시리얼모니터
19:59:43.929 -> nan cm
19:59:43.929 -> Start Angle: -256 degrees, End Angle: -1 degrees, Object Size: nan cm, Average Distance: nan cm
19:59:43.929 -> Start Angle: -256 degrees, End Angle: -1 degrees, Object Size: nan cm, Average Distance: nan cm
이러한값이 꾸준히반복되면서 오라오는중
슬레이브시리얼모니터
19:23:30.481 -> Name: 오른쪽, Start Angle: 5 degrees, End Angle: 5 degrees, Object Size: 0.00 cm, Average Distance: 124.00 cm
19:23:43.638 -> Name: 오른쪽, Start Angle: 70 degrees, End Angle: 70 degrees, Object Size: 0.00 cm, Average Distance: 72.00 cm
19:23:47.671 -> Name: 오른쪽, Start Angle: 90 degrees, End Angle: -5 degrees, Object Size: -58.27 cm, Average Distance: 92.00 cm
19:37:30.733 -> Start Angle: 20 degrees, End Angle: 20 degrees, Object Size: 0.00 cm, Average Distance: 7.00 cm
19:37:37.796 -> Start Angle: 55 degrees, End Angle: 55 degrees, Object Size: 0.00 cm, Average Distance: 4.00 cm
19:37:42.855 -> Start Angle: 80 degrees, End Angle: 80 degrees, Object Size: 0.00 cm, Average Distance: 5.00 cm
19:46:32.921 -> Start Angle: 40 degrees, End Angle: 40 degrees, Object Size: 0.00 cm, Average Distance: 65.00 cm
19:47:09.320 -> Start Angle: 30 degrees, End Angle: 30 degrees, Object Size: 0.00 cm, Average Distance: 7.00 cm
슬레이브쪽은 초음파센서에 사물이탐지될때마다 저렇게 시리얼모니터에 값이 뜹니다
댓글 12
조회수 1,736알토이드님의 댓글
알토이드 작성일
0,1번핀은 serial 통신에 사용되고
2,3 번핀이 i2c 통신에 사용되는 것이 아닌가요?
매드닥터님의 댓글
매드닥터 작성일아죄송합니다 제가 글을잘못올렸습니다 말씀하신대로 연결되어있습니다. 현재 2번 3번이 연결되어있습니다.
master님의 댓글
master 작성일
아두이노 예제는 돌려보셨겠죠?
동작을 확인한 예제를 첨부하든지 링크 적어보세요
매드닥터님의 댓글
매드닥터 작성일
i2c 통신이 재대로 이루어지고 있는지는 다음 코딩으로 확인했습니다.
I2C통신 확인코딩
마스터
#include <Wire.h>
void setup() {
Wire.begin(); // I2C 통신 초기화
Serial.begin(9600); // 시리얼 통신 시작
}
void loop() {
if (Serial.available()) {
char command = Serial.read(); // 시리얼 입력 읽기
if (command == 'M') {
Wire.beginTransmission(8); // 슬레이브의 I2C 주소 8로 시작
Wire.write('M'); // 명령 전송
Wire.endTransmission(); // 전송 완료
Serial.println("Sent command 'M' to slave."); // 디버그용 메시지 출력
}
}
}
슬레이브
#include <Wire.h>
#include <Servo.h>
Servo servoMotor;
int targetAngle = 0; // 서보 모터의 목표 각도
bool commandReceived = false; // 명령을 받았는지 확인하는 플래그
void setup() {
Wire.begin(8); // 슬레이브의 I2C 주소를 8로 설정
Wire.onReceive(receiveI2CEvent); // 함수 이름 변경
servoMotor.attach(9); // 서보 모터 핀을 9번에 연결 (예시 핀 번호)
servoMotor.write(90); // 초기 각도 설정 (90도)
Serial.begin(9600); // 시리얼 통신 시작
}
void loop() {
if (commandReceived) {
for (int angle = 0; angle <= 90; angle += 5) {
Serial.println("Moving servo to angle: " + String(angle));
servoMotor.write(angle); // 각도로 서보 모터 움직이기
delay(1000); // 1초 대기
}
commandReceived = false; // 명령 수행 완료
}
}
void receiveI2CEvent(int bytes) { // 함수 이름 변경
while (Wire.available()) {
char command = Wire.read(); // 받은 명령 읽기
if (command == 'M') { // "M" 명령인 경우
Serial.println("Received command 'M'."); // 디버그용 메시지 출력
commandReceived = true; // 명령을 받았음을 표시
}
}
}
매드닥터님의 댓글
매드닥터 작성일재대로 마스터의명령을듣고 슬레이브가 작동하는것을 확인했습니다 물론 코딩의 내용처럼 디버깅을하여 시리얼모니터로 명령을 수신하는것과 송신받고 움직일때마다 해당각도를 시리얼모니터에 뜨는것도확인이 되었습니다.
master님의 댓글
master
1바이트 송수신에는 문제가 없다는 것을 확인 했군요
매드닥터님의 댓글
매드닥터 작성일
현재 슬레이브쪽은 제가원하는값을아주잘띄우고있습니다. 이걸마스터가 i2c통신으로받기만하면되는데 뭐가 문제인지 모르겠습니다 코딩의 문제가 있는것같은데 오류는 안뜨는상태이니 모르겠습니다. ㅠㅠ
마스터코딩이 전부다 바뀌어도상관없으니 누가 도와주십시오 이걸해결하고나면 현재 emic2모듈을 마스터한테 연결시켜 시리얼모니터에나오는값을 음성출력하는것이 최종목적입니다.
master님의 댓글
master
슬레이브에서 측정한 후, 측정값을 마스터로 보내지말고
슬레이브에서 측정하고, 측정값으로 음성출력 종류까지 계산 한 후, 마스터로 음성 출력 종류를 보내세요
음성 출력의 종류가 수십개 이상 되지는 않을테니 1바이트면 충분합니다.
즉, 마스터에서 처리하던 (거리값->음성출력) 계산을 슬레이브에서 하는 겁니다.
마스터에서는 단순히 슬레이브에서 출력해달라는 음성만 출력해주는 것이죠
매드닥터님의 댓글
매드닥터 작성일감사합니다 한번그렇게 시도해보겠습니다.
매드닥터님의 댓글
매드닥터 작성일
말씀하신대로하니 반대로 오류가 많이 생기고 i2c통신이 안되어 마스터는 어떠한 시리얼모니터도 뜨지않습니다 그래서 지금 이러한 마스터아두이노 코딩을 업로드하고 사용해보았습니다
#include <Wire.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // 소리 출력을 위한 소프트웨어 시리얼 통신 객체 생성
#define SLAVE1_ADDRESS 9 // 첫 번째 슬레이브 아두이노 주소
#define SLAVE2_ADDRESS 10 // 두 번째 슬레이브 아두이노 주소
void setup() {
Wire.begin(); // 마스터 아두이노 통신 시작
mySerial.begin(9600); // 소리 출력을 위한 소프트웨어 시리얼 통신 시작
Serial.begin(9600); // 시리얼 통신 시작
}
void loop() {
// 첫 번째 슬레이브에 대한 정보 수신 및 출력
Wire.requestFrom(SLAVE1_ADDRESS, 8); // 5바이트 데이터 요청
if (Wire.available() >= 8) {
String receivedData = "";
while (Wire.available()) {
char receivedChar = Wire.read();
receivedData += receivedChar;
}
String name = receivedData.substring(0, receivedData.indexOf(',')); // 이름 추출
int startAngleIndex = receivedData.indexOf(',') + 1; // 시작 각도 인덱스
int startAngle = receivedData.substring(startAngleIndex, receivedData.indexOf(',', startAngleIndex)).toInt(); // 시작 각도 추출
int endAngleIndex = receivedData.indexOf(',', startAngleIndex) + 1; // 끝 각도 인덱스
int endAngle = receivedData.substring(endAngleIndex, receivedData.indexOf(',', endAngleIndex)).toInt(); // 끝 각도 추출
int objectSizeIndex = receivedData.indexOf(',', endAngleIndex) + 1; // 사물 크기 인덱스
float objectSize = receivedData.substring(objectSizeIndex).toFloat(); // 사물 크기 추출
// 평균 거리 정보 추출
int averageDistanceIndex = receivedData.indexOf(',', objectSizeIndex) + 1; // 평균 거리 인덱스
float averageDistance = receivedData.substring(averageDistanceIndex).toFloat(); // 평균 거리 추출
// 데이터 출력
Serial.print("Slave 1 - Name: ");
Serial.print(name);
Serial.print(", Start Angle: ");
Serial.print(startAngle);
Serial.print(" degrees, End Angle: ");
Serial.print(endAngle);
Serial.print(" degrees, Object Size: ");
Serial.print(objectSize);
Serial.print(" cm, Average Distance: ");
Serial.print(averageDistance);
Serial.println(" cm");
// 소리 출력 (TTS 모듈 사용)
String ttsMessage = "Slave 1 - Name: " + name + ", Start Angle: " + String(startAngle) + " degrees, End Angle: " + String(endAngle) + " degrees, Object Size: " + String(objectSize) + " cm, Average Distance: " + String(averageDistance) + " cm";
mySerial.println(ttsMessage); // TTS 메시지 출력
}
// 두 번째 슬레이브에 대한 정보 수신 및 출력
Wire.requestFrom(SLAVE2_ADDRESS, 8); // 5바이트 데이터 요청
if (Wire.available() >= 8) {
String receivedData = "";
while (Wire.available()) {
char receivedChar = Wire.read();
receivedData += receivedChar;
}
String name = receivedData.substring(0, receivedData.indexOf(',')); // 이름 추출
int startAngleIndex = receivedData.indexOf(',') + 1; // 시작 각도 인덱스
int startAngle = receivedData.substring(startAngleIndex, receivedData.indexOf(',', startAngleIndex)).toInt(); // 시작 각도 추출
int endAngleIndex = receivedData.indexOf(',', startAngleIndex) + 1; // 끝 각도 인덱스
int endAngle = receivedData.substring(endAngleIndex, receivedData.indexOf(',', endAngleIndex)).toInt(); // 끝 각도 추출
int objectSizeIndex = receivedData.indexOf(',', endAngleIndex) + 1; // 사물 크기 인덱스
float objectSize = receivedData.substring(objectSizeIndex).toFloat(); // 사물 크기 추출
// 평균 거리 정보 추출
int averageDistanceIndex = receivedData.indexOf(',', objectSizeIndex) + 1; // 평균 거리 인덱스
float averageDistance = receivedData.substring(averageDistanceIndex).toFloat(); // 평균 거리 추출
// 데이터 출력
Serial.print("Slave 2 - Name: ");
Serial.print(name);
Serial.print(", Start Angle: ");
Serial.print(startAngle);
Serial.print(" degrees, End Angle: ");
Serial.print(endAngle);
Serial.print(" degrees, Object Size: ");
Serial.print(objectSize);
Serial.print(" cm, Average Distance: ");
Serial.print(averageDistance);
Serial.println(" cm");
// 소리 출력 (TTS 모듈 사용)
String ttsMessage = "Slave 2 - Name: " + name + ", Start Angle: " + String(startAngle) + " degrees, End Angle: " + String(endAngle) + " degrees, Object Size: " + String(objectSize) + " cm, Average Distance: " + String(averageDistance) + " cm";
mySerial.println(ttsMessage); // TTS 메시지 출력
}
}
이코딩을사용하니
18:04:42.549 -> Slave 2 - Name: , Start Angle: 0 degrees, End Angle: 0 degrees, Object Size: 0.00 cm, Average Distance: 0.00 cm
18:04:42.672 -> Slave 2 - Name: , Start Angle: 0 degrees, End Angle: 0 degrees, Object Size: 0.00 cm, Average Distance: 0.00 cm
이러한 값이 시리얼모니터에 뜨는것을확인했습니다. 시리얼모니터를 보았을때분명 요구하고있는것같은데 정보를받지못해서 이러한값이 뜨는건지 잘모르겠습니다.
매드닥터님의 댓글
매드닥터 작성일값이 마스터쪽에 저렇게 뜨고있어도 i2c통신이 되고있다고 생각한 이유는 i2c통신선을하나라도 빼면 더이상 값을 시리얼모니터에 만들지않기 때문입니다
master님의 댓글
master
슬레이브가 2개 인가요?
아두이노 예제처럼 심플한 코드를 만들어서 테스트 하세요