state machine encoder logic and first simple menu
This commit is contained in:
parent
65ac37fd62
commit
5e12e9a4a0
125
fw/main.c
125
fw/main.c
@ -69,20 +69,64 @@ void handle_usbfs_input(int numbytes, uint8_t *data)
|
||||
}
|
||||
|
||||
|
||||
// triggered on the falling edge of the rotary encoder PIN_A
|
||||
/*
|
||||
* __ ____ ____
|
||||
* A: |____| |____| |____
|
||||
* ____ ____ __
|
||||
* B: ____| |____| |____|
|
||||
* ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
|
||||
* f r r f f r r f f r
|
||||
*/
|
||||
void update_encoder(void)
|
||||
{
|
||||
// 0 = 00, 1 = 01, 2 = 10, 3 = 11
|
||||
static uint8_t last_state = 0;
|
||||
// Lookup table: state_table[last_state][current_state]
|
||||
// 0 = invalid move or bounce (ignore)
|
||||
// 1 = valid forward step
|
||||
// -1 = valid backward step
|
||||
static const int8_t state_table[4][4] = {
|
||||
{ 0, 1, -1, 0}, // from 00
|
||||
{-1, 0, 0, 1}, // from 01
|
||||
{ 1, 0, 0, -1}, // from 10
|
||||
{ 0, -1, 1, 0} // from 11
|
||||
};
|
||||
|
||||
// FIXME: even with interrupts disabled and debounce, a single detent triggers
|
||||
// multiple interrupts, leading to multiple encoder updates in a short time.
|
||||
bool a = funDigitalRead(PIN_ENC_A);
|
||||
bool b = funDigitalRead(PIN_ENC_B);
|
||||
Delay_Us(100);
|
||||
if (a != funDigitalRead(PIN_ENC_A) || b != funDigitalRead(PIN_ENC_B))
|
||||
return; // debounce
|
||||
|
||||
uint8_t current_state = (a << 1) | b;
|
||||
|
||||
// Find the movement direction based on transition
|
||||
encoder += state_table[last_state][current_state];
|
||||
|
||||
// Save current state for the next interrupt
|
||||
last_state = current_state;
|
||||
}
|
||||
|
||||
// Attached to PIN_ENC_A rising and falling edges
|
||||
void EXTI7_0_IRQHandler(void) __attribute__((interrupt));
|
||||
void EXTI7_0_IRQHandler(void)
|
||||
{
|
||||
__disable_irq();
|
||||
update_encoder();
|
||||
EXTI->INTFR = EXTI_Line3;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
// Attached to PIN_ENC_B rising and falling edges
|
||||
void EXTI15_8_IRQHandler(void) __attribute__((interrupt));
|
||||
void EXTI15_8_IRQHandler(void)
|
||||
{
|
||||
uint32_t now = funSysTick32();
|
||||
if (now - last_interrupt > ENCODER_DEBOUNCE) {
|
||||
last_interrupt = now;
|
||||
if (funDigitalRead(PIN_ENC_A)) {
|
||||
encoder++;
|
||||
} else {
|
||||
encoder--;
|
||||
}
|
||||
}
|
||||
__disable_irq();
|
||||
update_encoder();
|
||||
EXTI->INTFR = EXTI_Line11;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
|
||||
@ -354,12 +398,21 @@ __attribute__((noreturn)) int main(void)
|
||||
|
||||
// Configure the IO as an interrupt.
|
||||
// PIN_ENC_B is on port B, channel 11
|
||||
AFIO->EXTICR1 = AFIO_EXTICR1_EXTI11_PB; // Port B channel (pin) 11
|
||||
EXTI->INTENR = EXTI_INTENR_MR11; // Enable EXT11
|
||||
EXTI->FTENR = EXTI_FTENR_TR11; // Falling edge trigger
|
||||
AFIO->EXTICR1 |= AFIO_EXTICR1_EXTI11_PB; // Port B channel (pin) 11
|
||||
EXTI->INTENR |= EXTI_INTENR_MR11; // Enable EXT11
|
||||
EXTI->FTENR |= EXTI_FTENR_TR11; // Falling edge trigger
|
||||
EXTI->RTENR |= EXTI_RTENR_TR11; // Rising edge trigger
|
||||
// enable interrupt
|
||||
NVIC_EnableIRQ(EXTI15_8_IRQn);
|
||||
|
||||
// PIN_ENC_A is on port B, channel 3
|
||||
AFIO->EXTICR1 |= AFIO_EXTICR1_EXTI3_PB; // Port B channel (pin) 3
|
||||
EXTI->INTENR |= EXTI_INTENR_MR3; // Enable EXT3
|
||||
EXTI->FTENR |= EXTI_FTENR_TR3; // Falling edge trigger
|
||||
EXTI->RTENR |= EXTI_RTENR_TR3; // Rising edge trigger
|
||||
// enable interrupt
|
||||
NVIC_EnableIRQ(EXTI7_0_IRQn);
|
||||
|
||||
Delay_Ms(500);
|
||||
|
||||
u8g2 = display_init();
|
||||
@ -388,7 +441,7 @@ __attribute__((noreturn)) int main(void)
|
||||
|
||||
// TODO: let the user decide the power profile
|
||||
pd_profile.set_temp = 200;
|
||||
pd_profile.set_power = 95; // Slightly below max power to avoid overloading
|
||||
pd_profile.set_power = 60; // Slightly below max power to avoid overloading
|
||||
pd_profile.tip_r = 2500; // TODO: tip check and resistance calculator
|
||||
pd_profile.max_duty = MIN(
|
||||
(100*(u32)isqrt((
|
||||
@ -416,6 +469,10 @@ __attribute__((noreturn)) int main(void)
|
||||
}
|
||||
|
||||
|
||||
enum {
|
||||
STATE_MENU,
|
||||
STATE_HEATING,
|
||||
} state = STATE_MENU;
|
||||
for (;;) {
|
||||
u32 start = funSysTick32();
|
||||
poll_input(); // usb
|
||||
@ -428,6 +485,9 @@ __attribute__((noreturn)) int main(void)
|
||||
static bool pwm = false; // PWM status
|
||||
static bool enabled = false; // Power electronics enabled
|
||||
static uint8_t count = 0; // Loop cycles with PWM on
|
||||
static s32 elapsed = 0;
|
||||
static bool prev_btn = true;
|
||||
bool btn = funDigitalRead(PIN_BTN);
|
||||
|
||||
if (has_pd) {
|
||||
static uint16_t vbus_mv, current_ma;
|
||||
@ -446,6 +506,26 @@ __attribute__((noreturn)) int main(void)
|
||||
tip_temp_c = I16_FP_EMA_K2(tip_temp_c, (tip_mv*TC_CONV_NOM)/TC_CONV_DEN) + temp_c;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case STATE_MENU:
|
||||
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "TEMP:");
|
||||
u8g2_DrawStr(u8g2, x_off+25, y_off+7, u8g2_u16toa(pd_profile.set_temp, 4));
|
||||
|
||||
if (encoder != 0) {
|
||||
pd_profile.set_temp += encoder;
|
||||
encoder = 0;
|
||||
#define MIN_TEMP 100
|
||||
#define MAX_TEMP 360
|
||||
if (pd_profile.set_temp < MIN_TEMP) pd_profile.set_temp = MIN_TEMP;
|
||||
if (pd_profile.set_temp > MAX_TEMP) pd_profile.set_temp = MAX_TEMP;
|
||||
}
|
||||
|
||||
if (btn == 0 && prev_btn == 1) {
|
||||
state = STATE_HEATING;
|
||||
enabled = false;
|
||||
}
|
||||
break;
|
||||
case STATE_HEATING:
|
||||
// Display tip temperature
|
||||
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "TIP:");
|
||||
u8g2_DrawStr(u8g2, x_off+20, y_off+7, u8g2_u16toa(tip_temp_c, 4));
|
||||
@ -497,9 +577,14 @@ __attribute__((noreturn)) int main(void)
|
||||
funDigitalWrite(PIN_12V, 0);
|
||||
}
|
||||
|
||||
// move to menu mode when encoder is turned
|
||||
if (encoder != 0) {
|
||||
state = STATE_MENU;
|
||||
funDigitalWrite(PIN_12V, 0);
|
||||
pwm_set(0);
|
||||
}
|
||||
|
||||
// Check button to toggle enable
|
||||
static bool prev_btn = true;
|
||||
bool btn = funDigitalRead(PIN_BTN);
|
||||
if (btn == 0 && prev_btn == 1) {
|
||||
enabled = !enabled;
|
||||
if (enabled) {
|
||||
@ -508,8 +593,8 @@ __attribute__((noreturn)) int main(void)
|
||||
pwm_off();
|
||||
}
|
||||
}
|
||||
prev_btn = btn;
|
||||
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// No PD capability, just display a message
|
||||
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "NO PD");
|
||||
@ -517,7 +602,9 @@ __attribute__((noreturn)) int main(void)
|
||||
|
||||
u8g2_SendBuffer(u8g2);
|
||||
|
||||
s32 elapsed = funSysTick32() - start;
|
||||
prev_btn = btn;
|
||||
|
||||
elapsed = funSysTick32() - start;
|
||||
if (elapsed > 0 && elapsed < Ticks_from_Ms(FRAME_TIME_MS)) {
|
||||
DelaySysTick(Ticks_from_Ms(FRAME_TIME_MS) - elapsed);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user