Data acquisition and device control with Scilab.
Desciription
Scilab is a freeware alternative to MATLAB. For low-cost data acquisition and device control a nice Arduino toolbox is available.
This site presents a Mbed port which allows to use Mbed boards (equipped with Arduino header) rather than Arduino to import real time data into Scilab and to control real equipment witch Scilab.
Installation
- Install Scilab to your PC, if not done yet.
- Launch Scilab and install the Arduino toolbox by executing the following command from the Scilab console:
--> atomsInstall("arduino")
Controlling Mbed's digital output from Scilab
- In Xcos open
examples/Arduino1.zcos
- Double click on the
Board
setup block and replace the serial port number with mbed's actual virtual serial port number.
- Double click on the
Digital WRITE
block and set Digital Pin to 13 (D13 is connected to LED1).
- Start simulation and LED1 on the Mbed board should start blinking.
Reading and displaying Mbed's analog input
- In Xcos open
examples/Arduino2.zcos
- Double click on the
Board
setup block and replace the serial port number with mbed's actual virtual serial port number.
- Double click on the
Analog READ
block and set Analog Pin to 2.
- Start simulation and a graph should appear showing the analog signal measured on Mbed's pin A2.
NOTE: Currently, there is bug in the toolbox ARDUINO_ANALOG_READ_sim function (I have reported to Scilab) so the analog readings are not correct.
PID controller
- In Xcos open
examples/Arduino9.zcos
Revision 0:295b7e1c12f3, committed 2021-01-18
- Comitter:
- hudakz
- Date:
- Mon Jan 18 19:51:22 2021 +0000
- Commit message:
- Data acquisition and device control with Scilab.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.gitignore Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,4 @@ +.build +.mbed +projectfiles +*.py*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CONTRIBUTING.md Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,5 @@ +# Contributing to Mbed OS + +Mbed OS is an open-source, device software platform for the Internet of Things. Contributions are an important part of the platform, and our goal is to make it as simple as possible to become a contributor. + +To encourage productive collaboration, as well as robust, consistent and maintainable code, we have a set of guidelines for [contributing to Mbed OS](https://os.mbed.com/docs/mbed-os/latest/contributing/index.html).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MPU6050.lib Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/hudakz/code/MPU6050/#9c2bb0f94c31
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,64 @@ +![](./resources/official_armmbed_example_badge.png) +# Blinky Mbed OS example + +The example project is part of the [Arm Mbed OS Official Examples](https://os.mbed.com/code/) and is the [getting started example for Mbed OS](https://os.mbed.com/docs/mbed-os/v5.14/quick-start/index.html). It contains an application that repeatedly blinks an LED on supported [Mbed boards](https://os.mbed.com/platforms/). + +You can build the project with all supported [Mbed OS build tools](https://os.mbed.com/docs/mbed-os/latest/tools/index.html). However, this example project specifically refers to the command-line interface tool [Arm Mbed CLI](https://github.com/ARMmbed/mbed-cli#installing-mbed-cli). +(Note: To see a rendered example you can import into the Arm Online Compiler, please see our [import quick start](https://os.mbed.com/docs/mbed-os/latest/quick-start/online-with-the-online-compiler.html#importing-the-code).) + +1. [Install Mbed CLI](https://os.mbed.com/docs/mbed-os/latest/quick-start/offline-with-mbed-cli.html). + +1. Clone this repository on your system, and change the current directory to where the project was cloned: + + ```bash + $ git clone git@github.com:armmbed/mbed-os-example-blinky && cd mbed-os-example-blinky + ``` + + Alternatively, you can download the example project with Arm Mbed CLI using the `import` subcommand: + + ```bash + $ mbed import mbed-os-example-blinky && cd mbed-os-example-blinky + ``` + + +## Application functionality + +The `main()` function is the single thread in the application. It toggles the state of a digital output connected to an LED on the board. + +## Building and running + +1. Connect a USB cable between the USB port on the board and the host computer. +2. <a name="build_cmd"></a> Run the following command to build the example project and program the microcontroller flash memory: + ```bash + $ mbed compile -m <TARGET> -t <TOOLCHAIN> --flash + ``` +The binary is located at `./BUILD/<TARGET>/<TOOLCHAIN>/mbed-os-example-blinky.bin`. + +Alternatively, you can manually copy the binary to the board, which you mount on the host computer over USB. + +Depending on the target, you can build the example project with the `GCC_ARM`, `ARM` or `IAR` toolchain. After installing Arm Mbed CLI, run the command below to determine which toolchain supports your target: + +```bash +$ mbed compile -S +``` + +## Expected output +The LED on your target turns on and off every 500 milliseconds. + + +## Troubleshooting +If you have problems, you can review the [documentation](https://os.mbed.com/docs/latest/tutorials/debugging.html) for suggestions on what could be wrong and how to fix it. + +## Related Links + +* [Mbed OS Stats API](https://os.mbed.com/docs/latest/apis/mbed-statistics.html). +* [Mbed OS Configuration](https://os.mbed.com/docs/latest/reference/configuration.html). +* [Mbed OS Serial Communication](https://os.mbed.com/docs/latest/tutorials/serial-communication.html). +* [Mbed OS bare metal](https://os.mbed.com/docs/mbed-os/latest/reference/mbed-os-bare-metal.html). +* [Mbed boards](https://os.mbed.com/platforms/). + +### License and contributions + +The software is provided under Apache-2.0 license. Contributions to this project are accepted under the same license. Please see contributing.md for more info. + +This project contains code from other projects. The original license text is included in those source files. They must comply with our license guide.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ScilabSerial/DcMotor.cpp Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,66 @@ +#include "DcMotor.h" + +/** + * @brief The DcMotor class + * @note Driven by L293 or L298 + */ +DcMotor::DcMotor(PinName pin1, PinName pin2, int driverType) : + _driverType(driverType) +{ + _pwmOut1 = new PwmOut(pin1); + _pwmOut1->write(0); + switch (_driverType) { + case 0: //L293 + _pwmOut2 = new PwmOut(pin2); + _pwmOut2->write(0); + break; + + case 1: //L297 + _digitalOut2 = new DigitalOut(pin2); + _digitalOut2->write(0); + break; + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +DcMotor::~DcMotor() +{ + delete _pwmOut1; + delete _pwmOut2; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void DcMotor::run(int direction, float speed) +{ + switch (_driverType) { + case 0: //L293 + if (direction == 0) { + _pwmOut1->write(0); + _pwmOut2->write(speed); + } + else { + _pwmOut1->write(speed); + _pwmOut2->write(0); + } + break; + + case 1: //L297 + if (direction == 0) + _digitalOut2->write(0); + else + _digitalOut2->write(1); + + _pwmOut1->write(speed); + break; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ScilabSerial/DcMotor.h Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,18 @@ +#ifndef DCMOTOR_H +#define DCMOTOR_H + +#include "mbed.h" + +class DcMotor +{ + PwmOut* _pwmOut1; + PwmOut* _pwmOut2; + DigitalOut* _digitalOut2; + int _driverType; +public: + DcMotor(PinName pin1, PinName pin2, int driverType); + ~DcMotor(); + void run(int direction, float speed); +}; + +#endif // DCMOTOR_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ScilabSerial/Encoder.cpp Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,65 @@ +#include "Encoder.h" + +/** + * @brief The Encoder class + * @note Rotary encoder with three operating modes + */ +Encoder::Encoder(PinName pinA, PinName pinB, int mode) : _position(0) +{ + switch (mode) { + case 1: + _chanA = new InterruptIn(pinA); + _chanA->rise(callback(this, &Encoder::onRiseMode1)); + _chanB = new InterruptIn(pinB); + break; + + case 2: + _chanA = new InterruptIn(pinA); + _chanA->rise(callback(this, &Encoder::onChangeMode2)); + _chanA->fall(callback(this, &Encoder::onChangeMode2)); + _chanB = new InterruptIn(pinB); + break; + + case 4: + _chanA = new InterruptIn(pinA); + _chanA->rise(callback(this, &Encoder::onChangeMode2)); + _chanA->fall(callback(this, &Encoder::onChangeMode2)); + _chanB = new InterruptIn(pinB); + _chanB->rise(callback(this, &Encoder::onChangeMode2)); + _chanB->fall(callback(this, &Encoder::onChangeMode2)); + break; + } +} + +Encoder::~Encoder() +{ + delete _chanA; + delete _chanB; +} + +void Encoder::onRiseMode1() +{ + int b = _chanB->read(); + if (b) + _position--; + else + _position++; +} +void Encoder::onChangeMode2() +{ + int a = _chanA->read(); + int b = _chanB->read(); + if ((a && !b) || (!a && b)) + _position++; + else + _position--; +} +void Encoder::onChangeMode4() +{ + int a = _chanA->read(); + int b = _chanB->read(); + if ((a && !b) || (!a && b)) + _position++; + else + _position--; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ScilabSerial/Encoder.h Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,20 @@ +#ifndef ENCODER_H +#define ENCODER_H + +#include "mbed.h" + +class Encoder +{ + InterruptIn* _chanA; + InterruptIn* _chanB; + int8_t _position; +public: + Encoder(PinName pinA, PinName pinB, int mode); + ~Encoder(); + int8_t position() { return _position; } + void reset() { _position = 0; } + void onRiseMode1(); + void onChangeMode2(); + void onChangeMode4(); +}; +#endif // ENCODER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ScilabSerial/IntrInCounter.cpp Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,6 @@ +#include "IntrInCounter.h" + +IntrInCounter::IntrInCounter(PinName pin) : _value(0), _interruptIn(new InterruptIn(pin)) +{ + _interruptIn->rise(callback(this, &IntrInCounter::inc)); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ScilabSerial/IntrInCounter.h Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,21 @@ +#ifndef INTRINCOUNTER_H +#define INTRINCOUNTER_H + +#include "mbed.h" + +/** + * @brief The IntInCounter class + * @note Incremented on rising edge of input signal connected to InterruptIn pin + */ +class IntrInCounter +{ + uint8_t _value; + InterruptIn* _interruptIn; +public: + IntrInCounter(PinName pin); + void inc() { _value++; } + void reset() { _value = 0; } + uint8_t read() { return _value; } + void activate(PinName pin) { } +}; +#endif // INTINCOUNTER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ScilabSerial/ScilabSerial.cpp Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,583 @@ +#include "ScilabSerial.h" + +extern UnbufferedSerial dbgPort; + +/** + * @brief + * @note + * @param + * @retval + */ +ScilabSerial::ScilabSerial(PinName tx, PinName rx, int baud /*= 115200*/ ) : + SerialBase(tx, rx, baud), + _rxComplete(false), + _rxBufLen(0), + _rxDataLen(0), + _deltaT(0), + _mpu6050Available(false) +{ + attach(callback(this, &ScilabSerial::onRx)); + + // Analog inputs + for (size_t i = 0; i < sizeof(_analogPinName) / sizeof(*_analogPinName); i++) { + // indexes -> pin names + if (_analogPinName[i] != NC) + _analogIns[i] = new AnalogIn(_analogPinName[i]); + else + _analogIns[i] = NULL; + } + + // PWM outputs + for (size_t i = 0; i < 4; i++) { + // indexes 0 to 3 -> pin names D4 to D7 + if (_digitalPinName[i + 4] != NC) + _pwmOuts[i] = new PwmOut(_digitalPinName[i + 4]); + else + _pwmOuts[i] = NULL; + } + + // Digital read write + for (size_t i = 0; i < sizeof(_digitalInOuts) / sizeof(*_digitalInOuts); i++) + _digitalInOuts[i] = NULL; + + // Servo + for (size_t i = 0; i < sizeof(_servos) / sizeof(*_servos); i++) + _servos[i] = NULL; + + // MPU6050 + _mpu6050 = NULL; + + // Interrup-in counters + for (size_t i = 0; i < sizeof(_intrInCounters) / sizeof(*_intrInCounters); i++) + _intrInCounters[i] = NULL; + + // DC motors + for (size_t i = 0; i < sizeof(_dcMotors) / sizeof(*_dcMotors); i++) + _dcMotors[i] = NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::onRx() +{ + // If the '\n' character was used as 'packet-end' delimiter then we could have: + // + // while (readable()) { + // volatile char c = _base_getc(); + // if (c != '\n') { + // if (rxBufLen >= RX_MAX) + // rxBufLen = 0; // rxBuf overflow + // rxBuf[rxBufLen++] = c; + // } + // else { + // // packet complete + // memset(rxData, 0, RX_MAX); // clear rxData + // memcpy(rxData, rxBuf, rxBufLen); // copy rxBuf to rxData + // rxDataLen = rxBufLen; // set rxData length + // memset(rxBuf, 0, RX_MAX); // clear rxBuf + // rxBufLen = 0; + // } + // } + // Unfortunately there is neither packet length information in the packet + // nor 'packet-end' delimiter is used. + // That's why we have to figure out the packet length on the fly based on it's content: + volatile char c = _base_getc(); // Read a byte from UART + + _rxBuf[_rxBufLen++] = c; // Store the byte in the receive buffer + + switch (_rxBuf[0]) { + case 'A': // Analog read + case 'G': // MPU6050 + case 'R': // Revision request + if (_rxBufLen == 2) + _rxComplete = true; + break; + + case 'W': // PWM (analog) write + case 'I': // Interrupt-in counter + if (_rxBufLen == 3) + _rxComplete = true; + break; + + case 'D': // Digital read/write + if (_rxBufLen == 3) + if (_rxBuf[1] == 'r') + _rxComplete = true; + break; + + case 'S': // Servo motor + if (_rxBufLen == 3) + if (_rxBuf[1] != 'w') + _rxComplete = true; + break; + + case 'E': // Encoder + if (_rxBufLen == 3) + if (_rxBuf[1] != 'a') + _rxComplete = true; + break; + + case 'C': + if (_rxBufLen == 5) + _rxComplete = true; + + case 'M': // DC motor + if (_rxBufLen == 3) + if (_rxBuf[1] == 'r') + _rxComplete = true; + break; + } + + if ((_rxBuf[0] != 'C') && (_rxBufLen == 4)) + _rxComplete = true; + + if (_rxComplete) { + _rxComplete = false; + memset(_rxData, 0, RX_MAX); // reset rxData + memcpy(_rxData, _rxBuf, _rxBufLen); // copy rxBuf to rxData + _rxDataLen = _rxBufLen; // set rxData length + memset(_rxBuf, 0, RX_MAX); // reset rxBuf + _rxBufLen = 0; + } + +// dbgPort.write((void*)(& _rxData), _rxDataLen); +// dbgPort.write("\r\n", 2); + +} + +/** + * @brief + * @note + * @param + * @retval + */ +ssize_t ScilabSerial::write(const void* buffer, size_t length) +{ + const char* ptr = (const char*)buffer; + const char* end = ptr + length; + + lock(); + while (ptr != end) { + _base_putc(*ptr++); + } + + unlock(); + + return ptr - (const char*)buffer; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::run() +{ + while (1) { + if (_mpu6050Available) + mpu6050UpdateData(); + + if (_rxDataLen > 0) { + _rxDataLen = 0; + switch (_rxData[0]) { + case 'A': // Analog read + analogRead(); + break; + + case 'W': // PWM (analog) write + pwmWrite(); + break; + + case 'D': // Digital + digitalReadWrite(); + break; + + case 'S': // Servo motor + servo(); + break; + + case 'G': // MPU6050 + mpu6050(); + break; + + case 'I': // Interrupt-in counter + intrInCounter(); + break; + + case 'E': // Encoder + encoder(); + break; + + case 'C': // DC motor init + dcMotorInit(); + break; + + case 'M': // DC motor + dcMotor(); + break; + + case 'R': // Revision + revision(); + break; + } + } + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::analogRead() +{ + int pin = _rxData[1] - '0'; // analog pin number 0 .. 5 + uint8_t i = pin; // index of corresponding analogIn 0 .. 5 + + if ((pin >= 0 && pin <= 5) && (_analogIns[i] != NULL)) { + uint16_t word = _analogIns[i]->read_u16(); // get decimal value 0 .. 65535 + float val = word / 64.0f; // map 16bit range to 10bit range + + word = round(val); + write((uint8_t*) &word, sizeof(uint16_t)); // send it to Scilab + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::pwmWrite() +{ + int pin = _rxData[1] - '0'; // digital pin number 4 .. 7 + uint8_t i = pin - 4; // index of corresponding analogOut (PWMOut) 0 .. 3 + + if ((pin >= 4 && pin <= 7) && (_pwmOuts[i] != NULL)) { + uint8_t val = _rxData[2]; // the duty cycle: between 0 (always off) and 255 (always on) + float dutyCycle = (float)val / 255.0f; // 0.0f (representing on 0%) and 1.0f (representing on 100%) + + _pwmOuts[i]->write(dutyCycle); + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::digitalReadWrite() +{ + int pin = _rxData[2] - '0'; // digital pin number 8 .. 13 + uint8_t i = pin - 8; // index of corresponding digitalInOut 0 .. 7 + + if ((pin >= 8 && pin <= 13) && (_digitalPinName[pin] != NC)) { + char cmd = _rxData[1]; // command + PinDirection pinDirection; // pin direction (PIN_INPUT, PIN_OUTPUT) + char c; + uint8_t val; + + switch (cmd) { + case 'a': // 'a'-> activate + pinDirection = (PinDirection) (_rxData[3] - '0'); + if (_digitalInOuts[i] != NULL) + delete _digitalInOuts[i]; + _digitalInOuts[i] = new DigitalInOut(_digitalPinName[pin], pinDirection, PullUp, 0); + break; + + case 'r': // 'r'-> read + c = _digitalInOuts[i]->read() + '0'; + write((uint8_t*) &c, 1); + break; + + case 'w': // 'w'-> write + val = _rxData[3] - '0'; + + if (val == 0 || val == 1) + _digitalInOuts[i]->write(val); + break; + } + } + else + _digitalInOuts[i] = NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::servo() +{ + int pin = _rxData[2] - '0' + 1; // digital pin number 2 .. 3 + uint8_t i = pin - 2; // index of corresponding servo 0 .. 1 + uint8_t val; + + if ((pin == 2 || pin == 3) && (_digitalPinName[pin] != NC)) { + char cmd = _rxData[1]; + switch (cmd) { + case 'a': // 'a' -> activate servo + if (_servos[i] != NULL) + delete _servos[i]; + _servos[i] = new Servo(_digitalPinName[pin]); + break; + + case 'd': // 'd'-> delete servo + delete _servos[i]; + _servos[i] = NULL; + break; + + case 'w': // 'w'-> write to servo position in degree (0 .. 180) + val = _rxData[3]; + if (val >= 0 && val <= 180) + _servos[i]->position(val); + break; + } + } + else + _servos[i] = NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::mpu6050() +{ + uint8_t cmd = _rxData[1]; + uint16_t data[9]; + + if (I2C_SCL != NC && I2C_SDA != NC) { + switch (cmd) { + case 'a': // 'a'-> acivate + if (_mpu6050 != NULL) + delete _mpu6050; + _mpu6050 = new MPU6050(); + _mpu6050Available = _mpu6050->init(); + _mpu6050Timer.start(); + break; + + case 't': // 't' -> test + if (_mpu6050->selfTestOK()) { + _mpu6050->reset(); // Reset registers to default in preparation for device calibration + _mpu6050->calibrate(); // Calibrate gyro and accelerometers, load biases in bias registers + _mpu6050Available = _mpu6050->init(); + _mpu6050Timer.reset(); + _mpu6050Timer.start(); + write("OK", 2); + } + else { + _mpu6050Available = false; + write("KO", 2); + } + break; + + case 'r': // 'r'-> read + if (_mpu6050Available) { + data[0] = _mpu6050->yaw(); + data[1] = _mpu6050->pitch(); + data[2] = _mpu6050->roll(); + data[3] = _mpu6050->accelX; + data[4] = _mpu6050->accelY; + data[5] = _mpu6050->accelZ; + data[6] = _mpu6050->gyroX; + data[7] = _mpu6050->gyroY; + data[8] = _mpu6050->gyroZ; + write(data, sizeof(data)); // send data to scilab + } + break; + } + } + else + _mpu6050 = NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::mpu6050UpdateData() +{ + // check if data is available after interrupt + + if (_mpu6050->dataReady()) { + _mpu6050->accel(); + _mpu6050->gyro(); + + uint32_t _now = _mpu6050Timer.read_us(); + _mpu6050Timer.reset(); + + float _deltaT = float(_now / 1e-6); // set integration time in seconds + + _mpu6050->madgwickFilter(_deltaT); // apply filter to estimate yaw, pitch and roll + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::intrInCounter() +{ + int pin = _rxData[2] - '0'; // digital pin number 8 .. 13 + uint8_t i = pin - 8; // index of corresonding IntCounter 0 .. 7 + + if ((pin >= 8 && pin <= 13) && (_digitalPinName[pin] != NC)) { + uint8_t val; + char cmd = _rxData[1]; + switch (cmd) { + case 'a': // 'a' -> activate a counter + if (_intrInCounters[i] != NULL) + delete _intrInCounters[i]; + _intrInCounters[i] = new IntrInCounter(_digitalPinName[pin]); + break; + + case 'p': // 'p' -> get position of a counter + val = _intrInCounters[i]->read(); + write(&val, 1); // send value to scilab (0 .. 256) + break; + + case 'r': // 'r' -> release an interrupt counter + delete _intrInCounters[i]; + break; + + case 'z': // 'z' -> set to zero (reset) a counter + _intrInCounters[i]->reset(); + break; + } + } + else + _intrInCounters[i] = NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::encoder() +{ + uint8_t i = _rxData[2] - '0'; // encoder index 0 .. 1 + + if ((i >= 0 && i <= 1) && (_digitalPinName[i])) { + int pinA, pinB; + int8_t pos; + int mode; + char cmd = _rxData[1]; // command + + switch (cmd) { + case 'a': // 'a' -> activate an encoder + i == 0 ? pinA = 8 : pinA = 10; + pinB = pinA + 1; // pinB -> 9 or 11 + mode = _rxData[3] - '0'; // '1' -> up chanA, '2' -> up/down chanA, '4' -> up/down chanA and chanB + if (_encoders[i] != NULL) + delete _encoders[i]; + _encoders[i] = new Encoder(_digitalPinName[pinA], _digitalPinName[pinB], mode); + break; + + case 'p': // 'p' -> get position of an encoder + pos = _encoders[i]->position(); + + write(&pos, 1); // send value to scilab (0 .. 256) + break; + + case 'r': // 'r' -> release an encoder + delete _encoders[i]; + break; + + case 'z': // 'z' -> set to zero (reset) the position of an encoder + _encoders[i]->reset(); + break; + } + } + else + _encoders[i] = NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::dcMotorInit() +{ + uint8_t pin1, pin2; + uint8_t driverType; + uint8_t i = _rxData[1] - '0'; // motor index + + if ((i < 2) && (_digitalPinName[i] != NC)) { + pin1 = _rxData[2]; // pin1 is 2 or 4 + if (pin1 == 2 || pin1 == 4) { + pin2 = _rxData[3] - '0'; // pin2 is 3 or 5 + if (pin2 == 3 || pin2 == 5) { + driverType = _rxData[4] - '0'; // driver: 0 -> L293, 1 -> L298 + if (driverType >= 0 && driverType <= 1) { + if (_dcMotors[i] != NULL) + delete _dcMotors[i]; + _dcMotors[i] = new DcMotor(_digitalPinName[pin1], _digitalPinName[pin2], driverType); + write("OK", 2); // tell scilab that motor initialization is complete + } + } + } + } + else + _dcMotors[i] = NULL; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::dcMotor() +{ + int pin1, pin2; + int mode; + char cmd; + float speed; + uint8_t i = _rxData[1] - '0'; // motor index + + if ((i < 2) && (_dcMotors[i] != NULL)) { + cmd = _rxData[2] - '0'; // direction of rotation or release + switch (cmd) { + case 0: // clockwise + case 1: // counter clockwise + speed = _rxData[3]; // speed + _dcMotors[i]->run(cmd, speed); + break; + + case 'r': // release + delete _dcMotors[i]; + break; + } + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void ScilabSerial::revision() +{ + write("v5", 2); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ScilabSerial/ScilabSerial.h Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,103 @@ +#ifndef SCILABSERIAL_H +#define SCILABSERIAL_H + +#include "mbed.h" +#include "Servo.h" +#include "IntrInCounter.h" +#include "Encoder.h" +#include "DcMotor.h" +#include "MPU6050.h" + +//#define USBSERIAL +#define RX_MAX 64 + +#ifdef USBSERIAL +#include "USBSerial.h" +//#include "stm32f103c8t6.h" +#endif +/** + * @brief The PcSerial class + * @note For serial communication with PC + */ +#ifdef USBSERIAL +class PcSerial : + public USBSerial +{ +public: + PcSerial() : + USBSerial(0x1f00, 0x2012, 0x0001, false) + { + rxDataLen = 0; + attach(this, &PcSerial::onRx); + } + + void onRx() + { + memset(rxData, 0, RX_MAX); + while (available()) { + char c = _getc(); + if (c != '\n') { + if (rxDataLen >= RX_MAX) + rxDataLen = 0; // rxBuf overflow + rxData[rxDataLen++] = c; + } + } + } + + ssize_t write(const void* buffer, size_t length) { return writeBlock((uint8_t*)buffer, length); } + char rxData[RX_MAX]; + volatile size_t rxDataLen; +}; +#else +class ScilabSerial : + public SerialBase +{ + bool _rxComplete; + char _rxBuf[RX_MAX]; + volatile size_t _rxBufLen; + char _rxData[RX_MAX]; + volatile size_t _rxDataLen; + +#if defined(TARGET_BLUEPILL) + PinName _digitalPinName[16] = { NC, NC, D2, D3, D4, D5, D6, D7, D8, NC, D10, D11, D12, D13, D14, D15 }; + PinName _analogPinName[6] = { A0, A1, A2, A3, NC, NC }; +#elif defined(TARGET_BLACKPILL) + PinName _digitalPinName[16] = { NC, NC, D2, D3, D4, D5, D6, D7, D8, NC, D10, D11, D12, D13, D14, D15 }; + PinName _analogPinName[6] = { A0, A1, A2, A3, NC, NC }; +#else + PinName _digitalPinName[16] = { NC, NC, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15 }; + PinName _analogPinName[6] = { A0, A1, A2, A3, A4, A5 }; +#endif + DigitalInOut* _digitalInOuts[8]; + AnalogIn* _analogIns[6]; + PwmOut* _pwmOuts[4]; + IntrInCounter* _intrInCounters[8]; + Servo* _servos[2]; + Encoder* _encoders[2]; + DcMotor* _dcMotors[2]; + MPU6050* _mpu6050; + Timer _mpu6050Timer; + uint32_t _now; + float _deltaT; + bool _mpu6050Available; +public: + + ScilabSerial(PinName tx, PinName rx, int baud = 115200); + + void run(); + void onRx(); + ssize_t write(const void* buffer, size_t length); + void analogRead(); + void pwmWrite(); + void digitalReadWrite(); + void servo(); + void mpu6050(); + void intrInCounter(); + void encoder(); + void dcMotorInit(); + void dcMotor(); + void revision(); + void mpu6050UpdateData(); +}; +#endif +#endif // SCILABSERIAL_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Servo.lib Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/simon/code/Servo/#36b69a7ced07
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,15 @@ +#include "mbed.h" +#include "ScilabSerial.h" + +/** + * @brief + * @note + * @param + * @retval + */ +int main() +{ + ScilabSerial scilab(USBTX, USBRX); + + scilab.run(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Mon Jan 18 19:51:22 2021 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#f2278567d09b9ae9f4843e1d9d393526b9462783
Binary file resources/official_armmbed_example_badge.png has changed