Учебник 7
Простой пользовательский объект

Объекты Java для ЖКИ

Помните учебник 2? Там мигали 3 светодиода. И мы писали led1.setOutput(Pin.LOW), чтоб включить светодиод. Однако удобнее создать объект Светодиод (LED) и написать что-то вроде led.setState(Led.State.ON) Для простого светодиода разница небольшая, но для сложных объектов (вроде ЖКИ) код становится проще, безопаснее и гибче.

Пользовательские объекты в MCU Java source

Объекты пользователя работают иначе, чем основной класс и слушатели. Код объекта пользователя компилируется и выполняется на компьютере, а не интерпретируется. Значит, он может выбрасывать исключения и использовать другие возможности языка Java. Вот шаблон:

//packages for user objects
import mcujavasource.transformer.instance.*;
import mcujavasource.transformer.userclass.*;

class MyObject extends AbstractInstanceUser
{
  private SourceInstance pin;
  
  public MyObject(Pin pin)
  { //only for running on PC
  }
  
  public MyObject(InstanceContext context, SourceInstance pin)
  { super(context);
    this.pin = pin;
    invoke(pin, "setDirection", Pin.OUT);
  }
  
  public void method()
  { invoke(pin, "pinMethod", args);
  }
}

Правила пользовательского объекта

  1. Пользовательский объект должен расширять (extend) mcujavasource.transformer.userclass.AbstractInstanceUser
  2. Обычные конструкторы остаются пустыми. Они, наверное, будут использоваться для выполнения программы на компьютере (симуляции).
  3. Для каждого обычного конструктора добавляется конструктор переводчика. В конструкторе переводчика аргумент InstanceContext context добавляется первым аргументом и все аргументы-объекты становятся типа SourceInstance. Первый оператор должен быть super(context);
  4. Чтобы вызвать метод экземпляра SourceInstance, используйте invoke(SourceInstance si, String methodName, Object... args); Например, pin.setOutput(Pin.LOW); становится invoke(pin, "setOutput", Pin.LOW); в пользовательском объекте.
  5. Код на С можно вставить (include), если аналогичный код невозможно написать на Java (например, используется ассемблер). Для вставки файла на С используется include(String name), name - имя файла, которое будет вставлено в оператор #include "name" Файлы по маске "**/*.c,**/*.cpp,**/*.h,**/*.s,**/*.S,**/*.asm" копируются из папки src в build в проекте NetBeans. Чтобы вызвать функцию, описанную в файле на С, вызвите метод callFunction(String functionName, Object... args)

Программа

Программа работает так же, как и в учебнике 2. Результирующий С код (файл main.c) абсолютно одинаковый.

import mcujavasource.mcu.*;

//packages for user objects
import mcujavasource.transformer.instance.*;
import mcujavasource.transformer.userclass.*;

/** Tutorial 7: simple user object.
 * It's tutorial 2, rewritten with SimpleLed object.
 * Three LEDs flash one after another.
 * Default 8-bit timer and its overflow interrupt is used for delay.
 * LED's anode is connected to +5V through 330 Ohm resistor,
 * cathode - to MCU port.
 */
public class Main extends Microcontroller
{
  /** Pin of the first LED, PB1 */
  private final Pin led1Pin = getHardware().getPort("B").getPin(1);
  
  /** Pin of the second LED, PB0 */
  private final Pin led2Pin = getHardware().getPort("B").getPin(0);
  
  /** Pin of the third LED, PB2 */
  private final Pin led3Pin = getHardware().getPort("B").getPin(2);
  
  private SimpleLed led1;
  private SimpleLed led2;
  private SimpleLed led3;
  
  
  private Timer timer;
  
  private volatile int currentLed = 0;
  
  public void init()
  { //register initialization on startup
    getHardware().setAllPortsDirection(Pin.IN);
    getHardware().setAllPortsPullUp(true);
    led1 = new SimpleLed(led1Pin);
    led2 = new SimpleLed(led2Pin);
    led3 = new SimpleLed(led3Pin);
    // led1 is initially turned on
    led1.setState(SimpleLed.State.ON);
    // getting default 8-bit timer
    timer = getHardware().getDefaultTimer(8);
    timer.setMode(TimerMode.NORMAL);
    // no prescaling
    timer.setPrescaling(1);
    timer.setEnabled(true);
    LedSwitcher ledSwitcher = new LedSwitcher();
    timer.addTimerListener(ledSwitcher);
    timer.setTimerOverflowedFired(true); //this enables interrupt
  }
  
  public void start()
  { //main program
    getHardware().setInterruptsEnabled(true);
  }
  
  private class LedSwitcher implements TimerListener
  {
    public void timerOverflowed()
    { currentLed++;
      if(currentLed >= 3) currentLed = 0;
      switch(currentLed)
      { case 0:
          led3.setState(SimpleLed.State.OFF); //turn off led3
          led1.setState(SimpleLed.State.ON); //turn on led1
          break;
        case 1:
          led1.setState(SimpleLed.State.OFF);
          led2.setState(SimpleLed.State.ON);
          break;
        case 2:
          led2.setState(SimpleLed.State.OFF);
          led3.setState(SimpleLed.State.ON);
          break;
      }
    }
    
  }
  
}

class SimpleLed extends AbstractInstanceUser
{
  public enum State { ON, OFF };
  
  private SourceInstance pin;
  
  /** Creates a SimpleLed from the given pin.
   * Initial state is OFF.
   */
  public SimpleLed(Pin pin)
  { //only for running on PC
  }
  
  //Pin class turned into SourceInstance, and InstanceContext context added
  public SimpleLed(InstanceContext context, SourceInstance pin)
  { super(context);
    this.pin = pin;
    invoke(pin, "setDirection", Pin.OUT);
    invoke(pin, "setOutput", true);
  }
  
  public void setState(State state)
  { boolean value = (state == State.OFF);
    invoke(pin, "setOutput", value);
  }
  
}

Скачать файл исходного кода программы