wokwi / avr8js

Arduino (8-bit AVR) simulator, written in JavaScript and runs in the browser / Node.js
https://blog.wokwi.com/avr8js-simulate-arduino-in-javascript/
MIT License
463 stars 73 forks source link

Attaching pushbutton input to PIN register #26

Closed gfeun closed 4 years ago

gfeun commented 4 years ago

Hello again !

So I have made some progress on my virtual training board using avr8js. I have 8 leds + 8 pushbutton. Using demo project it was quite easy to set up.

I am now wondering if there is a "nice" way to hook up the pushbuttons to a specific µController GPIO port.

What I am doing now is register some event listener on the push-button events. On event, I access cpu register directly and modify the internal cpu data field of the corresponding register

function buttonPress(e :Event) {
  const id = e.target.id.slice(-1)
  const bitMask = 1 << id;
  runner.cpu.data[runner.portC.portConfig.PIN] = runner.cpu.data[runner.portC.portConfig.PIN] | bitMask
}

function buttonRelease(e :Event) {
  const id = e.target.id.slice(-1)
  const bitMask = ~(1 << id);
  runner.cpu.data[runner.portC.portConfig.PIN] = runner.cpu.data[runner.portC.portConfig.PIN] & bitMask
}

// buttons ids are "button1", "button2"
const buttonModule = new Array<PushButtonElement>(8);
for(let i=0; i<buttonModule.length; i++) {
  buttonModule[i] = document.querySelector<PushButtonElement>("wokwi-pushbutton[id=button"+i+"]");
  buttonModule[i].addEventListener("button-press", buttonPress, false)
  buttonModule[i].addEventListener("button-release", buttonRelease, false)
}

This is working, with the following code i have a "blink led according to button pressed":

setup() {
  DDRB = 0xFF;
  DDRC = 0x00;
}
loop() {
  delay(500);
  PORTB = PINC;
  delay(500);
  PORTB = 0;
}

But i find modifying the internal cpu data directly looks like a hack and i may have missed the "proper" way to do it. Do you have any recommendation or good practice on how to do it ?

Thank you !

urish commented 4 years ago

Hi Glenn!

Great to hear from you again :-)

At the moment, the GPIO module only includes the pinState() function, which queries the current state of the pins.

It does make a lot of sense to add another method that will let you set the state of a pin. One of the main challenges is correctly dealing with pull-ups. For instance, let's say that your virtual button connects the pin with GND. When the button is not pressed, the pin is floating. What value should the user code get when reading from the pin if the pull-up is not used?

urish commented 4 years ago

We now have a new setPin() method for this purpose. Note that this is a breaking change since now setting the PIN memory location directly (as you did above) will be overridden by the AVRIOPort class. The new method should be a part of the upcoming 0.9.0 release

urish commented 4 years ago

Released as part of 0.9.0