248 lines
7.3 KiB
C

/*****************************************************************************
* MIDI Footswitch *
* Copyright (C) 2014-2018 Stefan Kalscheuer *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation version 3. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
*****************************************************************************/
/**
* MIDI Footswitch
*
* @file midifs.c
* @author Stefan Kalscheuer
* @date 2014-06-17
* @brief Main program
*
* Platform: ATtiny2313
* Internal RC-oscillator 8 MHz
*/
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "midifs.h"
#include "usart.h"
// Counter for debouncing inputs.
volatile uint16_t counterBtn1 = 0;
volatile uint16_t counterBtn2 = 0;
volatile uint16_t counterBtn3 = 0;
volatile uint16_t counterBtn4 = 0;
volatile uint16_t counterSw1 = 0;
volatile uint16_t counterSw2 = 0;
// Input states.
volatile uint8_t stateBtn1 = 0;
volatile uint8_t stateBtn2 = 0;
volatile uint8_t stateBtn3 = 0;
volatile uint8_t stateBtn4 = 0;
volatile uint8_t stateSw1 = 0;
volatile uint8_t stateSw2 = 0;
// Channel, bank and tuner states.
volatile uint8_t currentChannel = 0;
volatile uint8_t currentBank = 0;
volatile uint8_t currentTuner = 0;
// Global interrupt counter.
uint16_t cnt = 0;
/**
* Switch to given bank.
*
* @param bank Bank number (supported 1 and 2).
* @return void
*/
void setBank(uint8_t bank) {
if (bank == 0) {
USART_Transmit(0xB0); // Bank 1
USART_Transmit(0x00);
USART_Transmit(0x00);
USART_Transmit(0xC0);
USART_Transmit(0x00);
USART_Transmit(currentChannel);
OUT_LED &= ~(1 << LED_RT); // LED green
OUT_LED |= (1 << LED_GN);
} else {
USART_Transmit(0xB0); // Bank 2
USART_Transmit(0x00);
USART_Transmit(0x01);
USART_Transmit(0xC0);
USART_Transmit(0x00);
USART_Transmit(currentChannel);
OUT_LED &= ~(1 << LED_GN); // LED green
OUT_LED |= (1 << LED_RT);
}
}
/**
* Main routine.
*
* @return This method should never terminate.
*/
int main(void) {
DDRB = 0x00; // PB1..7 as inputs
PORTB = 0xFF; // interlan pull-ups for PB0..7y
DDRD = 0x30; // PD4..5 as outputs
PORTD = 0x0C; // internal pull-ups for PD2..3
OUT_LED = 0x30; // LEDs off
// Timer1 init
TCCR1A |= (1 << WGM01); // Set timer 0 to CTC-Mode
TCCR1B &= ~(1 << CS10); // Prescaler 8 (1MHz)
TCCR1B |= (1 << CS11);
TCCR1B &= ~(1 << CS12);
OCR1A = 499; // Pperiod of 1 ms
cli(); // Disable interrupts
TIMSK |= (1 << TOIE1); // Activate timer 1
sei(); // Enable interrupts
//USART_Init(38400); // Initialize USART with 38400 baud (debug)
USART_Init(31250); // Initialize USART with 31250 baud
while (1) {
if (counterBtn1 > BTN_THRESHOLD && stateBtn1 == 0) { // Button 1
setBank(currentBank);
USART_Transmit(0xC0); // Channel 1
USART_Transmit(0x00);
currentChannel = 0;
currentTuner = 0;
stateBtn1 = 1;
} else if (counterBtn1 < BTN_THRESHOLD && stateBtn1 == 1) {
stateBtn1 = 0;
}
if (counterBtn2 > BTN_THRESHOLD && stateBtn2 == 0) { // Button 2
setBank(currentBank);
USART_Transmit(0xC0); // Channel 2
USART_Transmit(0x01);
currentChannel = 1;
currentTuner = 0;
stateBtn2 = 1;
} else if (counterBtn2 < BTN_THRESHOLD && stateBtn2 == 1) {
stateBtn2 = 0;
}
if (counterBtn3 > BTN_THRESHOLD && stateBtn3 == 0) { // Button 3
setBank(currentBank);
USART_Transmit(0xC0); // Channel 3
USART_Transmit(0x02);
currentChannel = 2;
currentTuner = 0;
stateBtn3 = 1;
} else if (counterBtn3 < BTN_THRESHOLD && stateBtn3 == 1) {
stateBtn3 = 0;
}
if (counterBtn4 > BTN_THRESHOLD && stateBtn4 == 0) { // Button 4
USART_Transmit(0xB0); // Tuner on
USART_Transmit(0x0F);
USART_Transmit(0x7F);
//OUT_LED |= (1 << LED_RT); // LEDs off
//OUT_LED |= (1 << LED_GN);
currentTuner = 1;
stateBtn4 = 1;
} else if (counterBtn4 < BTN_THRESHOLD && stateBtn4 == 1) {
stateBtn4 = 0;
}
if (counterSw1 > BTN_THRESHOLD && stateSw1 == 0) { // Switch Pos. 1
setBank(0);
currentBank = 0;
currentTuner = 0;
stateSw1 = 1;
} else if (counterSw1 < BTN_THRESHOLD && stateSw1 == 1) {
stateSw1 = 0;
}
if (counterSw2 > BTN_THRESHOLD && stateSw2 == 0) { // Switch Pos. 2
setBank(1);
currentBank = 1;
currentTuner = 0;
stateSw2 = 1;
} else if (counterSw2 < BTN_THRESHOLD && stateSw2 == 1) {
stateSw2 = 0;
}
}
}
/**
* interrupt function: TIMER1_OVF1_vect
*
* Timer interrupt. Increments counters for inputs
*/
ISR(TIMER1_OVF_vect) {
if (++cnt == 250) {
cnt = 0;
}
if (currentTuner == 1 && cnt == 1) {
if (currentBank == 1) {
OUT_LED ^= (1 << LED_GN);
} else {
OUT_LED ^= (1 << LED_RT);
}
}
if (bit_is_clear(IN_BTN, BTN1) && counterBtn1 < BTN_MAX) { // Button 1
counterBtn1++;
} else if (counterBtn1 > 0) {
counterBtn1--;
}
if (bit_is_clear(IN_BTN, BTN2) && counterBtn2 < BTN_MAX) { // Button 2
counterBtn2++;
} else if (counterBtn2 > 0) {
counterBtn2--;
}
if (bit_is_clear(IN_BTN, BTN3) && counterBtn3 < BTN_MAX) { // Button 3
counterBtn3++;
} else if (counterBtn3 > 0) {
counterBtn3--;
}
if (bit_is_clear(IN_BTN, BTN4) && counterBtn4 < BTN_MAX) { // Button 4
counterBtn4++;
} else if (counterBtn4 > 0) {
counterBtn4--;
}
if (bit_is_clear(IN_SW, SW1) && counterSw1 < BTN_MAX) { // Switch 1
counterSw1++;
} else if (counterSw1 > 0) {
counterSw1--;
}
if (bit_is_clear(IN_SW, SW2) && counterSw2 < BTN_MAX) { // Switch 2
counterSw2++;
} else if (counterSw2 > 0) {
counterSw2--;
}
}