Questão inicial
Eu tenho uma pergunta geral sobre o manuseio de interrupções em microcontroladores. Estou usando o MSP430, mas acho que a pergunta pode ser estendida a outros UCs. Gostaria de saber se é uma boa prática ativar / desativar as interrupções com frequência ao longo do código. Quero dizer, se eu tenho uma parte do código que não será sensível a interrupções (ou, pior ainda, não deve ouvir interrupções, por qualquer motivo), é melhor:
- Desative as interrupções antes e depois as reative após a seção crítica.
- Coloque um sinalizador dentro do respectivo ISR e (em vez de desativar a interrupção), defina o sinalizador como false antes da seção crítica e redefina-o para true, logo após. Para impedir que o código do ISR seja executado.
- Nenhum dos dois, então sugestões são bem-vindas!
Atualização: interrupções e gráficos de estado
Vou fornecer uma situação específica. Vamos supor que queremos implementar um gráfico de estados, composto por 4 blocos:
- Transições / Efeito.
- Condições de saída.
- Atividade de entrada.
- Faça atividade.
Isso é o que um professor nos ensinou na universidade. Provavelmente, não é a melhor maneira de fazer isso, seguindo este esquema:
while(true) {
/* Transitions/Effects */
//----------------------------------------------------------------------
next_state = current_state;
switch (current_state)
{
case STATE_A:
if(EVENT1) {next_state = STATE_C}
if(d == THRESHOLD) {next_state = STATE_D; a++}
break;
case STATE_B:
// transitions and effects
break;
(...)
}
/* Exit activity -> only performed if I leave the state for a new one */
//----------------------------------------------------------------------
if (next_state != current_state)
{
switch(current_state)
{
case STATE_A:
// Exit activity of STATE_A
break;
case STATE_B:
// Exit activity of STATE_B
break;
(...)
}
}
/* Entry activity -> only performed the 1st time I enter a state */
//----------------------------------------------------------------------
if (next_state != current_state)
{
switch(next_state)
{
case STATE_A:
// Entry activity of STATE_A
break;
case STATE_B:
// Entry activity of STATE_B
break;
(...)
}
}
current_state = next_state;
/* Do activity */
//----------------------------------------------------------------------
switch (current_state)
{
case STATE_A:
// Do activity of STATE_A
break;
case STATE_B:
// Do activity of STATE_B
break;
(...)
}
}
Suponhamos também que, digamos STATE_A
, eu queira ser sensível a uma interrupção vinda de um conjunto de botões (com sistema de desacoplamento, etc. etc.). Quando alguém pressiona um desses botões, uma interrupção é gerada e o sinalizador relacionado à porta de entrada é copiado em uma variável buttonPressed
. Se o debounce estiver definido para 200 ms de alguma forma (watchdog timer, timer, counter, ...), temos certeza de que buttonPressed
não será possível atualizar com um novo valor antes de 200 ms. É isso que estou perguntando a você (e a mim mesmo :), é claro)
Preciso ativar a interrupção na atividade DO STATE_A
e desativar antes de sair?
/* Do activity */
//-------------------------------------
switch (current_state)
{
case STATE_A:
// Do activity of STATE_A
Enable_ButtonsInterrupt(); // and clear flags before it
// Do fancy stuff and ...
// ... wait until a button is pressed (e.g. LPM3 of the MSP430)
// Here I have my buttonPressed flag ready!
Disable_ButtonsInterrupt();
break;
case STATE_B:
// Do activity of STATE_B
break;
(...)
}
De uma maneira que tenho certeza de que na próxima vez em que executo o bloco 1 (transição / efeitos) na próxima iteração, tenho certeza de que as condições verificadas ao longo das transições não são provenientes de uma interrupção subsequente que substituiu o valor anterior buttonPressed
daquele precisa (embora seja impossível que isso aconteça porque 250 ms devem decorrer).