├── CmdLine.png ├── README.md ├── SabvotonCommandlineInterface.ino └── SabvotonRegister.xlsx /CmdLine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/slothorpe/SabvotonCommandLineInterface/b0ab4bbcf0b1429a6f23fa882225417baf2940a5/CmdLine.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SabvotonCommandLineInterface 2 | simple command-line interface for MQ Sabvoton BLDC controller using ModBus-Master library 3 | 4 | This is a sipmle arduino sketch providing a command line interface to the MQ Sabvoton BLDC controller using the ModBus-Master library. 5 | Also there is a screenshot showing the usage and a spreadsheet with the known registers of the Sabvoton. 6 | 7 | Please be carefull with writing in unknown registers, you might kill your controller ! 8 | 9 | Last update: 10 | - minor bugfixes 11 | - added support for small OLED displays with U8GLIB to show the values of all status registers all 500ms 12 | -------------------------------------------------------------------------------- /SabvotonCommandlineInterface.ino: -------------------------------------------------------------------------------- 1 | /* Command-Line Interface für den Sabvoton-Controller 2 | * Basis ModbusMaster Library 3 | * Holger Lesch, August 2019 4 | * holger.lesch@gmx.net 5 | * 6 | * last Change: March 2020: oled-display for status registers 7 | */ 8 | 9 | #include 10 | #include 11 | 12 | #define OLED_DISPLAY 13 | #ifdef OLED_DISPLAY 14 | #include "U8glib.h" 15 | //U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NONE); // I2C / TWI 16 | U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_NO_ACK); 17 | #endif 18 | 19 | #define LED_PIN 13 20 | 21 | 22 | // instantiate ModbusMaster object 23 | ModbusMaster node; 24 | 25 | #define BUF_LENGTH 128 /* Buffer for the incoming command. */ 26 | static bool do_echo = true; 27 | static unsigned long lastMillis = 0; 28 | 29 | #define NUM_STAT_REG 26 30 | uint16_t data[NUM_STAT_REG] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; 31 | 32 | #ifdef OLED_DISPLAY 33 | void u8g_prepare(void) { 34 | u8g.setFont(u8g_font_6x10); 35 | u8g.setFontRefHeightExtendedText(); 36 | u8g.setDefaultForegroundColor(); 37 | u8g.setFontPosTop(); 38 | } 39 | 40 | #define NUM_COLUMNS 5 41 | 42 | void draw(void) { 43 | int z,i; 44 | char buf[80]; 45 | u8g_prepare(); 46 | u8g.drawStr( 0, 0, "Sabvoton CL-Interface"); 47 | for (z=1;z<=NUM_COLUMNS;z++) { 48 | for (i=0;i : writeSingleRegister\r\n" 68 | "read : readHoldingRegister\r\n" 69 | "dump : try to read all registers in a range\r\n" 70 | "test : write incremental values to a single register\r\n" 71 | "echo : set echo off (0) or on (1)")); 72 | } else if (strcmp_P(command, PSTR("write")) == 0) { 73 | int reg = atoi(strsep(&cmdline, " ")); 74 | if (reg == 0 || strlen(cmdline)==0) { 75 | Serial.print(F("error: invalid command: ")); 76 | Serial.println(command); 77 | Serial.println("usage: write "); 78 | return; 79 | } 80 | int val = atoi(cmdline); 81 | int result = node.writeSingleRegister(reg, val); 82 | if (result != node.ku8MBSuccess) result = node.writeSingleRegister(reg, val); 83 | if (result == node.ku8MBSuccess) 84 | { 85 | sprintf(buf,"register %d set to %d (0x%04x)",reg, val, val); 86 | Serial.println(buf); 87 | } else { 88 | sprintf(buf,"write error: %02x", result); 89 | Serial.println(buf); 90 | } 91 | } else if (strcmp_P(command, PSTR("read")) == 0) { 92 | int reg = atoi(cmdline); 93 | if (reg == 0) { 94 | Serial.print(F("error: invalid command: ")); 95 | Serial.println(command); 96 | Serial.println("usage: read "); 97 | return; 98 | } 99 | int result = node.readHoldingRegisters(reg, 1); 100 | if (result != node.ku8MBSuccess) result = node.readHoldingRegisters(reg, 1); 101 | if (result == node.ku8MBSuccess) 102 | { 103 | int r = node.getResponseBuffer(0); 104 | float rf = ((float)r)/SINGLEFLOAT; 105 | int vk = (int) rf; 106 | int nk = (int)((rf - ((float)vk)*SINGLEFLOAT)*100); 107 | float rdf = ((float)r)/DOUBLEFLOAT; 108 | int vdk = (int) rdf; 109 | int ndk = (int)((rdf - ((float)vdk)*DOUBLEFLOAT)*100); 110 | sprintf(buf,"register %d: %d (0x%04x %d.%d %d.%d)",reg, r,r,vk,nk,vdk, ndk); 111 | Serial.println(buf); 112 | } else { 113 | sprintf(buf,"read error: %02x", result); 114 | Serial.println(buf); 115 | } 116 | } else if (strcmp_P(command, PSTR("dump")) == 0) { 117 | int reg1 = atoi(strsep(&cmdline, " ")); 118 | int reg2 = atoi(cmdline); 119 | if (reg1 == 0 || reg2==0 || reg1>reg2) { 120 | Serial.print(F("error: invalid command: ")); 121 | Serial.println(command); 122 | Serial.println("usage: dump "); 123 | return; 124 | } 125 | int j; 126 | for (j=reg1; j<=reg2;j++) { 127 | int result = node.readHoldingRegisters(j, 1); 128 | if (result != node.ku8MBSuccess) result = node.readHoldingRegisters(j, 1); 129 | if (result == node.ku8MBSuccess) 130 | { 131 | int r = node.getResponseBuffer(0); 132 | float rf = ((float)r)/SINGLEFLOAT; 133 | int vk = (int) rf; 134 | int nk = (int)((rf - ((float)vk)*SINGLEFLOAT)*100); 135 | float rdf = ((float)r)/DOUBLEFLOAT; 136 | int vdk = (int) rdf; 137 | int ndk = (int)((rdf - ((float)vdk)*DOUBLEFLOAT)*100); 138 | sprintf(buf,"%04d: %d (0x%04x %d.%d %d.%d)",j,r,r,vk,nk,vdk,ndk); 139 | Serial.println(buf); 140 | } else { 141 | //sprintf(buf,"%04d: error",j); 142 | //Serial.println(buf); 143 | } 144 | } 145 | } else if (strcmp_P(command, PSTR("test")) == 0) { 146 | int reg = atoi(strsep(&cmdline, " ")); 147 | if (reg == 0 || strlen(cmdline)==0) { 148 | Serial.print(F("error: invalid command: ")); 149 | Serial.println(command); 150 | Serial.println("usage: write test