From cce4c3d5b7a26fbb11bcf83373e9544944eeec0f Mon Sep 17 00:00:00 2001 From: Artur Date: Sat, 4 Apr 2026 20:12:29 +0500 Subject: [PATCH] 04-04-2026-20-12 --- scr/MKS42C.cpp | 156 +++++++++++++++++++++++++++++++++++++++++++++++++ scr/MKS42C.h | 87 +++++++++++++++++++++++++++ 2 files changed, 243 insertions(+) diff --git a/scr/MKS42C.cpp b/scr/MKS42C.cpp index e69de29..813a2c8 100644 --- a/scr/MKS42C.cpp +++ b/scr/MKS42C.cpp @@ -0,0 +1,156 @@ +#include "MKS42C.h" + +MKS42C::MKS42C(HardwareSerial& serial, uint8_t address) { + _serial = &serial; + _addr = address; + _isMoving = false; +} + +uint8_t MKS42C::calculateCRC(uint8_t* data, uint8_t len) { + // вычисление контрольной суммы + uint16_t checksum = 0; + for (uint8_t i = 0; i < len; i++) { + checksum += data[i]; + } + return (uint8_t)(checksum & 0xFF); +} + +void MKS42C::sendRaw(uint8_t* data, uint8_t len) { + // отправить в порт + _serial->write(data, len); + _serial->write(calculateCRC(data, len)); +} + +void MKS42C::clearBuffer() { + // очистить входящий буфер + while (_serial->available()) { + _serial->read(); + } +} + +void MKS42C::setEnable(bool state) { + // вкл / выкл движка + uint8_t cmd[] = {_addr, 0xF3, (uint8_t)(state ? 0x01 : 0x00)}; + sendRaw(cmd, 3); +} + +void MKS42C::stop() { + // стоп + uint8_t cmd[] = {_addr, 0xF7}; + sendRaw(cmd, 2); + _isMoving = false; +} + +void MKS42C::setHome() { + // задать текущую позицию, как 0 (сброс энкодера) + uint8_t cmd[] = {_addr, 0x34}; + sendRaw(cmd, 2); + delay(100); +} + +void MKS42C::setTorque(uint16_t ma) { + // задать момент вращения + uint8_t cmd[] = {_addr, 0xAF, (uint8_t)((ma >> 8) & 0xFF), (uint8_t)(ma & 0xFF)}; + sendRaw(cmd, 4); +} + +void MKS42C::run(uint8_t dir, uint8_t speed) { + // просто включить + uint8_t val = ((dir & 0x01) << 7) | (speed & 0x7F); + uint8_t cmd[] = {_addr, 0xF6, val}; + + sendRaw(cmd, 3); + _isMoving = true; +} + +void MKS42C::rotateDegrees(float degrees, uint8_t speed) { + // включить на определённое количество гражут=сов + long pulses = (long)((degrees / 360.0) * 16384.0); + uint8_t dir = (pulses >= 0) ? 0x00 : 0x01; + uint32_t absP = abs(pulses); + + uint8_t cmd[] = { + _addr, + 0xFD, + (uint8_t)((dir << 7) | (speed & 0x7F)), + (uint8_t)((absP >> 24) & 0xFF), + (uint8_t)((absP >> 16) & 0xFF), + (uint8_t)((absP >> 8) & 0xFF), + (uint8_t)(absP & 0xFF) + }; + sendRaw(cmd, 7); + _isMoving = true; +} + +float MKS42C::readPosition() { + // считать значение энкодера + clearBuffer(); + uint8_t cmd[] = {_addr, 0x30}; + sendRaw(cmd, 2); + + unsigned long start = millis(); + while (_serial->available() < 5 && millis() - start < 50); + + if (_serial->available() >= 5) { + uint8_t buf[5]; + _serial->readBytes(buf, 5); + + uint16_t rawPos = (uint16_t)((buf[2] << 8) | buf[3]); + + // Переводим в понятные градусы + return (rawPos * 360.0) / 16384.0; + } + + return -1.0; +} + +long MKS42C::readAbsolutePosition() { + // считать абсолютное значение энкодера + clearBuffer(); + uint8_t cmd[] = {_addr, 0x31}; + sendRaw(cmd, 2); + + unsigned long start = millis(); + while (_serial->available() < 6 && millis() - start < 100); + + if (_serial->available() >= 6) { + uint8_t buf[6]; + _serial->readBytes(buf, 6); + uint32_t rawPos = ((uint32_t)buf[2] << 24) | ((uint32_t)buf[3] << 16) | + ((uint32_t)buf[4] << 8) | (uint32_t)buf[5]; + return (buf[1] == 0) ? (long)rawPos : -(long)rawPos; + } + return 0; +} + +bool MKS42C::isBusy() { + // проверить движется ли мотор + if (_serial->available() >= 3) { + uint8_t buf[3]; + if (_serial->peek() == _addr) { + _serial->readBytes(buf, 3); + if (buf[1] == 0x02) { + _isMoving = false; + return false; + } + } + } + return _isMoving; +} + +bool MKS42C::isBlocked() { + // проверить блокировку вала + clearBuffer(); + uint8_t cmd[] = {_addr, 0x3A}; + sendRaw(cmd, 2); + + unsigned long start = millis(); + while (_serial->available() < 3 && millis() - start < 50); + + if (_serial->available() >= 3) { + uint8_t buf[3]; + _serial->readBytes(buf, 3); + return (buf[1] == 0x02); + } + return false; +} \ No newline at end of file diff --git a/scr/MKS42C.h b/scr/MKS42C.h index e69de29..675b48b 100644 --- a/scr/MKS42C.h +++ b/scr/MKS42C.h @@ -0,0 +1,87 @@ +#ifndef MKS42C_H +#define MKS42C_H + +#include +#include + +class MKS42C { +public: + /** + * @brief Конструктор класса + * @param serial Ссылка на объект HardwareSerial (например, Serial2) + * @param address UART адрес мотора (по умолчанию 0xE0) + */ + MKS42C(HardwareSerial& serial, uint8_t address = 0xE0); + + /** + * @brief Включить или выключить удержание вала + * @param state true - включить (Enable), false - отключить (Disable) + */ + void setEnable(bool state); + + /** + * @brief Остановка двигателя + */ + void stop(); + + /** + * @brief Установить текущую позицию как нулевую (Home) + * Данные записываются в EEPROM драйвера. + */ + void setHome(); + + /** + * @brief Установка крутящего момента через ограничение тока + * @param ma Ток в миллиамперах (рекомендуется 0 - 2000) + */ + void setTorque(uint16_t ma); + + /** + * @brief Запустить непрерывное вращение + * @param dir Направление: 0 - CW (по часовой), 1 - CCW (против часовой) + * @param speed Скорость вращения (0 - 255) + */ + void run(uint8_t dir, uint8_t speed); + + /** + * @brief Поворот на определенное количество градусов + * @param degrees Угол (положительный или отрицательный) + * @param speed Скорость вращения (0 - 255) + */ + void rotateDegrees(float degrees, uint8_t speed); + + /** + * @brief Чтение текущей позиции вала (0-360 градусов) + * @return Позиция в градусах (float) + */ + float readPosition(); + + /** + * @brief Чтение абсолютной позиции энкодера (с учетом полных оборотов) + * @return Количество импульсов (14-бит энкодер: 16384 на оборот при MStep 16) + */ + long readAbsolutePosition(); + + /** + * @brief Проверка, завершил ли мотор движение (по команде rotateDegrees) + * @return true - мотор еще в пути, false - мотор остановился + */ + bool isBusy(); + + /** + * @brief Проверка состояния защиты (блокировка вала) + * @return true - сработала защита (Protect), false - нормальная работа + */ + bool isBlocked(); + +private: + HardwareSerial* _serial; + uint8_t _addr; + bool _moving; + + uint8_t calculateCRC(uint8_t* data, uint8_t len); + void sendRaw(uint8_t* data, uint8_t len); + void clearBuffer(); +}; + +#endif \ No newline at end of file