Zu deinem code:
...
on = 0;
if (!on)
...
und
...
on = 1;
if (on)
...
Beide if werden auf diese Weise immer zutreffen

Zu meinem code:
Ein uint8_t ist ein byte und das kann man fast genauso testen wie ein bool.
Wenn es null ist treffen Vergleiche nicht zu (false), wenn es größer ist treffen Vergleiche zu (true). Man kann also wie bei bool 'if (on)' verwenden, muß nur auf 0 oder 1 setzen statt false und true.

In der ISR mach das 'on ^= 0x01;' den Wechsel genauso wie du es im if else beabsichtigst, nur kann der compiler im Vergleich dahinter keinen Blödsinn mehr veranstalten wie wenn du on zwischendurch setzt.
XOR:
0^0 ist 0
1^0 ist 1
0^1 ist 1
1^1 ist 0
Wenn on 1 ist und mit ner 1 xored, wird es 0, aus true wird false.
Wenn on 0 ist und mit ner 1 xored, wird es 1, aus false wird true.

Ausgeschrieben wirds evtl. deutlicher:
on = on ^ 0x01;