Tutorial 7
Simple user object

Java objects for MCU

Remember tutorial 2? There were 3 flashing LEDs. And we had to write led1.setOutput(Pin.LOW) to turn on the LED. The more convenient way is to create LED object and write something like led.setState(Led.State.ON) With LED the difference is not large, but for complex devices (like LCD) code become easier, safer and more flexible.

User objects in MCU Java source

User objects work in different way than microcontroller classes and listeners. User object's code is compiled and executed on computer, not interpreted. In fact, user classes are translators. So, they can throw exceptions and use other Java langauge features. Here's a template:

//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);
  }
}

User class rules

  1. User class must extend mcujavasource.transformer.userclass.AbstractInstanceUser
  2. Normal constructors are left empty. They mihgt be used for running the program on PC (simulation).
  3. For each normal constructor an translator constructor is added. In translator constructor an InstanceContext context argument is added to beginning, and all object arguments turn to SourceInstance type. The first statement in translator constructor must be super(context);
  4. To invoke a method of SourceInstance, use invoke(SourceInstance si, String methodName, Object... args); For example, pin.setOutput(Pin.LOW); become invoke(pin, "setOutput", Pin.LOW); in user class.
  5. Native code can be included, if appropriate analog cannot be written in Java (for example, code uses assembler). To include a native library, use include(String name), name is a string to write in #include "name" statement. Files with patterns "**/*.c,**/*.cpp,**/*.h,**/*.s,**/*.S,**/*.asm" are copied from src to build directory in NetBeans project. To call a function defined in native code, use callFunction(String functionName, Object... args)

Program

This program works in the same way as tutorial 2. The C code (main.c file) is absolutely equal.

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);
  }
  
}

Download java source file