1

I'm currently using C to program a microcontroller (microchip PIC18F4520) for a university project, to turn it into a very basic MIDI controller. My code uses the 4520's 10-bit ADC (analogue-digital converter) to read the position of a variable resistor, then conditions that value down to an 8-bit MIDI value. If the MIDI value has changed since the last scan, then it outputs this from the USART as a MIDI CC message (the 3rd byte of a 3-byte message for anyone not familiar with MIDI protocol). However, the output usually ends up flickering between 2 adjacent values, so I'd like to add some hysteresis so that the byte will only be sent to the USART if it's 2 greater or less than the previous MIDI value. The basic gist of my code is this:

while(1){
/*Code here to perform ADC and condition this to a MIDI value - this dedinitely works*/

   if((newMIDIvalue > oldMIDIvalue+2)||(newMIDIvalue < oldMIDIvalue-2)){
   /*Code here to send MIDI CC message to the USART - this also definitely works*/
   }
   
   oldMIDIvalue = newMIDIvalue;
}

I've not posted full code, as it's all specific to the microcontroller I'm using, and wouldn't be particuarly useful. All of the microcontroller-specific code works fine, it's just the logic I'm using to implement hysteresis that isn't doing what I want.

  • 1
    Please clarify what "_isn't doing what I want_" means. What do you want, and what does it instead? – the busybee May 04 '21 at 12:59
  • @Eben I wasn't seeing any ouput from the USART on my MIDI monitor. I've fixed it now; the issue was that `oldMIDIvalue = newMIDIvalue;` was outside the `if` loop, and was updating faster than I could turn the resistor. Moving it inside the loop fixed the issue. Sorry I wasn't clearer initially – Robert Reid May 04 '21 at 13:12
  • 2
    Great! Now you should consider to answer your own question with the correct solution. After some time you can mark it, too. Eben's answer is it not, as I understand it. This will help future visitors with a similar problem. – the busybee May 04 '21 at 13:21
  • Thanks, answer is posted. I'll try and remember to accept it in a few days, but I'd appreciate it if you could upvote it in the meantime to push it up the list – Robert Reid May 04 '21 at 13:56

3 Answers3

2

Issue is now resolved. Placing oldMIDIvalue = newMIDIvalue; outside the if loop meant that the oldMIDIvalue was updated on every cycle, giving the user no time to turn the resistor far enough between cycles. Placing oldMIDIvalue = newMIDIvalue; inside the if loop updated oldMIDIvalue only once an output had been sent from the USART, fixing the problem.

P.S. - this was a difficult issue to find, as the code worked fine during debugging. If breakpoints are set within the if loop and the resistor is turned whilst the code is paused on the breakpoints, there isn't a problem. Part of the issue was that the logic isn't actually flawed on paper, it's just the reality of physical controls that creates the problem. Hopefully this saves someone else the bother!

0

You can try using

if((newMIDIvalue > (oldMIDIvalue+hystereis))||(newMIDIvalue < (oldMIDIvalue-hysteresis))){
   /*Code here to send MIDI CC message to the USART - this also definitely works*/
   }
#define hysteresis   2
moto
  • 38
  • 4
0

Your current code should work, you need to describe more how it doesnt work.

if you feel that your current static hysteris detectection is too simple, you could add a simple filter (add a ring buffer with previous N values and compare to the average of those values).

Eben
  • 157
  • 4