//==============================================================
// MotorBank BLC 시리즈 아두이노 RS485(MC-RS485 프로토콜) 공용 예제 V1.1
// 적용 제품: BLC-200 / BLC-400 / BLC-400R4E (통신 프로토콜 동일)
// 기능: 속도제어(가감속) / 위치제어(가감속) / 위치·속도 피드백 읽기
// 보드: Arduino Uno + RS485 컨버터 모듈(MAX485 등)
// 근거: 통신프로토콜 MC-RS485 V1.0.1 (문서 예제 체크섬 10건 검증 일치)
//
// [통신 설정] 9600bps(제품 초기값), 8 Data, No Parity, 1 Stop
// [프레임 구조] FF FE | ID | Data크기 | Checksum | Mode | Data...
// Checksum = ~(ID + Data크기 + Mode + Data바이트 합)의 하위 1바이트
//
// [결선 - MAX485 모듈 기준]
// 모듈 RO -> D10 / DI -> D11 / DE+RE(묶음) -> D3
// 모듈 A/B -> 드라이버 485 A/B (통신 안 되면 A/B 교차)
// 모듈 VCC -> 5V, GND -> 아두이노·드라이버 공통
// * MAS-001 확장쉴드 사용 시 쉴드의 485 단자에 연결 (MAS-001 상세페이지 참조)
//
// [시리얼 모니터 사용법] (9600bps, "새 줄" 설정)
// f1000 : CW 100.0RPM (0.1RPM 단위, 도달시간 1초 가감속)
// r500 : CCW 50.0RPM
// s : 정지(속도 0)
// g9000 : CW 90.00도 위치 이동 (0.01도 단위, 도달시간 1초)
// G9000 : CCW 90.00도 위치 이동
// z : 현재 위치를 0으로 초기화
// p : 위치 피드백 요청(방향/각도/속도/전류 표시)
// v : 속도 피드백 요청
//==============================================================
#include <SoftwareSerial.h>
const int RS485_RX = 10, RS485_TX = 11, RS485_EN = 3;
const byte MOTOR_ID = 0x00; // 제품 초기 ID 0x00 (변경했다면 수정)
SoftwareSerial rs485(RS485_RX, RS485_TX);
// 프레임 송신: mode + data → 헤더/크기/체크섬 자동 구성
void sendFrame(byte mode, const byte *data, byte dlen) {
byte size = dlen + 2; // Mode + Data + Checksum
int sum = MOTOR_ID + size + mode;
for (byte i = 0; i < dlen; i++) sum += data[i];
byte chk = (~sum) & 0xFF;
byte f[16]; byte n = 0;
f[n++] = 0xFF; f[n++] = 0xFE;
f[n++] = MOTOR_ID; f[n++] = size; f[n++] = chk; f[n++] = mode;
for (byte i = 0; i < dlen; i++) f[n++] = data[i];
while (rs485.available()) rs485.read(); // 수신버퍼 비우기
digitalWrite(RS485_EN, HIGH);
rs485.write(f, n);
rs485.flush();
digitalWrite(RS485_EN, LOW);
Serial.print(F("TX:"));
for (byte i = 0; i < n; i++) { Serial.print(' '); if (f[i]<16) Serial.print('0'); Serial.print(f[i], HEX); }
Serial.println();
}
// 수신 프레임 읽기 + 위치/속도 피드백(0xD1/0xD2) 해석
void readFeedback() {
byte buf[24]; byte n = 0;
unsigned long t0 = millis();
while (millis() - t0 < 300 && n < 24) {
if (rs485.available()) buf[n++] = rs485.read();
}
if (n == 0) { Serial.println(F("RX: (응답 없음 - 결선/ID/전원 확인)")); return; }
Serial.print(F("RX:"));
for (byte i = 0; i < n; i++) { Serial.print(' '); if (buf[i]<16) Serial.print('0'); Serial.print(buf[i], HEX); }
Serial.println();
// 프레임 헤더 탐색(자기 에코 뒤에 응답이 붙을 수 있어 마지막 FFFE 기준 해석)
for (int i = n - 4; i >= 0; i--) {
if (buf[i] == 0xFF && buf[i+1] == 0xFE) {
byte mode = buf[i+5];
if ((mode == 0xD1 || mode == 0xD2) && i + 11 < (int)n + 1) {
byte dir = buf[i+6];
unsigned int a = ((unsigned int)buf[i+7] << 8) | buf[i+8];
unsigned int b = ((unsigned int)buf[i+9] << 8) | buf[i+10];
byte cur = buf[i+11];
if (mode == 0xD1) { // 위치 피드백: 위치[0.01도] 속도[0.1RPM]
Serial.print(F("위치: ")); Serial.print(dir ? F("CW ") : F("CCW "));
Serial.print(a / 100.0); Serial.print(F("도, 속도 "));
Serial.print(b / 10.0); Serial.print(F("RPM, 전류 "));
Serial.print(cur * 0.1); Serial.println(F("A"));
} else { // 속도 피드백: 속도[0.1RPM] 위치[0.1도]
Serial.print(F("속도: ")); Serial.print(dir ? F("CW ") : F("CCW "));
Serial.print(a / 10.0); Serial.print(F("RPM, 위치 "));
Serial.print(b / 10.0); Serial.print(F("도, 전류 "));
Serial.print(cur * 0.1); Serial.println(F("A"));
}
}
break;
}
}
}
void speedMove(byte dir, unsigned int spd01rpm, byte time01s) { // 가감속 속도제어 0x03
byte d[4] = { dir, (byte)(spd01rpm >> 8), (byte)(spd01rpm & 0xFF), time01s };
sendFrame(0x03, d, 4);
}
void posMove(byte dir, unsigned int pos001deg, byte time01s) { // 가감속 위치제어 0x02
byte d[4] = { dir, (byte)(pos001deg >> 8), (byte)(pos001deg & 0xFF), time01s };
sendFrame(0x02, d, 4);
}
void setup() {
Serial.begin(9600);
rs485.begin(9600); // 제품 초기값 9600bps
pinMode(RS485_EN, OUTPUT);
digitalWrite(RS485_EN, LOW);
Serial.println(F("BLC MC-RS485 ready."));
Serial.println(F("f1000 r500 s g9000 G9000 z p v"));
}
void loop() {
if (!Serial.available()) return;
String cmd = Serial.readStringUntil('\n');
cmd.trim();
if (cmd.length() == 0) return;
char c = cmd.charAt(0);
long v = cmd.substring(1).toInt();
switch (c) {
case 'f': speedMove(0x01, constrain(v, 1, 65533), 10); break; // CW, 도달 1.0s
case 'r': speedMove(0x00, constrain(v, 1, 65533), 10); break; // CCW
case 's': speedMove(0x01, 1, 5); delay(600); speedMove(0x01, 1, 1);
Serial.println(F("감속 정지")); break;
case 'g': posMove(0x01, constrain(v, 0, 65533), 10); break; // CW 위치
case 'G': posMove(0x00, constrain(v, 0, 65533), 10); break; // CCW 위치
case 'z': sendFrame(0x0E, nullptr, 0); Serial.println(F("위치 0 초기화")); break;
case 'p': sendFrame(0xA1, nullptr, 0); readFeedback(); return;
case 'v': sendFrame(0xA2, nullptr, 0); readFeedback(); return;
default: Serial.println(F("? f1000 r500 s g9000 G9000 z p v")); return;
}
readFeedback(); // 명령 후 응답/에코 로그 표시
}



장착된 브레이크는 B타입 브레이크입니다.
B타입 브레이크는 전압을 인가해줘야 브레이크가 해제되어 모터 샤프트가 회전합니다.
주로 수직상태로 모터가 놓일 때, B타입 브레이크를 사용합니다.
브레이크에 전압을 인가하지 않은 상태에서 모터를 절대 구동시키지 마세요!




브레이크 장착BLDC모터 시리즈

엔코더 홀센서타입BLDC모터 시리즈





