├── images ├── pwm_analyze.png ├── pushpull_fet.png ├── arduinouno_l298n_connect.jpg └── arduinouno_l298n_rotate45.gif ├── library.properties ├── keywords.txt ├── library.json ├── LICENSE ├── example ├── ContinuousDrive │ └── ContinuousDrive.ino ├── ServoDrive │ └── ServoDrive.ino ├── DualMotorEsp32_FreeRTOS │ └── DualMotorEsp32_FreeRTOS.ino ├── DualMotor │ └── DualMotor.ino ├── DualMotorEsp32 │ └── DualMotorEsp32.ino └── TripleMotorEsp8266 │ └── TripleMotorEsp8266.ino ├── .gitignore ├── README.md └── UcnBrushlessDCMotorPWM.h /images/pwm_analyze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usefullcodenet/UcnBrushlessDCMotorPWM/HEAD/images/pwm_analyze.png -------------------------------------------------------------------------------- /images/pushpull_fet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usefullcodenet/UcnBrushlessDCMotorPWM/HEAD/images/pushpull_fet.png -------------------------------------------------------------------------------- /images/arduinouno_l298n_connect.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usefullcodenet/UcnBrushlessDCMotorPWM/HEAD/images/arduinouno_l298n_connect.jpg -------------------------------------------------------------------------------- /images/arduinouno_l298n_rotate45.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/usefullcodenet/UcnBrushlessDCMotorPWM/HEAD/images/arduinouno_l298n_rotate45.gif -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=UcnBrushlessDCMotorPWM 2 | version=1.2 3 | license=MIT 4 | author=usefullcode.net 5 | maintainer=usefullcode.net 6 | sentence=Brushless DC motor(BLDC) drive like as servo motor 7 | paragraph=Support Arduino UNO(ATMEGA328P), STM32, ESP32, ESP8266. Support motor driver is MOS-FET sitch, DRV8313, L298N and so on. 8 | category=Device Control 9 | url=https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM/ 10 | repository=https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM.git 11 | architectures=* 12 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | #xxxxxx KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | SetPower KEYWORD2 16 | SetAbortFlag KEYWORD2 17 | ClearAbortFlag KEYWORD2 18 | DoRotate KEYWORD2 19 | DoRotateLoop KEYWORD2 20 | calcRequireStepCount KEYWORD2 21 | suspend KEYWORD2 22 | 23 | ####################################### 24 | # Constants (LITERAL1) 25 | ####################################### 26 | 27 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UcnBrushlessDCMotorPWM", 3 | "keywords": "brushless dc motor, BLDC, ESP32, ESP8266, DRV8313, L298N, servo, gimbal", 4 | "description": "Brushless DC motor(BLDC) drive like as servo motor (MOS-FET, DRV8313, L298N etc)", 5 | "repository": 6 | { 7 | "type": "git", 8 | "url": "https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM.git" 9 | }, 10 | "authors": 11 | [ 12 | { 13 | "name": "usefullcode.net", 14 | "email": "usefullcode@gmail.com", 15 | "url": "https://www.usefullcode.net/", 16 | "maintainer": true 17 | } 18 | ], 19 | "license": "MIT", 20 | "version": "1.2", 21 | "downloadUrl": "https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM/archive/v1.2.zip", 22 | "frameworks": "arduino", 23 | "platforms": "*" 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 usefullcode.net 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/ContinuousDrive/ContinuousDrive.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // UcnBrushlessDCMotorPWM example 4 | // 5 | // Arduino library for driving brushless DC motor like as servo motor 6 | // 7 | // 8 | // https://usefullcode.net/ 9 | // https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM 10 | // 11 | // Copyright (c) 2020 usefullcode.net 12 | // 13 | // MIT License (MIT) 14 | // 15 | ////////////////////////////////////////////////////////////////////////// 16 | // 17 | //# Abstruct 18 | // 19 | // This sample code show how to drive brushless DC motor with continous rotation. 20 | // 21 | // 22 | //# Prepare 23 | // 24 | //- MPU 25 | // - Arduino UNO board (ATMEGA328P) 26 | // - http://s.click.aliexpress.com/e/_dTG6WHQ 27 | // 28 | //- Motor driver 29 | // - L298N motor driver module 30 | // - http://s.click.aliexpress.com/e/_dVlgCao 31 | // 32 | //- Brushless DC motor 33 | // - DYS GM60-80T(24N22P) gimbal motor 34 | // - http://s.click.aliexpress.com/e/_d6vn8wY 35 | // 36 | //- External battery 37 | // - 5V mobile battery 38 | // 39 | // 40 | //# Connection 41 | // 42 | // Arduino UNO 9pin -> L298N modle IN1 43 | // Arduino UNO 10pin -> L298N modle IN2 44 | // Arduino UNO 11pin -> L298N modle IN3 45 | // 46 | // L298N modle OUT1 -> GM60-80T U 47 | // L298N modle OUT2 -> GM60-80T V 48 | // L298N modle OUT3 -> GM60-80T W 49 | // 50 | // mobile battery 5V -> L298N modle 5V 51 | // mobile battery 5V -> L298N modle VIN 52 | // mobile battery GND -> L298N modle GND 53 | // 54 | // mobile battery GND -> Arduino UNO GND 55 | // 56 | // *L298N modle ENA/ENB jumpers are closed 57 | // 58 | // 59 | //# ATTENTION 60 | // 61 | // The brushless DC motor needs a large current. Be sure to use ampere meter. 62 | // Mobile battery with built-in safety circuit is recommended for the motor power supply, 63 | // and USB current meter is useful. 64 | // 65 | // USB current meter http://s.click.aliexpress.com/e/_dZpiddS 66 | // 67 | 68 | 69 | #include 70 | 71 | 72 | UcnBrushlessDCMotorPWM _bldc; 73 | 74 | //PWM output pin for BLDC driver 75 | #define BLDC_DRV_IN1 9 76 | #define BLDC_DRV_IN2 10 77 | #define BLDC_DRV_IN3 11 78 | 79 | //(option) ENABLE pin for BLDC driver 80 | #define BLDC_DRV_EN1 -1 //4 81 | #define BLDC_DRV_EN2 -1 //5 82 | #define BLDC_DRV_EN3 -1 //6 83 | 84 | //Pole count of BLDC motor 85 | //#define BLDC_MOTOR_POLE 14 //12N14P 86 | #define BLDC_MOTOR_POLE 22 //24N22P 87 | //#define BLDC_MOTOR_POLE 26 //24N26P 88 | //#define BLDC_MOTOR_POLE 28 //24N28P 89 | //#define BLDC_MOTOR_POLE 32 //24N32P 90 | 91 | 92 | void setup() 93 | { 94 | _bldc.begin(BLDC_MOTOR_POLE, BLDC_DRV_IN1, BLDC_DRV_IN2, BLDC_DRV_IN3, BLDC_DRV_EN1, BLDC_DRV_EN2, BLDC_DRV_EN3); 95 | 96 | _bldc.SetPower(80); //motor power 80% 97 | } 98 | 99 | void loop() 100 | { 101 | // continuos rotation 102 | _bldc.DoRotate(1); 103 | delayMicroseconds(3000); 104 | } 105 | 106 | 107 | -------------------------------------------------------------------------------- /example/ServoDrive/ServoDrive.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // UcnBrushlessDCMotorPWM example 4 | // 5 | // Arduino library for driving brushless DC motor like as servo motor 6 | // 7 | // 8 | // https://usefullcode.net/ 9 | // https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM 10 | // 11 | // Copyright (c) 2020 usefullcode.net 12 | // 13 | // MIT License (MIT) 14 | // 15 | ////////////////////////////////////////////////////////////////////////// 16 | // 17 | //# Abstruct 18 | // 19 | // This sample code show how to drive brushless DC motor with 180 degree rotation. 20 | // 21 | // 22 | //# Prepare 23 | // 24 | //- MPU 25 | // - Arduino UNO board (ATMEGA328P) 26 | // - http://s.click.aliexpress.com/e/_dTG6WHQ 27 | // 28 | //- Motor driver 29 | // - L298N motor driver module 30 | // - http://s.click.aliexpress.com/e/_dVlgCao 31 | // 32 | //- Brushless DC motor 33 | // - DYS GM60-80T(24N22P) gimbal motor 34 | // - http://s.click.aliexpress.com/e/_d6vn8wY 35 | // 36 | //- External battery 37 | // - 5V mobile battery 38 | // 39 | // 40 | //# Connection 41 | // 42 | // Arduino UNO 9pin -> L298N modle IN1 43 | // Arduino UNO 10pin -> L298N modle IN2 44 | // Arduino UNO 11pin -> L298N modle IN3 45 | // 46 | // L298N modle OUT1 -> GM60-80T U 47 | // L298N modle OUT2 -> GM60-80T V 48 | // L298N modle OUT3 -> GM60-80T W 49 | // 50 | // mobile battery 5V -> L298N modle 5V 51 | // mobile battery 5V -> L298N modle VIN 52 | // mobile battery GND -> L298N modle GND 53 | // 54 | // mobile battery GND -> Arduino UNO GND 55 | // 56 | // *L298N modle ENA/ENB jumpers are closed 57 | // 58 | // 59 | //# ATTENTION 60 | // 61 | // The brushless DC motor needs a large current. Be sure to use ampere meter. 62 | // Mobile battery with built-in safety circuit is recommended for the motor power supply, 63 | // and USB current meter is useful. 64 | // 65 | // USB current meter http://s.click.aliexpress.com/e/_dZpiddS 66 | // 67 | 68 | 69 | #include 70 | 71 | 72 | UcnBrushlessDCMotorPWM _bldc; 73 | 74 | //PWM output pin for BLDC driver 75 | #define BLDC_DRV_IN1 9 76 | #define BLDC_DRV_IN2 10 77 | #define BLDC_DRV_IN3 11 78 | 79 | //(option) ENABLE pin for BLDC driver 80 | #define BLDC_DRV_EN1 -1 //4 81 | #define BLDC_DRV_EN2 -1 //5 82 | #define BLDC_DRV_EN3 -1 //6 83 | 84 | //Pole count of BLDC motor 85 | //#define BLDC_MOTOR_POLE 14 //12N14P 86 | #define BLDC_MOTOR_POLE 22 //24N22P 87 | //#define BLDC_MOTOR_POLE 26 //24N26P 88 | //#define BLDC_MOTOR_POLE 28 //24N28P 89 | //#define BLDC_MOTOR_POLE 32 //24N32P 90 | 91 | 92 | void setup() 93 | { 94 | _bldc.begin(BLDC_MOTOR_POLE, BLDC_DRV_IN1, BLDC_DRV_IN2, BLDC_DRV_IN3, BLDC_DRV_EN1, BLDC_DRV_EN2, BLDC_DRV_EN3); 95 | 96 | _bldc.SetPower(80); //motor power 80% 97 | } 98 | 99 | void loop() 100 | { 101 | //180 degree rotation with 3000 usec delay loop 102 | _bldc.DoRotateLoop(180, 3000); 103 | 104 | //180 degree inverse rotation with 3000 usec delay loop 105 | _bldc.DoRotateLoop(-180, 3000); 106 | } 107 | 108 | -------------------------------------------------------------------------------- /example/DualMotorEsp32_FreeRTOS/DualMotorEsp32_FreeRTOS.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // UcnBrushlessDCMotorPWM example 4 | // 5 | // Arduino library for driving brushless DC motor like as servo motor 6 | // 7 | // 8 | // https://usefullcode.net/ 9 | // https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM 10 | // 11 | // Copyright (c) 2020 usefullcode.net 12 | // 13 | // MIT License (MIT) 14 | // 15 | ////////////////////////////////////////////////////////////////////////// 16 | // 17 | //# Abstruct 18 | // 19 | // This sample code show how to drive two brushless DC motors. 20 | // 21 | // 22 | //# Prepare 23 | // 24 | //- MPU 25 | // - ESP-WROOM-32 (ESP32) 26 | // - http://s.click.aliexpress.com/e/_dVmyc4c 27 | // 28 | //- Motor driver (2pcs) 29 | // - L298N motor driver module 30 | // - http://s.click.aliexpress.com/e/_dVlgCao 31 | // 32 | //- Brushless DC motor 1 33 | // - DYS GM60-80T(24N22P) gimbal motor 34 | // - http://s.click.aliexpress.com/e/_d6vn8wY 35 | // 36 | //- Brushless DC motor 2 37 | // - EMAX MT2204-2300KV(12N14P) drone motor 38 | // - http://s.click.aliexpress.com/e/_dXdxFgg 39 | // 40 | //- External battery 41 | // - 5V mobile battery 42 | // 43 | // 44 | //# Connection 45 | // 46 | // ESP-WROOM-32 IO 25 -> L298N modle 1 IN1 47 | // ESP-WROOM-32 IO 26 -> L298N modle 1 IN2 48 | // ESP-WROOM-32 IO 27 -> L298N modle 1 IN3 49 | // 50 | // L298N modle 1 OUT1 -> GM60-80T U 51 | // L298N modle 1 OUT2 -> GM60-80T V 52 | // L298N modle 1 OUT3 -> GM60-80T W 53 | // 54 | // mobile battery 5V -> L298N modle 1 5V 55 | // mobile battery 5V -> L298N modle 1 VIN 56 | // mobile battery GND -> L298N modle 1 GND 57 | // 58 | // ESP-WROOM-32 IO 12 -> L298N modle 2 IN1 59 | // ESP-WROOM-32 IO 13 -> L298N modle 2 IN2 60 | // ESP-WROOM-32 IO 14 -> L298N modle 2 IN3 61 | // 62 | // L298N modle 2 OUT1 -> MT2204-2300KV U 63 | // L298N modle 2 OUT2 -> MT2204-2300KV V 64 | // L298N modle 2 OUT3 -> MT2204-2300KV W 65 | // 66 | // mobile battery 5V -> L298N modle 2 5V 67 | // mobile battery 5V -> L298N modle 2 VIN 68 | // mobile battery GND -> L298N modle 2 GND 69 | // 70 | // mobile battery GND -> ESP-WROOM-32 GND 71 | // 72 | // *Both L298N modles' ENA/ENB jumpers are closed 73 | // 74 | // 75 | //# ATTENTION 76 | // 77 | // The brushless DC motor needs a large current. Be sure to use ampere meter. 78 | // Mobile battery with built-in safety circuit is recommended for the motor power supply, 79 | // and USB current meter is useful. 80 | // 81 | // USB current meter http://s.click.aliexpress.com/e/_dZpiddS 82 | // 83 | 84 | 85 | 86 | 87 | #include 88 | 89 | 90 | UcnBrushlessDCMotorPWM _bldc1(0, 1, 2); // use PWM channel 0/1/2 91 | UcnBrushlessDCMotorPWM _bldc2(3, 4, 5); // use PWM channel 3/4/5 92 | 93 | //PWM output pin for BLDC driver 94 | #define BLDC1_DRV_IN1 25 95 | #define BLDC1_DRV_IN2 26 96 | #define BLDC1_DRV_IN3 27 97 | 98 | //PWM output pin for BLDC driver 99 | #define BLDC2_DRV_IN1 12 100 | #define BLDC2_DRV_IN2 13 101 | #define BLDC2_DRV_IN3 14 102 | 103 | 104 | //Pole count of BLDC motor 105 | #define BLDC1_MOTOR_POLE 22 //24N22P 106 | #define BLDC2_MOTOR_POLE 14 //12N14P 107 | 108 | 109 | 110 | 111 | void TaskBldc(void *pParam) 112 | { 113 | _bldc2.begin(BLDC2_MOTOR_POLE, BLDC2_DRV_IN1, BLDC2_DRV_IN2, BLDC2_DRV_IN3); 114 | _bldc2.SetPower(50); //motor power 50% 115 | 116 | while(true) 117 | { 118 | _bldc2.DoRotateLoop(90, 500); 119 | _bldc2.DoRotateLoop(-90, 500); 120 | } 121 | } 122 | 123 | void setup() 124 | { 125 | TaskHandle_t th; 126 | xTaskCreatePinnedToCore(TaskBldc, "TaskBldc", 2048, NULL, 5, &th, 1); //set core ID 127 | 128 | 129 | _bldc1.begin(BLDC1_MOTOR_POLE, BLDC1_DRV_IN1, BLDC1_DRV_IN2, BLDC1_DRV_IN3); 130 | _bldc1.SetPower(80); //motor power 80% 131 | } 132 | 133 | void loop() 134 | { 135 | _bldc1.DoRotateLoop(180, 1000); 136 | _bldc1.DoRotateLoop(-180, 1000); 137 | } 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /example/DualMotor/DualMotor.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // UcnBrushlessDCMotorPWM example 4 | // 5 | // Arduino library for driving brushless DC motor like as servo motor 6 | // 7 | // 8 | // https://usefullcode.net/ 9 | // https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM 10 | // 11 | // Copyright (c) 2020 usefullcode.net 12 | // 13 | // MIT License (MIT) 14 | // 15 | ////////////////////////////////////////////////////////////////////////// 16 | // 17 | //# Abstruct 18 | // 19 | // This sample code show how to drive two brushless DC motors. 20 | // 21 | // 22 | //# Prepare 23 | // 24 | //- MPU 25 | // - Arduino UNO board (ATMEGA328P) 26 | // - http://s.click.aliexpress.com/e/_dTG6WHQ 27 | // 28 | //- Motor driver (2pcs) 29 | // - L298N motor driver module 30 | // - http://s.click.aliexpress.com/e/_dVlgCao 31 | // 32 | //- Brushless DC motor 1 33 | // - DYS GM60-80T(24N22P) gimbal motor 34 | // - http://s.click.aliexpress.com/e/_d6vn8wY 35 | // 36 | //- Brushless DC motor 2 37 | // - EMAX MT2204-2300KV(12N14P) drone motor 38 | // - http://s.click.aliexpress.com/e/_dXdxFgg 39 | // 40 | //- External battery 41 | // - 5V mobile battery 42 | // 43 | // 44 | //# Connection 45 | // 46 | // Arduino UNO 3pin -> L298N modle 1 IN1 47 | // Arduino UNO 5pin -> L298N modle 1 IN2 48 | // Arduino UNO 6pin -> L298N modle 1 IN3 49 | // 50 | // L298N modle 1 OUT1 -> GM60-80T U 51 | // L298N modle 1 OUT2 -> GM60-80T V 52 | // L298N modle 1 OUT3 -> GM60-80T W 53 | // 54 | // mobile battery 5V -> L298N modle 1 5V 55 | // mobile battery 5V -> L298N modle 1 VIN 56 | // mobile battery GND -> L298N modle 1 GND 57 | // 58 | // Arduino UNO 9pin -> L298N modle 2 IN1 59 | // Arduino UNO 10pin -> L298N modle 2 IN2 60 | // Arduino UNO 11pin -> L298N modle 2 IN3 61 | // 62 | // L298N modle 2 OUT1 -> MT2204-2300KV U 63 | // L298N modle 2 OUT2 -> MT2204-2300KV V 64 | // L298N modle 2 OUT3 -> MT2204-2300KV W 65 | // 66 | // mobile battery 5V -> L298N modle 2 5V 67 | // mobile battery 5V -> L298N modle 2 VIN 68 | // mobile battery GND -> L298N modle 2 GND 69 | // 70 | // mobile battery GND -> Arduino UNO GND 71 | // 72 | // *Both L298N modles' ENA/ENB jumpers are closed 73 | // 74 | // 75 | //# ATTENTION 76 | // 77 | // The brushless DC motor needs a large current. Be sure to use ampere meter. 78 | // Mobile battery with built-in safety circuit is recommended for the motor power supply, 79 | // and USB current meter is useful. 80 | // 81 | // USB current meter http://s.click.aliexpress.com/e/_dZpiddS 82 | // 83 | 84 | 85 | 86 | 87 | #include 88 | 89 | 90 | UcnBrushlessDCMotorPWM _bldc1; 91 | UcnBrushlessDCMotorPWM _bldc2; 92 | 93 | //PWM output pin for BLDC driver 94 | #define BLDC1_DRV_IN1 3 95 | #define BLDC1_DRV_IN2 5 96 | #define BLDC1_DRV_IN3 6 97 | 98 | //PWM output pin for BLDC driver 99 | #define BLDC2_DRV_IN1 9 100 | #define BLDC2_DRV_IN2 10 101 | #define BLDC2_DRV_IN3 11 102 | 103 | 104 | //Pole count of BLDC motor 105 | #define BLDC1_MOTOR_POLE 22 //24N22P 106 | #define BLDC2_MOTOR_POLE 14 //12N14P 107 | 108 | 109 | void setup() 110 | { 111 | _bldc1.begin(BLDC1_MOTOR_POLE, BLDC1_DRV_IN1, BLDC1_DRV_IN2, BLDC1_DRV_IN3); 112 | _bldc1.SetPower(80); //motor power 80% 113 | 114 | _bldc2.begin(BLDC2_MOTOR_POLE, BLDC2_DRV_IN1, BLDC2_DRV_IN2, BLDC2_DRV_IN3); 115 | _bldc2.SetPower(40); //motor power 40% 116 | } 117 | 118 | 119 | uint32_t _nBldcRequreStep1 = 0; 120 | int8_t _nBldcStep1 = 1; 121 | 122 | uint32_t _nBldcRequreStep2 = 0; 123 | int8_t _nBldcStep2 = 1; 124 | 125 | void loop() 126 | { 127 | if (_nBldcRequreStep1 == 0) 128 | { 129 | _nBldcRequreStep1 = _bldc1.calcRequireStepCount(90); 130 | _nBldcStep1 = -_nBldcStep1; 131 | } 132 | 133 | if (_nBldcRequreStep2 == 0) 134 | { 135 | _nBldcRequreStep2 = _bldc2.calcRequireStepCount(180); 136 | _nBldcStep2 = -_nBldcStep2; 137 | } 138 | 139 | _bldc1.DoRotate(_nBldcStep1); 140 | _bldc2.DoRotate(_nBldcStep2); 141 | 142 | _nBldcRequreStep1--; 143 | _nBldcRequreStep2--; 144 | 145 | delayMicroseconds(500); 146 | } 147 | 148 | 149 | -------------------------------------------------------------------------------- /example/DualMotorEsp32/DualMotorEsp32.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // UcnBrushlessDCMotorPWM example 4 | // 5 | // Arduino library for driving brushless DC motor like as servo motor 6 | // 7 | // 8 | // https://usefullcode.net/ 9 | // https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM 10 | // 11 | // Copyright (c) 2020 usefullcode.net 12 | // 13 | // MIT License (MIT) 14 | // 15 | ////////////////////////////////////////////////////////////////////////// 16 | // 17 | //# Abstruct 18 | // 19 | // This sample code show how to drive two brushless DC motors. 20 | // 21 | // 22 | //# Prepare 23 | // 24 | //- MPU 25 | // - ESP-WROOM-32 (ESP32) 26 | // - http://s.click.aliexpress.com/e/_dVmyc4c 27 | // 28 | //- Motor driver (2pcs) 29 | // - L298N motor driver module 30 | // - http://s.click.aliexpress.com/e/_dVlgCao 31 | // 32 | //- Brushless DC motor 1 33 | // - DYS GM60-80T(24N22P) gimbal motor 34 | // - http://s.click.aliexpress.com/e/_d6vn8wY 35 | // 36 | //- Brushless DC motor 2 37 | // - EMAX MT2204-2300KV(12N14P) drone motor 38 | // - http://s.click.aliexpress.com/e/_dXdxFgg 39 | // 40 | //- External battery 41 | // - 5V mobile battery 42 | // 43 | // 44 | //# Connection 45 | // 46 | // ESP-WROOM-32 IO 0 -> L298N modle 1 IN1 47 | // ESP-WROOM-32 IO 2 -> L298N modle 1 IN2 48 | // ESP-WROOM-32 IO 15 -> L298N modle 1 IN3 49 | // 50 | // L298N modle 1 OUT1 -> GM60-80T U 51 | // L298N modle 1 OUT2 -> GM60-80T V 52 | // L298N modle 1 OUT3 -> GM60-80T W 53 | // 54 | // mobile battery 5V -> L298N modle 1 5V 55 | // mobile battery 5V -> L298N modle 1 VIN 56 | // mobile battery GND -> L298N modle 1 GND 57 | // 58 | // ESP-WROOM-32 IO 12 -> L298N modle 2 IN1 59 | // ESP-WROOM-32 IO 14 -> L298N modle 2 IN2 60 | // ESP-WROOM-32 IO 27 -> L298N modle 2 IN3 61 | // 62 | // L298N modle 2 OUT1 -> MT2204-2300KV U 63 | // L298N modle 2 OUT2 -> MT2204-2300KV V 64 | // L298N modle 2 OUT3 -> MT2204-2300KV W 65 | // 66 | // mobile battery 5V -> L298N modle 2 5V 67 | // mobile battery 5V -> L298N modle 2 VIN 68 | // mobile battery GND -> L298N modle 2 GND 69 | // 70 | // mobile battery GND -> ESP-WROOM-32 GND 71 | // 72 | // *Both L298N modles' ENA/ENB jumpers are closed 73 | // 74 | // 75 | //# ATTENTION 76 | // 77 | // The brushless DC motor needs a large current. Be sure to use ampere meter. 78 | // Mobile battery with built-in safety circuit is recommended for the motor power supply, 79 | // and USB current meter is useful. 80 | // 81 | // USB current meter http://s.click.aliexpress.com/e/_dZpiddS 82 | // 83 | 84 | 85 | 86 | 87 | #include 88 | 89 | 90 | UcnBrushlessDCMotorPWM _bldc1(0, 1, 2); // use PWM channel 0/1/2 91 | UcnBrushlessDCMotorPWM _bldc2(3, 4, 5); // use PWM channel 3/4/5 92 | 93 | //PWM output pin for BLDC driver 94 | #define BLDC1_DRV_IN1 0 95 | #define BLDC1_DRV_IN2 2 96 | #define BLDC1_DRV_IN3 15 97 | 98 | //PWM output pin for BLDC driver 99 | #define BLDC2_DRV_IN1 12 100 | #define BLDC2_DRV_IN2 14 101 | #define BLDC2_DRV_IN3 27 102 | 103 | 104 | //Pole count of BLDC motor 105 | #define BLDC1_MOTOR_POLE 22 //24N22P 106 | #define BLDC2_MOTOR_POLE 14 //12N14P 107 | 108 | 109 | void setup() 110 | { 111 | _bldc1.begin(BLDC1_MOTOR_POLE, BLDC1_DRV_IN1, BLDC1_DRV_IN2, BLDC1_DRV_IN3); 112 | _bldc1.SetPower(80); //motor power 80% 113 | 114 | _bldc2.begin(BLDC2_MOTOR_POLE, BLDC2_DRV_IN1, BLDC2_DRV_IN2, BLDC2_DRV_IN3); 115 | _bldc2.SetPower(40); //motor power 40% 116 | } 117 | 118 | 119 | uint32_t _nBldcRequreStep1 = 0; 120 | int8_t _nBldcStep1 = 1; 121 | 122 | uint32_t _nBldcRequreStep2 = 0; 123 | int8_t _nBldcStep2 = 1; 124 | 125 | void loop() 126 | { 127 | if (_nBldcRequreStep1 == 0) 128 | { 129 | _nBldcRequreStep1 = _bldc1.calcRequireStepCount(90); 130 | _nBldcStep1 = -_nBldcStep1; 131 | } 132 | 133 | if (_nBldcRequreStep2 == 0) 134 | { 135 | _nBldcRequreStep2 = _bldc2.calcRequireStepCount(180); 136 | _nBldcStep2 = -_nBldcStep2; 137 | } 138 | 139 | _bldc1.DoRotate(_nBldcStep1); 140 | _bldc2.DoRotate(_nBldcStep2); 141 | 142 | _nBldcRequreStep1--; 143 | _nBldcRequreStep2--; 144 | 145 | delayMicroseconds(500); 146 | } 147 | 148 | 149 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | .gitconfig 13 | 14 | # Build results 15 | [Dd]ebug/ 16 | [Dd]ebugPublic/ 17 | [Rr]elease/ 18 | [Rr]eleases/ 19 | x64/ 20 | x86/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | [Ll]og/ 25 | 26 | # Visual Studio 2015 cache/options directory 27 | .vs/ 28 | # Uncomment if you have tasks that create the project's static files in wwwroot 29 | #wwwroot/ 30 | 31 | # MSTest test Results 32 | [Tt]est[Rr]esult*/ 33 | [Bb]uild[Ll]og.* 34 | 35 | # NUNIT 36 | *.VisualState.xml 37 | TestResult.xml 38 | 39 | # Build Results of an ATL Project 40 | [Dd]ebugPS/ 41 | [Rr]eleasePS/ 42 | dlldata.c 43 | 44 | # DNX 45 | project.lock.json 46 | project.fragment.lock.json 47 | artifacts/ 48 | 49 | *_i.c 50 | *_p.c 51 | *_i.h 52 | *.ilk 53 | *.meta 54 | *.obj 55 | *.pch 56 | *.pdb 57 | *.pgc 58 | *.pgd 59 | *.rsp 60 | *.sbr 61 | *.tlb 62 | *.tli 63 | *.tlh 64 | *.tmp 65 | *.tmp_proj 66 | *.log 67 | *.vspscc 68 | *.vssscc 69 | .builds 70 | *.pidb 71 | *.svclog 72 | *.scc 73 | 74 | # Chutzpah Test files 75 | _Chutzpah* 76 | 77 | # Visual C++ cache files 78 | ipch/ 79 | *.aps 80 | *.ncb 81 | *.opendb 82 | *.opensdf 83 | *.sdf 84 | *.cachefile 85 | *.VC.db 86 | *.VC.VC.opendb 87 | 88 | # Visual Studio profiler 89 | *.psess 90 | *.vsp 91 | *.vspx 92 | *.sap 93 | 94 | # TFS 2012 Local Workspace 95 | $tf/ 96 | 97 | # Guidance Automation Toolkit 98 | *.gpState 99 | 100 | # ReSharper is a .NET coding add-in 101 | _ReSharper*/ 102 | *.[Rr]e[Ss]harper 103 | *.DotSettings.user 104 | 105 | # JustCode is a .NET coding add-in 106 | .JustCode 107 | 108 | # TeamCity is a build add-in 109 | _TeamCity* 110 | 111 | # DotCover is a Code Coverage Tool 112 | *.dotCover 113 | 114 | # NCrunch 115 | _NCrunch_* 116 | .*crunch*.local.xml 117 | nCrunchTemp_* 118 | 119 | # MightyMoose 120 | *.mm.* 121 | AutoTest.Net/ 122 | 123 | # Web workbench (sass) 124 | .sass-cache/ 125 | 126 | # Installshield output folder 127 | [Ee]xpress/ 128 | 129 | # DocProject is a documentation generator add-in 130 | DocProject/buildhelp/ 131 | DocProject/Help/*.HxT 132 | DocProject/Help/*.HxC 133 | DocProject/Help/*.hhc 134 | DocProject/Help/*.hhk 135 | DocProject/Help/*.hhp 136 | DocProject/Help/Html2 137 | DocProject/Help/html 138 | 139 | # Click-Once directory 140 | publish/ 141 | 142 | # Publish Web Output 143 | *.[Pp]ublish.xml 144 | *.azurePubxml 145 | # TODO: Comment the next line if you want to checkin your web deploy settings 146 | # but database connection strings (with potential passwords) will be unencrypted 147 | #*.pubxml 148 | *.publishproj 149 | 150 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 151 | # checkin your Azure Web App publish settings, but sensitive information contained 152 | # in these scripts will be unencrypted 153 | PublishScripts/ 154 | 155 | # NuGet Packages 156 | *.nupkg 157 | # The packages folder can be ignored because of Package Restore 158 | **/packages/* 159 | # except build/, which is used as an MSBuild target. 160 | !**/packages/build/ 161 | # Uncomment if necessary however generally it will be regenerated when needed 162 | #!**/packages/repositories.config 163 | # NuGet v3's project.json files produces more ignoreable files 164 | *.nuget.props 165 | *.nuget.targets 166 | 167 | # Microsoft Azure Build Output 168 | csx/ 169 | *.build.csdef 170 | 171 | # Microsoft Azure Emulator 172 | ecf/ 173 | rcf/ 174 | 175 | # Windows Store app package directories and files 176 | AppPackages/ 177 | BundleArtifacts/ 178 | Package.StoreAssociation.xml 179 | _pkginfo.txt 180 | 181 | # Visual Studio cache files 182 | # files ending in .cache can be ignored 183 | *.[Cc]ache 184 | # but keep track of directories ending in .cache 185 | !*.[Cc]ache/ 186 | 187 | # Others 188 | ClientBin/ 189 | ~$* 190 | *~ 191 | *.dbmdl 192 | *.dbproj.schemaview 193 | *.jfm 194 | *.pfx 195 | *.publishsettings 196 | node_modules/ 197 | orleans.codegen.cs 198 | 199 | # Since there are multiple workflows, uncomment next line to ignore bower_components 200 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 201 | #bower_components/ 202 | 203 | # RIA/Silverlight projects 204 | Generated_Code/ 205 | 206 | # Backup & report files from converting an old project file 207 | # to a newer Visual Studio version. Backup files are not needed, 208 | # because we have git ;-) 209 | _UpgradeReport_Files/ 210 | Backup*/ 211 | UpgradeLog*.XML 212 | UpgradeLog*.htm 213 | 214 | # SQL Server files 215 | *.mdf 216 | *.ldf 217 | 218 | # Business Intelligence projects 219 | *.rdl.data 220 | *.bim.layout 221 | *.bim_*.settings 222 | 223 | # Microsoft Fakes 224 | FakesAssemblies/ 225 | 226 | # GhostDoc plugin setting file 227 | *.GhostDoc.xml 228 | 229 | # Node.js Tools for Visual Studio 230 | .ntvs_analysis.dat 231 | 232 | # Visual Studio 6 build log 233 | *.plg 234 | 235 | # Visual Studio 6 workspace options file 236 | *.opt 237 | 238 | # Visual Studio LightSwitch build output 239 | **/*.HTMLClient/GeneratedArtifacts 240 | **/*.DesktopClient/GeneratedArtifacts 241 | **/*.DesktopClient/ModelManifest.xml 242 | **/*.Server/GeneratedArtifacts 243 | **/*.Server/ModelManifest.xml 244 | _Pvt_Extensions 245 | 246 | # Paket dependency manager 247 | .paket/paket.exe 248 | paket-files/ 249 | 250 | # FAKE - F# Make 251 | .fake/ 252 | 253 | # JetBrains Rider 254 | .idea/ 255 | *.sln.iml 256 | 257 | # CodeRush 258 | .cr/ 259 | 260 | # Python Tools for Visual Studio (PTVS) 261 | __pycache__/ 262 | *.pyc -------------------------------------------------------------------------------- /example/TripleMotorEsp8266/TripleMotorEsp8266.ino: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // UcnBrushlessDCMotorPWM example 4 | // 5 | // Arduino library for driving brushless DC motor like as servo motor 6 | // 7 | // 8 | // https://usefullcode.net/ 9 | // https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM 10 | // 11 | // Copyright (c) 2020 usefullcode.net 12 | // 13 | // MIT License (MIT) 14 | // 15 | ////////////////////////////////////////////////////////////////////////// 16 | // 17 | //# Abstruct 18 | // 19 | // This sample code show how to drive three brushless DC motors. 20 | // 21 | // 22 | //# Prepare 23 | // 24 | //- MPU 25 | // - WeMos D1 mini (ESP8266) 26 | // - http://s.click.aliexpress.com/e/_dTOy2L6 27 | // 28 | //- Motor driver (3pcs) 29 | // - L298N motor driver module 30 | // - http://s.click.aliexpress.com/e/_dVlgCao 31 | // 32 | //- Brushless DC motor 1 33 | // - EMAX MT2204-2300KV(12N14P) drone motor 34 | // - http://s.click.aliexpress.com/e/_dXdxFgg 35 | // 36 | //- Brushless DC motor 2 37 | // - EMAX MT2204-2300KV(12N14P) drone motor 38 | // - http://s.click.aliexpress.com/e/_dXdxFgg 39 | // 40 | //- Brushless DC motor 3 41 | // - DYS GM60-80T(24N22P) gimbal motor 42 | // - http://s.click.aliexpress.com/e/_d6vn8wY 43 | // 44 | //- External battery 45 | // - 5V mobile battery 46 | // 47 | // 48 | //# Connection 49 | // 50 | // WeMos D1 mini D1 -> L298N modle 1 IN1 51 | // WeMos D1 mini D2 -> L298N modle 1 IN2 52 | // WeMos D1 mini D3 -> L298N modle 1 IN3 53 | // 54 | // mobile battery 5V -> L298N modle 1 5V 55 | // mobile battery 5V -> L298N modle 1 VIN 56 | // mobile battery GND -> L298N modle 1 GND 57 | // 58 | // L298N modle 1 OUT1 -> MT2204-2300KV U 59 | // L298N modle 1 OUT2 -> MT2204-2300KV V 60 | // L298N modle 1 OUT3 -> MT2204-2300KV W 61 | // 62 | // 63 | // WeMos D1 mini D0 -> L298N modle 2 IN1 64 | // WeMos D1 mini D5 -> L298N modle 2 IN2 65 | // WeMos D1 mini D6 -> L298N modle 2 IN3 66 | // 67 | // L298N modle 2 OUT1 -> MT2204-2300KV U 68 | // L298N modle 2 OUT2 -> MT2204-2300KV V 69 | // L298N modle 2 OUT3 -> MT2204-2300KV W 70 | // 71 | // mobile battery 5V -> L298N modle 2 5V 72 | // mobile battery 5V -> L298N modle 2 VIN 73 | // mobile battery GND -> L298N modle 2 GND 74 | // 75 | // 76 | // WeMos D1 mini D8 -> L298N modle 3 IN1 77 | // WeMos D1 mini D7 -> L298N modle 3 IN2 78 | // WeMos D1 mini D4 -> L298N modle 3 IN3 79 | // 80 | // L298N modle 3 OUT1 -> GM60-80T U 81 | // L298N modle 3 OUT2 -> GM60-80T V 82 | // L298N modle 3 OUT3 -> GM60-80T W 83 | // 84 | // mobile battery 5V -> L298N modle 3 5V 85 | // mobile battery 5V -> L298N modle 3 VIN 86 | // mobile battery GND -> L298N modle 3 GND 87 | // 88 | // 89 | // mobile battery GND -> Arduino UNO GND 90 | // 91 | // *Both L298N modles' ENA/ENB jumpers are closed 92 | // 93 | // *It may not work due to insufficient current, add mobile battery for each BLDC motor. 94 | // 95 | // 96 | //# ATTENTION 97 | // 98 | // The brushless DC motor needs a large current. Be sure to use ampere meter. 99 | // Mobile battery with built-in safety circuit is recommended for the motor power supply, 100 | // and USB current meter is useful. 101 | // 102 | // USB current meter http://s.click.aliexpress.com/e/_dZpiddS 103 | // 104 | 105 | 106 | 107 | 108 | #include 109 | 110 | 111 | UcnBrushlessDCMotorPWM _bldc1; 112 | UcnBrushlessDCMotorPWM _bldc2; 113 | UcnBrushlessDCMotorPWM _bldc3; 114 | 115 | 116 | #define D0 16 117 | #define D1 5 118 | #define D2 4 119 | #define D3 0 120 | #define D4 2 121 | #define D5 14 122 | #define D6 12 123 | #define D7 13 124 | #define D8 15 125 | 126 | 127 | //PWM output pin for BLDC driver 128 | #define BLDC1_DRV_IN1 D1 129 | #define BLDC1_DRV_IN2 D2 130 | #define BLDC1_DRV_IN3 D3 131 | 132 | //PWM output pin for BLDC driver 133 | #define BLDC2_DRV_IN1 D0 134 | #define BLDC2_DRV_IN2 D5 135 | #define BLDC2_DRV_IN3 D6 136 | 137 | //PWM output pin for BLDC driver 138 | #define BLDC3_DRV_IN1 D8 139 | #define BLDC3_DRV_IN2 D7 140 | #define BLDC3_DRV_IN3 D4 141 | 142 | 143 | //Pole count of BLDC motor 144 | #define BLDC1_MOTOR_POLE 14 //12N14P 145 | #define BLDC2_MOTOR_POLE 14 //12N14P 146 | #define BLDC3_MOTOR_POLE 22 //24N22P 147 | 148 | 149 | 150 | 151 | void setup() 152 | { 153 | _bldc1.begin(BLDC1_MOTOR_POLE, BLDC1_DRV_IN1, BLDC1_DRV_IN2, BLDC1_DRV_IN3, -1, -1, -1, 100); 154 | _bldc1.suspend(); 155 | 156 | _bldc2.begin(BLDC2_MOTOR_POLE, BLDC2_DRV_IN1, BLDC2_DRV_IN2, BLDC2_DRV_IN3, -1, -1, -1, 100); 157 | _bldc2.suspend(); 158 | 159 | _bldc3.begin(BLDC3_MOTOR_POLE, BLDC3_DRV_IN1, BLDC3_DRV_IN2, BLDC3_DRV_IN3); 160 | _bldc3.suspend(); 161 | 162 | _bldc1.SetPower(40); //motor power 40% 163 | _bldc2.SetPower(40); //motor power 40% 164 | _bldc3.SetPower(80); //motor power 80% 165 | } 166 | 167 | 168 | uint32_t _nBldcRequreStep1 = 0; 169 | int8_t _nBldcStep1 = 1; 170 | 171 | uint32_t _nBldcRequreStep2 = 0; 172 | int8_t _nBldcStep2 = 1; 173 | 174 | uint32_t _nBldcRequreStep3 = 0; 175 | int8_t _nBldcStep3 = 1; 176 | 177 | 178 | 179 | void loop() 180 | { 181 | if (_nBldcRequreStep1 == 0) 182 | { 183 | //90 degree rotation for BLDC motor 1 184 | _nBldcRequreStep1 = _bldc1.calcRequireStepCount(90); 185 | _nBldcStep1 = -_nBldcStep1; 186 | } 187 | 188 | if (_nBldcRequreStep2 == 0) 189 | { 190 | //180 degree rotation for BLDC motor 1 191 | _nBldcRequreStep2 = _bldc2.calcRequireStepCount(180); 192 | _nBldcStep2 = -_nBldcStep2; 193 | } 194 | 195 | if (_nBldcRequreStep3 == 0) 196 | { 197 | //360 degree rotation for BLDC motor 1 198 | _nBldcRequreStep3 = _bldc3.calcRequireStepCount(360); 199 | _nBldcStep3 = -_nBldcStep3; 200 | } 201 | 202 | _bldc1.DoRotate(_nBldcStep1); 203 | _bldc2.DoRotate(_nBldcStep2); 204 | _bldc3.DoRotate(_nBldcStep3); 205 | 206 | _nBldcRequreStep1--; 207 | _nBldcRequreStep2--; 208 | _nBldcRequreStep3--; 209 | 210 | delayMicroseconds(3000); 211 | } 212 | 213 | 214 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UcnBrushlessDCMotorPWM 2 | 3 | Arduino library that drives brushless DC motor like servo motor. 4 | 5 | - Arduino library 6 | - Drive brushless DC motor with ATMEGA328P, STM32, ESP32, ESP8266 7 | - Support multiple motors with one MPU 8 | - Support continuous rotation 9 | - Support rotation with angle 10 | - Triple PWM output with sin curve 11 | 12 | ![push-pull](images/pwm_analyze.png) 13 | ![45 degree rotate](images/arduinouno_l298n_rotate45.gif) 14 | 15 | 16 | ## Support MPU 17 | - ATMEGA328P 18 | - Dual motors support 19 | - 31KHz PWM frequency 20 | - STM32 21 | - Multiple motors support 22 | - High PWM frequency 23 | - ESP32 24 | - Multiple motors support 25 | - High PWM frequency 26 | - ESP8266 27 | - Multiple motors support 28 | - Low PWM frequency 29 | - NOT recommended 30 | 31 | ## Support Motor driver 32 | - [L298N](http://s.click.aliexpress.com/e/_d6YWPqk) cheap([price $1.5](http://s.click.aliexpress.com/e/_d6YWPqk)) driver 33 | - Dual Full-Bridge driver IC 34 | - Maximum drive current is 4A(total), 3A(peak) or 2A(continuous) 35 | - Logic supply voltage 5V 36 | - Motor voltage support 46V(max) 37 | - [DRV8313](http://s.click.aliexpress.com/e/_d6fRu7w) cheap([price $1](http://s.click.aliexpress.com/e/_d6fRu7w)) driver 38 | - Three Half-H-Bridge driver IC 39 | - Maximum drive current is 2.5A(peak) or 1.75A(RMS) 40 | - Logic voltage support 3.3V and 5V 41 | - Motor voltage support 65V(max) 42 | - MOS-FET switch 43 | - etc 44 | 45 | # Install 46 | 47 | ## Library manager 48 | Arduino IDE with using library manager. 49 | 50 | 1. Select [Sketch -> Include Library -> Manage Libraries...] to open library manager. 51 | 2. Search "UcnBrushlessDCMotorPWM" in library manager. 52 | 3. Select and install this library. 53 | 54 | ## Manual install 55 | 56 | 1. Download latest zip library from [here](https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM/releases) 57 | 2. Select [Sketch -> Include Library -> Add .ZIP Library...] 58 | 3. Select and install downloaded library. 59 | 60 | 61 | # Connection example 62 | 63 | ## [L298N](http://s.click.aliexpress.com/e/_d6YWPqk) 64 | 65 | - withoout L298N enable pin 66 | ![withoout L298N enable pin](images/arduinouno_l298n_connect.jpg) 67 | ``` 68 | Arduino UNO 9pin -> L298N modle IN1 69 | Arduino UNO 10pin -> L298N modle IN2 70 | Arduino UNO 11pin -> L298N modle IN3 71 | 72 | L298N modle OUT1 -> BLDC motor U 73 | L298N modle OUT2 -> BLDC motor V 74 | L298N modle OUT3 -> BLDC motor W 75 | 76 | mobile battery 5V -> L298N modle 5V 77 | mobile battery 5V -> L298N modle VIN 78 | mobile battery GND -> L298N modle GND 79 | 80 | mobile battery GND -> Arduino UNO GND 81 | 82 | *L298N modle ENA/ENB jumpers are closed 83 | ``` 84 | 85 | - with L298N enable pin 86 | ``` 87 | Arduino UNO 9pin -> L298N modle IN1 88 | Arduino UNO 10pin -> L298N modle IN2 89 | Arduino UNO 11pin -> L298N modle IN3 90 | 91 | Arduino UNO 4pin -> L298N modle ENA 92 | Arduino UNO 5pin -> L298N modle ENB 93 | 94 | L298N modle OUT1 -> BLDC motor U 95 | L298N modle OUT2 -> BLDC motor V 96 | L298N modle OUT3 -> BLDC motor W 97 | 98 | mobile battery 5V -> L298N modle 5V 99 | mobile battery 5V -> L298N modle VIN 100 | mobile battery GND -> L298N modle GND 101 | 102 | mobile battery GND -> Arduino UNO GND 103 | 104 | *L298N modle ENA/ENB jumpers are open 105 | ``` 106 | 107 | 108 | 109 | ## [DRV8313](http://s.click.aliexpress.com/e/_d6fRu7w) 110 | ``` 111 | Arduino UNO 9pin -> DRV8313 IN1 112 | Arduino UNO 10pin -> DRV8313 IN2 113 | Arduino UNO 11pin -> DRV8313 IN3 114 | 115 | Arduino UNO 4pin -> DRV8313 EN1 116 | Arduino UNO 5pin -> DRV8313 EN2 117 | Arduino UNO 6pin -> DRV8313 EN3 118 | 119 | DRV8313 OUT1 -> BLDC motor U 120 | DRV8313 OUT2 -> BLDC motor V 121 | DRV8313 OUT3 -> BLDC motor W 122 | 123 | mobile battery 5V -> DRV8313 VM 124 | mobile battery GND -> DRV8313 GND 125 | 126 | mobile battery GND -> Arduino UNO GND 127 | ``` 128 | 129 | 130 | ## FET switch 131 | ![push-pull](images/pushpull_fet.png) 132 | 133 | 134 | 135 | # Basic usage 136 | 137 | ## Setup 138 | 139 | ```c 140 | #include 141 | 142 | 143 | UcnBrushlessDCMotorPWM _bldc; 144 | 145 | //PWM output pin for BLDC driver 146 | #define BLDC_DRV_IN1 9 147 | #define BLDC_DRV_IN2 10 148 | #define BLDC_DRV_IN3 11 149 | 150 | //(option) ENABLE pin for BLDC driver 151 | #define BLDC_DRV_EN1 4 152 | #define BLDC_DRV_EN2 5 153 | #define BLDC_DRV_EN3 6 154 | 155 | //Pole count of BLDC motor 156 | #define BLDC_MOTOR_POLE 14 //12N14P 157 | //#define BLDC_MOTOR_POLE 22 //24N22P 158 | //#define BLDC_MOTOR_POLE 26 //24N26P 159 | //#define BLDC_MOTOR_POLE 28 //24N28P 160 | //#define BLDC_MOTOR_POLE 32 //24N32P 161 | 162 | 163 | void setup() 164 | { 165 | _bldc.begin(BLDC_MOTOR_POLE, BLDC_DRV_IN1, BLDC_DRV_IN2, BLDC_DRV_IN3, BLDC_DRV_EN1, BLDC_DRV_EN2, BLDC_DRV_EN3); 166 | 167 | _bldc.SetPower(80); //motor power 80% 168 | } 169 | ``` 170 | 171 | 172 | 173 | ## Drive like as slow DC motor 174 | 175 | ```c 176 | void loop() 177 | { 178 | // continuos rotation 179 | _bldc.DoRotate(1); 180 | delayMicroseconds(3000); 181 | } 182 | ``` 183 | 184 | 185 | 186 | ## Drive like as servo motor 187 | 188 | ```c 189 | void loop() 190 | { 191 | //180 degree rotation with 3000 usec delay loop 192 | _bldc.DoRotateLoop(180, 3000); 193 | 194 | //180 degree inverse rotation with 3000 usec delay loop 195 | _bldc.DoRotateLoop(-180, 3000); 196 | } 197 | ``` 198 | 199 | # Available PWM pin 200 | 201 | ## Arduino UNO(ATMEGA328P) 202 | - 3 pin 203 | - 5 pin 204 | - 6 pin 205 | - 9 pin 206 | - 10 pin 207 | - 11 pin 208 | 209 | ## STM32(STM32F103) 210 | - PA0 to PA3 211 | - PA6 to PA10 212 | - PB0 to PB1 213 | - PB6 to PB9 214 | 215 | ## ESP32 216 | - GPIO 0 217 | - GPIO 2 218 | - GPIO 4 219 | - GPIO 12 to 15 220 | - GPIO 25 to 27 221 | - GPIO 32 to 33 222 | - A4 to A5 223 | - A10 to A19 224 | 225 | 226 | ## ESP8266 227 | - GPIO 0 to GPIO 5 228 | - GPIO 12 to GPIO 16 229 | - GPIO 6 to 11 are reserved for flash memory 230 | - attention: ex. "D1" means NOT "GPIO 1" 231 | 232 | # ATTENTION 233 | 234 | The brushless DC motor needs a large current. Be sure to use ampere meter. 235 | Mobile battery with built-in safety circuit is recommended for the motor power supply, and [USB current meter](http://s.click.aliexpress.com/e/_dZpiddS) is useful. 236 | 237 | 238 | # Download 239 | 240 | Download release version from [here](https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM/releases) 241 | 242 | # License 243 | MIT 244 | 245 | -------------------------------------------------------------------------------- /UcnBrushlessDCMotorPWM.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////// 2 | // 3 | // UcnBrushlessDCMotorPWM 4 | // 5 | // Arduino library for driving brushless DC motor like as servo motor 6 | // 7 | // 8 | // https://usefullcode.net/ 9 | // https://github.com/usefullcodenet/UcnBrushlessDCMotorPWM 10 | // 11 | // Copyright (c) 2020 usefullcode.net 12 | // 13 | // MIT License (MIT) 14 | // 15 | ////////////////////////////////////////////////////////////////////////// 16 | 17 | #ifndef UcnBrushlessDCMotorPWM_h 18 | #define UcnBrushlessDCMotorPWM_h 19 | 20 | 21 | 22 | 23 | class UcnBrushlessDCMotorPWM 24 | { 25 | protected: 26 | 27 | const uint8_t PWM_MAX = 255; 28 | const uint8_t PWM_MIN = 0; 29 | 30 | uint16_t _nSinTableSize; 31 | 32 | int16_t _nPhaseIndex1; 33 | int16_t _nPhaseIndex2; 34 | int16_t _nPhaseIndex3; 35 | 36 | uint8_t* _pnSinTable; 37 | 38 | uint8_t _nPower = 100; 39 | 40 | volatile bool _bAbortLoop; 41 | 42 | uint8_t _nMotorPoleCount; 43 | 44 | uint8_t _nPinIn1; 45 | uint8_t _nPinIn2; 46 | uint8_t _nPinIn3; 47 | 48 | #if defined(ESP32) 49 | uint8_t _nChannelIn1_eps32 = 0; 50 | uint8_t _nChannelIn2_eps32 = 1; 51 | uint8_t _nChannelIn3_eps32 = 2; 52 | #endif 53 | 54 | int8_t _nPinEn1; 55 | int8_t _nPinEn2; 56 | int8_t _nPinEn3; 57 | 58 | 59 | 60 | virtual void PrepareSinTable(uint16_t nSinTableSize) 61 | { 62 | if (nSinTableSize == 0) 63 | return; 64 | 65 | _nSinTableSize = nSinTableSize; 66 | 67 | double rad = 0; 68 | double diff = 2.0 * PI / _nSinTableSize / 1; 69 | int16_t tmp; 70 | 71 | if (_pnSinTable != NULL) 72 | delete _pnSinTable; 73 | 74 | _pnSinTable = new uint8_t[_nSinTableSize]; 75 | for (int i = 0; i < _nSinTableSize; i++) 76 | { 77 | // degree: 0 to 360, value: PWM_MIN to PWM_MAX 78 | tmp = (int)((sin(rad) + 1.0) * (PWM_MAX - PWM_MIN) / 2) + PWM_MIN; 79 | if (tmp < PWM_MIN) 80 | tmp = PWM_MIN; 81 | if (tmp > PWM_MAX) 82 | tmp = PWM_MAX; 83 | 84 | _pnSinTable[i] = tmp; 85 | 86 | rad += diff; 87 | } 88 | 89 | _nPhaseIndex1 = 0; 90 | _nPhaseIndex2 = _nSinTableSize / 3; 91 | _nPhaseIndex3 = _nPhaseIndex2 + _nPhaseIndex2; 92 | } 93 | 94 | 95 | 96 | // 0 - (_nSinTableSize-1) 97 | virtual inline uint8_t GetSinTableValue(int16_t nIndex) const 98 | { 99 | if (_nPower >= 100) 100 | return _pnSinTable[nIndex]; 101 | 102 | uint16_t tmp = _nPower; 103 | tmp *= _pnSinTable[nIndex]; 104 | tmp /= 100; 105 | 106 | if (tmp > PWM_MAX) 107 | tmp = PWM_MAX; 108 | 109 | return tmp; 110 | } 111 | 112 | 113 | virtual void setupPWM(uint32_t nPwmFreq = 0) 114 | { 115 | #if defined(ARDUINO_ARCH_AVR) 116 | 117 | //nPwmFreq is ignored, use 31.37KHz 118 | 119 | if (_nPinIn1 == 5 || _nPinIn1 == 6 || _nPinIn2 == 5 || _nPinIn2 == 6 || _nPinIn3 == 5 || _nPinIn3 == 6) 120 | { 121 | // timer0 122 | // 5pin and 6pin PWM to 31.37KHz 123 | TCCR0B &= B11111000; 124 | TCCR0B |= B00000001; 125 | } 126 | 127 | if (_nPinIn1 == 9 || _nPinIn1 == 10 || _nPinIn2 == 9 || _nPinIn2 == 10 || _nPinIn3 == 9 || _nPinIn3 == 10) 128 | { 129 | // timer1 130 | // 9pin and 10pin PWM to 31.37KHz 131 | TCCR1B &= B11111000; 132 | TCCR1B |= B00000001; 133 | } 134 | 135 | if (_nPinIn1 == 3 || _nPinIn1 == 11 || _nPinIn2 == 3 || _nPinIn2 == 11 || _nPinIn3 == 3 || _nPinIn3 == 11) 136 | { 137 | // timer2 138 | // 3pin and 11pin PWM to 31.37KHz 139 | TCCR2B &= B11111000; 140 | TCCR2B |= B00000001; 141 | } 142 | 143 | pinMode(_nPinIn1, OUTPUT); 144 | pinMode(_nPinIn2, OUTPUT); 145 | pinMode(_nPinIn3, OUTPUT); 146 | #endif 147 | 148 | #if defined(ESP32) 149 | 150 | if (nPwmFreq == 0) 151 | nPwmFreq = 48000; //default 48KHz PWM 152 | 153 | ledcSetup(_nChannelIn1_eps32, nPwmFreq, 8); //8bit PWM 154 | ledcSetup(_nChannelIn2_eps32, nPwmFreq, 8); //8bit PWM 155 | ledcSetup(_nChannelIn3_eps32, nPwmFreq, 8); //8bit PWM 156 | 157 | ledcAttachPin(_nPinIn1, _nChannelIn1_eps32); 158 | ledcAttachPin(_nPinIn2, _nChannelIn2_eps32); 159 | ledcAttachPin(_nPinIn3, _nChannelIn3_eps32); 160 | #endif 161 | 162 | #if defined(ESP8266) 163 | 164 | if (nPwmFreq == 0) 165 | nPwmFreq = 10000; //default 10KHz PWM (high freq cause invalid PWM pulse) 166 | 167 | analogWriteRange(255); //8bit PWM 168 | analogWriteFreq(nPwmFreq); 169 | #endif 170 | 171 | #if defined(ARDUINO_ARCH_STM32) 172 | 173 | if (nPwmFreq == 0) 174 | nPwmFreq = 100000; //default 100KHz PWM 175 | 176 | analogWriteResolution(8); //8bit PWM 177 | analogWriteFrequency(nPwmFreq); 178 | #endif 179 | 180 | } 181 | 182 | 183 | 184 | 185 | virtual inline void WritePwmValue(uint8_t nPinOrChannel, uint8_t nValue) const 186 | { 187 | #if defined(ESP32) 188 | ledcWrite(nPinOrChannel, nValue); 189 | #else 190 | analogWrite(nPinOrChannel, nValue); 191 | #endif 192 | } 193 | 194 | 195 | virtual inline void WritePwm(uint8_t nPinOrChannel, uint16_t nPhaseIndex) const 196 | { 197 | WritePwmValue(nPinOrChannel, GetSinTableValue(nPhaseIndex)); 198 | } 199 | 200 | 201 | 202 | virtual inline void WritePwm123(void) const 203 | { 204 | #if defined(ESP32) 205 | WritePwm(_nChannelIn1_eps32, _nPhaseIndex1); 206 | WritePwm(_nChannelIn2_eps32, _nPhaseIndex2); 207 | WritePwm(_nChannelIn3_eps32, _nPhaseIndex3); 208 | #else 209 | WritePwm(_nPinIn1, _nPhaseIndex1); 210 | WritePwm(_nPinIn2, _nPhaseIndex2); 211 | WritePwm(_nPinIn3, _nPhaseIndex3); 212 | #endif 213 | } 214 | 215 | 216 | 217 | 218 | 219 | public: 220 | 221 | virtual void suspend(uint8_t value = 0) 222 | { 223 | #if defined(ESP32) 224 | WritePwmValue(_nChannelIn1_eps32, value); 225 | WritePwmValue(_nChannelIn2_eps32, value); 226 | WritePwmValue(_nChannelIn3_eps32, value); 227 | #else 228 | WritePwmValue(_nPinIn1, value); 229 | WritePwmValue(_nPinIn2, value); 230 | WritePwmValue(_nPinIn3, value); 231 | #endif 232 | } 233 | 234 | 235 | 236 | 237 | 238 | #if defined(ESP32) 239 | UcnBrushlessDCMotorPWM(uint8_t nChannelIn1_eps32 = 0, uint8_t nChannelIn2_eps32 = 1, uint8_t nChannelIn3_eps32 = 2) 240 | #else 241 | UcnBrushlessDCMotorPWM() 242 | #endif 243 | { 244 | _pnSinTable = NULL; 245 | _bAbortLoop = false; 246 | _nSinTableSize = 200; 247 | 248 | _nPinEn1 = -1; 249 | _nPinEn2 = -1; 250 | _nPinEn3 = -1; 251 | 252 | #if defined(ESP32) 253 | _nChannelIn1_eps32 = nChannelIn1_eps32; 254 | _nChannelIn2_eps32 = nChannelIn2_eps32; 255 | _nChannelIn3_eps32 = nChannelIn3_eps32; 256 | #endif 257 | } 258 | 259 | 260 | virtual ~UcnBrushlessDCMotorPWM() 261 | { 262 | end(); 263 | } 264 | 265 | 266 | virtual void begin(uint8_t nMotorPoleCount, uint8_t nPinIn1, uint8_t nPinIn2, uint8_t nPinIn3, int8_t nPinEn1 = -1, int8_t nPinEn2 = -1, int8_t nPinEn3 = -1, uint16_t nSinTableSize = 200, uint32_t nPwmFreq = 0) 267 | { 268 | _nPinIn1 = nPinIn1; 269 | _nPinIn2 = nPinIn2; 270 | _nPinIn3 = nPinIn3; 271 | 272 | _nPinEn1 = nPinEn1; 273 | _nPinEn2 = nPinEn2; 274 | _nPinEn3 = nPinEn3; 275 | 276 | _nMotorPoleCount = nMotorPoleCount; 277 | 278 | PrepareSinTable(nSinTableSize); 279 | 280 | setupPWM(nPwmFreq); 281 | 282 | // set ENABLE1 pin to HIGH 283 | if(nPinEn1 >= 0) 284 | { 285 | pinMode(nPinEn1, OUTPUT); 286 | digitalWrite(nPinEn1, HIGH); 287 | } 288 | 289 | // set ENABLE2 pin to HIGH 290 | if(nPinEn2 >= 0) 291 | { 292 | pinMode(nPinEn2, OUTPUT); 293 | digitalWrite(nPinEn2, HIGH); 294 | } 295 | 296 | // set ENABLE3 pin to HIGH 297 | if(nPinEn3 >= 0) 298 | { 299 | pinMode(nPinEn3, OUTPUT); 300 | digitalWrite(nPinEn3, HIGH); 301 | } 302 | } 303 | 304 | 305 | virtual void end(void) 306 | { 307 | // set ENABLE1 pin to LOW 308 | if(_nPinEn1 >= 0) 309 | { 310 | digitalWrite(_nPinEn1, LOW); 311 | } 312 | 313 | // set ENABLE2 pin to LOW 314 | if(_nPinEn2 >= 0) 315 | { 316 | digitalWrite(_nPinEn2, LOW); 317 | } 318 | 319 | // set ENABLE3 pin to LOW 320 | if(_nPinEn3 >= 0) 321 | { 322 | digitalWrite(_nPinEn3, LOW); 323 | } 324 | 325 | if (_pnSinTable) 326 | delete _pnSinTable; 327 | _pnSinTable = NULL; 328 | } 329 | 330 | 331 | 332 | // power: 0 to 100 (%) 333 | void SetPower(uint8_t nPower) 334 | { 335 | if (nPower > 100) 336 | nPower = 100; 337 | _nPower = nPower; 338 | } 339 | 340 | 341 | virtual void SetAbortFlag(void) 342 | { 343 | _bAbortLoop = true; 344 | } 345 | 346 | virtual void ClearAbortFlag(void) 347 | { 348 | _bAbortLoop = false; 349 | } 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | virtual inline void DoRotate(int16_t nStep = 1) 358 | { 359 | WritePwm123(); 360 | 361 | _nPhaseIndex1 += nStep; 362 | _nPhaseIndex2 += nStep; 363 | _nPhaseIndex3 += nStep; 364 | 365 | if (nStep > 0) 366 | { 367 | if (_nPhaseIndex1 >= _nSinTableSize) 368 | _nPhaseIndex1 = 0; 369 | if (_nPhaseIndex2 >= _nSinTableSize) 370 | _nPhaseIndex2 = 0; 371 | if (_nPhaseIndex3 >= _nSinTableSize) 372 | _nPhaseIndex3 = 0; 373 | } 374 | else 375 | { 376 | if (_nPhaseIndex1 < 0) 377 | _nPhaseIndex1 = _nSinTableSize - 1; 378 | if (_nPhaseIndex2 < 0) 379 | _nPhaseIndex2 = _nSinTableSize - 1; 380 | if (_nPhaseIndex3 < 0) 381 | _nPhaseIndex3 = _nSinTableSize - 1; 382 | } 383 | } 384 | 385 | 386 | 387 | 388 | inline uint32_t calcRequireStepCount(int16_t nRotateDegree) 389 | { 390 | //360degree rotate need ((_nMotorPoleCount + 1) / 2.0 * _nSinTableSize) steps 391 | return (uint32_t)((double)nRotateDegree / 360.0 * (_nMotorPoleCount + 1) / 2.0 * _nSinTableSize); 392 | } 393 | 394 | 395 | void DoRotateLoop(int16_t nRotateDegree, uint16_t nDelayMicroSec, int8_t nStep = 1) 396 | { 397 | if (_pnSinTable == NULL) 398 | return; 399 | 400 | if (nRotateDegree < 0) 401 | { 402 | nRotateDegree = -nRotateDegree; 403 | nStep = -nStep; 404 | } 405 | uint8_t nStepAbs = abs(nStep); 406 | 407 | uint32_t nRequireStep = calcRequireStepCount(nRotateDegree); 408 | 409 | while (_bAbortLoop == false) 410 | { 411 | DoRotate(nStep); 412 | 413 | nRequireStep -= nStepAbs; 414 | if (nRequireStep == 0) 415 | break; 416 | 417 | delayMicroseconds(nDelayMicroSec); 418 | #ifdef ESP32 419 | vTaskDelay(1); // for FreeRTOS 420 | #endif 421 | 422 | } 423 | } 424 | 425 | }; 426 | 427 | 428 | #endif 429 | --------------------------------------------------------------------------------