Teach lesson
Lógica digital na DE1-SoC com VHDL (6/6): projeto final de FSM — máquina de venda automática
Construa uma FSM VHDL de máquina de venda automática, teste os caminhos de crédito no hardware e, se houver tempo, experimente checkpoints opcionais.
New to LabsLand? Create your teacher account
Learning Outcomes
Executar e explicar uma máquina de estados finitos não trivial em hardware real.
Construir um controlador de máquina de venda cujo estado represente o crédito acumulado.
Reconhecer a devolução de troco, a seleção de produto e o display decimal como checkpoints guiados opcionais.
Explicar por que o projeto básico precisa memorizar estados de crédito e, se fizer o 3-C2, raciocinar sobre estados e flip-flops.
Student activity preview
Activity Content
Preview only. In a class session, students can fill in responses and submit their work to the teacher.
Do semáforo ao controlador: uma FSM que guarda seu dinheiro
8 min
Na Lição 5, você construiu uma máquina de estados finitos cujo estado representava uma posição abstrata em um ciclo: um semáforo que passava de verde para amarelo e depois para vermelho. Se fez o detector opcional, você também viu um estado guardar parte de um padrão. Neste projeto final, o estado representa algo concreto e físico: quanto dinheiro foi inserido até agora. Você construirá um pequeno controlador de máquina de venda automática; os checkpoints opcionais permitem ampliá-lo recurso por recurso.
Lembre-se de que uma máquina de estados finitos possui três partes: um conjunto de estados, uma regra para o próximo estado a partir do estado atual e das entradas e uma saída que depende do estado — e, em uma máquina de Mealy, também das entradas. A habilidade nova desta lição é o projeto: primeiro você decide quais estados são necessários e desenha a tabela de transições; só depois escreve o VHDL.
Para uma máquina que recebe moedas, a escolha natural é fazer cada estado representar um nível de crédito. Se ela aceita moedas de 5 e 10 centavos e libera o produto ao chegar a 15 centavos, o crédito pode ser 0, 5, 10 ou 15 centavos — quatro estados. Vamos chamá-los de S0, S5, S10 e S15. Inserir uma moeda leva a um estado de crédito maior; alcançar o preço libera o produto e devolve a máquina a S0.
Os sinais da placa são os mesmos de sempre. Como este é um projeto sequencial, acionado por clock, a própria entidade declara o clock: o modelo padrão blink.vhd não possui clock, portanto acrescentamos CLOCK_50 : in std_logic. Como na Lição 5, uma chave levantada vale 1; KEY é ativo em nível baixo, portanto um botão pressionado vale 0; LEDR é ativo em nível alto; e HEX0–HEX5 são displays de sete segmentos ativos em nível baixo.
A máquina de venda como diagrama de estados de crédito. Cada estado representa um nível de crédito. Uma moeda de 5 centavos, SW(0), avança um estado; uma moeda de 10 centavos, SW(1), avança dois. Os caminhos de preço exato chegam primeiro a S15; no pulso seguinte, S15 ativa a liberação e retorna a S0. Os checkpoints opcionais posteriores acrescentam uma segunda saída, a devolução de troco, e mais estados para a seleção de produto.
A máquina básica usa quatro estados separados: S0, S5, S10, S15. Por que ela precisa de um estado diferente para cada nível de crédito? O que ela *não* conseguiria fazer se tivesse apenas um estado?
LEDR(7), liberação, fica retido e permanece aceso até você pressionar KEY(0). Depois que o produto é liberado e a máquina volta a S0, o que apaga essa retenção? Que problema surgiria se nada a apagasse?
Exercício 3-C: FSM da máquina de venda automática
14 min
Este é o projeto básico completo. Leia-o como uma FSM nos três blocos que agora já são familiares: um divisor de clock, para que a inserção de moedas ocorra em um ritmo humano; um bloco combinacional de próximo estado e saída; e um registrador de estado acionado por clock, com reset assíncrono ativo em nível baixo.
Os estados. S0, S5, S10, S15 são os quatro níveis de crédito nomeados. O crédito atual em centavos é derivado explicitamente de comparações de estado e mostrado de duas formas: em LEDR(3 downto 0), como um número binário de centavos, e em HEX0, como um único caractere: 0 para 0 centavos, 5 para 5, A para 10 e F para 15. Esses são simplesmente os dígitos hexadecimais de valor 0, 5, 10 e 15.
As transições — esta é a tabela que você desenharia primeiro ao projetar:
Resumo das transições:
- S0, 0 centavos: moeda de 5 -> S5; moeda de 10 -> S10; não libera.
- S5, 5 centavos: moeda de 5 -> S10; moeda de 10 -> S15; não libera.
- S10, 10 centavos: moeda de 5 -> S15; moeda de 10 -> S0 e libera ao chegar a 20 centavos, sem troco na versão básica.
- S15, 15 centavos: no pulso seguinte -> S0 e libera, independentemente da entrada.
Dois detalhes merecem atenção. Em S10, inserir uma moeda de 10 centavos chega a 20 — mais do que o preço de 15 — portanto a máquina libera o produto e volta a S0, mas nesta versão básica não devolve troco. O checkpoint seguinte corrige isso. E S15 é um estado de “liberar e reiniciar”: no pulso seguinte, ele ativa dispense e volta a S0, independentemente da entrada. Portanto, quando as moedas totalizam exatamente 15 centavos, você verá o crédito chegar a F; no pulso seguinte, o produto será liberado.
A saída de liberação é retida. dispense é um sinal de um pulso. Como no detector da Lição 5, é fácil perder um pulso único na câmera remota. Por isso, nós o guardamos em dispensed_latch, ligamos esse valor a LEDR(7) e o apagamos apenas no reset. Assim, depois da liberação, LEDR(7) permanece aceso até você pressionar KEY(0).
Inserção de moeda — temporização. O divisor usa DIV = 16,666,666, portanto slow_clk alterna aproximadamente a cada 0,33 s, mas a FSM amostra moedas apenas nas bordas de subida. Na prática, considere que um pulso de moeda dura cerca de 0,67 s. Para inserir uma moeda, levante uma chave, espere pelo menos uma borda de subida e abaixe-a novamente para 0. Manter uma chave levantada por vários pulsos contaria como várias moedas. Insira uma moeda por vez.
-- Código inicial do estudante: preencha as linhas TODO antes de sintetizar.
-- Lição 6 - Exercício 3-C: projeto básico da FSM da máquina de venda automática.
-- SW(0)=moeda de 5 centavos, SW(1)=moeda de 10, KEY(0)=reset. LEDR(7)=retenção de liberação.
-- Para inserir uma moeda, mantenha SW(0) ou SW(1) em 1 durante uma borda de subida de slow_clk, cerca de 0,67 s.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity blink is
port (
CLOCK_50 : in std_logic;
KEY : in std_logic_vector(3 downto 0);
SW : in std_logic_vector(9 downto 0);
LEDR : out std_logic_vector(9 downto 0);
HEX0 : out std_logic_vector(6 downto 0)
);
end entity blink;
architecture rtl of blink is
type state_t is (S0, S5, S10, S15);
signal state, next_state : state_t := S0;
signal dispense, dispensed_latch : std_logic := '0';
signal credit : unsigned(3 downto 0);
constant DIV : unsigned(24 downto 0) := to_unsigned(16666666, 25);
signal div_count : unsigned(24 downto 0) := (others => '0');
signal slow_clk : std_logic := '0';
function seg(d : unsigned(3 downto 0)) return std_logic_vector is
begin
case d is
when "0000" => return "1000000"; -- 0
when "0101" => return "0010010"; -- 5
when "1010" => return "0001000"; -- A = 10
when "1111" => return "0001110"; -- F = 15
when others => return "1111111";
end case;
end function;
begin
process(CLOCK_50)
begin
if rising_edge(CLOCK_50) then
if KEY(0) = '0' then
div_count <= (others => '0'); slow_clk <= '0';
elsif div_count = DIV then
div_count <= (others => '0'); slow_clk <= not slow_clk;
else
div_count <= div_count + 1;
end if;
end if;
end process;
process(state, SW)
begin
next_state <= state;
dispense <= '0';
case state is
when S0 => TODO_FROM_0_CENTS;
when S5 => TODO_FROM_5_CENTS;
when S10 => TODO_FROM_10_CENTS;
when S15 => TODO_DISPENSE_AND_RESET;
end case;
end process;
process(slow_clk, KEY)
begin
if KEY(0) = '0' then
state <= S0; dispensed_latch <= '0';
elsif rising_edge(slow_clk) then
state <= next_state;
if TODO_DISPENSE_CONDITION then dispensed_latch <= '1'; end if;
end if;
end process;
credit <= to_unsigned(0, 4) when state = S0 else
to_unsigned(5, 4) when state = S5 else
to_unsigned(10, 4) when state = S10 else
to_unsigned(15, 4);
LEDR(7) <= TODO_DISPENSE_LED;
LEDR(3 downto 0) <= std_logic_vector(credit);
LEDR(6) <= '0'; -- substitua esta linha por change_latch na extensão 3-C1
LEDR(5 downto 4) <= (others => '0');
LEDR(9 downto 8) <= (others => '0');
HEX0 <= seg(credit);
end architecture rtl;Partindo de S0, preveja antes de executar: que sequência de caracteres aparecerá em HEX0 e quando LEDR(7), liberação, acenderá se você inserir uma moeda de 10 centavos e depois uma de 5, uma por pulso?
Execute a máquina: moedas, liberação e reset
14 min
Construa o controlador na placa real, insira moedas por dois caminhos diferentes e confirme que o LED de liberação permanece aceso.
Abra o laboratório VHDL da DE1-SoC. O editor mostra o arquivo
blink.vhd.Selecione todo o conteúdo de
blink.vhde substitua-o pelo código inicial da máquina de venda acima. Preencha todas as transições, condições e saídasTODO, mantenha a entidade com o nomeblinke observe que ela declaraCLOCK_50 : in std_logic: o modelo não acrescenta o clock automaticamente.Selecione Sintetizar (
Synthesize). Se um tour guiado cobrir o botão, feche-o ou pule-o. Espere de 1 a 3 minutos, corrija qualquer erro de digitação e sintetize outra vez. Continue apenas quando a compilação terminar com 0 erros.Selecione Enviar para a FPGA (
Upload to FPGA) e aguarde a placa ao vivo e a câmera.Pressione e solte
KEY(0)para reiniciar.HEX0deve mostrar0eLEDR(7)deve estar apagado.Três moedas de 5. Levante
SW(0), espere cerca de 0,67 s por um pulso de moeda e abaixeSW(0).HEX0passa a5. Repita para chegar aA, 10 centavos, e mais uma vez para chegar aF, 15. No pulso seguinte, o produto é liberado:LEDR(7)acende eHEX0volta a0.LEDR(7)permanece aceso.Pressione
KEY(0)para reiniciar:LEDR(7)apaga eHEX0mostra0.Moeda de 5 + moeda de 5 + moeda de 10. Insira duas moedas de 5 (
HEX0:0→5→A) e depois uma de 10 emSW(1). A partir de S10, ela leva o total a 20 centavos; a máquina libera imediatamente e volta a S0.LEDR(7)acende.Pressione
KEY(0)para reiniciar antes do checkpoint seguinte.
Comece pelo reset. Insira uma moeda por pulso e registre HEX0 e LEDR(7). No caminho de preço exato, registre a linha em que o crédito chega primeiro a F com a liberação ainda apagada; depois espere mais um pulso e registre a linha da liberação. Em seguida, reinicie e faça o caminho de duas moedas de 5 mais uma de 10.
| Moeda inserida | Crédito em HEX0 (0/5/A/F) | LEDR(7) liberou? (sim/não) |
|---|---|---|
Envie sua evidência. Depois que três moedas de 5 fizerem a máquina liberar o produto, faça uma captura da câmera com LEDR(7) aceso e anexe-a abaixo.
Quando o crédito chega a 15 centavos e HEX0 mostra F, o produto não é liberado no mesmo pulso: isso acontece no pulso seguinte. Observando o caso S15 no código, explique em uma frase por quê.
No projeto básico, inserir uma moeda de 10 a partir de S10 chega a 20 centavos e libera o produto, mas o cliente perde 5 centavos. Que saída você precisa acrescentar para corrigir isso e em qual único caso ela se aplica?
Checkpoint 3-C1 opcional: acrescente a devolução de troco
12 min
Se o professor quiser propor uma extensão, este checkpoint opcional corrige o caso injusto que você acabou de identificar. Quando a máquina chega a 20 centavos — o único caminho com pagamento a mais, S10 seguido de uma moeda de 10 —, ela deve acender um segundo LED, LEDR(6), com o significado de “devolver 5 centavos de troco”, além de liberar o produto em LEDR(7). Nenhuma outra liberação, exatamente a 15 centavos, devolve troco.
Esta é uma alteração pequena e precisa na FSM. Você precisa de uma segunda saída retida, change_latch, ligada a LEDR(6) e ativada sempre que a máquina liberar o produto *pelo caminho de 20 centavos*. A forma mais limpa é acrescentar um sinal combinacional change ao lado de dispense, ativá-lo somente no ramo S10 + moeda de 10, retê-lo exatamente como dispensed_latch e substituir a linha básica LEDR(6) <= '0'; por LEDR(6) <= change_latch;.
Este é o comportamento esperado após sua alteração:
Comportamento esperado no checkpoint:
- Três moedas de 5 (5+5+5): o crédito chega a 15 centavos; espere mais um pulso, então LEDR(7), liberação = sim; LEDR(6), troco = não; retorna a S0.
- Moeda de 5 + moeda de 10 (5+10): o crédito chega a 15 centavos; espere mais um pulso, então LEDR(7), liberação = sim; LEDR(6), troco = não; retorna a S0.
- Moeda de 10 + moeda de 5 (10+5): o crédito chega a 15 centavos; espere mais um pulso, então LEDR(7), liberação = sim; LEDR(6), troco = não; retorna a S0.
- Moeda de 5 + moeda de 5 + moeda de 10 (5+5+10): o crédito chega a 20 centavos; LEDR(7), liberação = sim; LEDR(6), troco = sim; retorna a S0.
- Duas moedas de 10 (10+10): o crédito chega a 20 centavos; LEDR(7), liberação = sim; LEDR(6), troco = sim; retorna a S0.
Implemente a alteração e confirme na placa que LEDR(6) acende somente em um caminho de 20 centavos e nunca em um caminho de exatamente 15 centavos.
Edite a entidade da máquina de venda para acrescentar a saída de devolução de troco: declare e retenha
change_latch, depois substitua a linha básicaLEDR(6) <= '0';porLEDR(6) <= change_latch;. Ela deve acender somente quando a máquina libera o produto pelo caminho de 20 centavos, S10 + moeda de 10, junto com a liberação já existente emLEDR(7).Selecione Sintetizar (
Synthesize), corrija qualquer erro de digitação e selecione Enviar para a FPGA (Upload to FPGA).Reinicie. Execute um caminho de exatamente 15 centavos, por exemplo três moedas de 5, espere o pulso extra de liberação e confirme que
LEDR(7)acende eLEDR(6)permanece apagado.Reinicie. Execute um caminho de 20 centavos, duas moedas de 5 seguidas de uma de 10 ou duas moedas de 10: confirme que ambos,
LEDR(7)eLEDR(6), acendem.
Depois da alteração 3-C1, execute cada caminho e leia os dois LEDs de saída. Nos caminhos de exatamente 15 centavos, espere o pulso extra de liberação antes da leitura. Registre se LEDR(7), liberação, e LEDR(6), troco, estão acesos ao final de cada caminho.
| Caminho de moedas | Crédito alcançado (15/20 centavos) | LEDR(7) liberou? (sim/não) | LEDR(6) devolveu troco? (sim/não) |
|---|---|---|---|
Envie sua evidência. Em um caminho de 20 centavos, por exemplo duas moedas de 5 seguidas de uma de 10, faça uma captura da câmera mostrando ambos LEDR(7), liberação, e LEDR(6), troco, acesos e anexe-a abaixo.
Capture o código do laboratório. Salve o blink.vhd modificado no laboratório e use o controle de evidência de código abaixo para enviar a versão do checkpoint 3-C1 com devolução de troco. Se o professor pedir um diagrama de estados, envie-o separadamente.
Na sua FSM modificada, em qual caso exato de estado e entrada a saída de troco, LEDR(6), é ativada? Por que esse é o *único* caso de pagamento a mais nesta máquina?
Checkpoint 3-C2 (opcional / bônus): seleção de produto
8 min
Este checkpoint bônus faz a máquina vender dois produtos: um refrigerante por 15 centavos, selecionado com SW(2), e um café por 20 centavos, selecionado com SW(3). A máquina deve liberar o produto somente quando o crédito alcançar o preço do item selecionado: com refrigerante, libera a 15 centavos; com café, espera até 20.
A ideia importante é que isso aumenta o espaço de estados. A máquina já não pode ser descrita apenas pelo crédito, pois seu comportamento a, por exemplo, 15 centavos agora depende de *qual produto* foi selecionado: libera se for refrigerante e continua esperando se for café. A máquina precisa lembrar tanto o crédito quanto a seleção. Combine os dois — por exemplo, um estado pode ser o par *(produto selecionado, nível de crédito)* — e determine quais combinações podem realmente ocorrer e o que cada uma faz.
Desenhe primeiro o diagrama de estados ampliado, decida quantos estados são realmente necessários e só então implemente. Não existe uma única codificação “correta”, mas existe um número mínimo de estados distintos exigido pelo comportamento e, a partir dele, um número mínimo de flip-flops.
(Bônus) Envie seu projeto. Anexe o diagrama de estados ampliado da máquina de dois produtos e cole o VHDL modificado ou anexe o código como arquivo .txt.
(Bônus) De quantos estados distintos sua máquina de dois produtos precisa e, portanto, qual é o número mínimo de flip-flops necessário? Lembre-se de que o número mínimo de flip-flops para codificar N estados é ceil(log2(N)). Informe seu N, mostre o cálculo ceil(log2(N)) e justifique brevemente sua contagem de estados.
Checkpoint 3-C3 (opcional / bônus): display decimal de dois dígitos
7 min
A máquina básica mostra o crédito como um único caractere hexadecimal, 0, 5, A ou F. É compacto, mas não é assim que uma máquina real mostra dinheiro. Este checkpoint bônus exibe o crédito como um número decimal de dois dígitos em HEX1:HEX0: 00, 05, 10 e 15. Mostre 20 somente se criar uma extensão separada com um estado de exibição de 20 centavos ou uma retenção própria; a extensão 3-C1 ainda devolve o display de crédito a 00, enquanto LEDR(6) indica o troco. HEX0 mostra as unidades e HEX1, as dezenas.
Isso reutiliza a ideia do decodificador de sete segmentos da Lição 2: uma função auxiliar chamada seg_dec, para poder coexistir com a função básica seg, associa um único dígito decimal de 0..9 ao padrão de segmentos ativo em nível baixo {g,f,e,d,c,b,a}. Separe o crédito em dezenas e unidades, decodifique cada parte e controle HEX1 e HEX0. Lembre-se de declarar HEX1 : out std_logic_vector(6 downto 0) na lista de portas da entidade: o exemplo básico desta lição expõe apenas HEX0, portanto HEX1 precisa ser declarado, exatamente como no decodificador de dois dígitos da Lição 2. Substitua também a linha original HEX0 <= seg(credit);; não deixe as duas atribuições a HEX0 ativas.
Uma função decimal seg_dec, no mesmo formato da função seg da Lição 2, e a separação dos valores básicos de crédito, 0, 5, 10 e 15, são suficientes:
-- Acrescente HEX1 à lista de portas da entidade e complete o auxiliar do display.
HEX0 : out std_logic_vector(6 downto 0);
HEX1 : out std_logic_vector(6 downto 0)
-- ...
function seg_dec(d : unsigned(3 downto 0)) return std_logic_vector is
begin
case d is
when "0000" => return "1000000";
when "0001" => return TODO_PATTERN_FOR_1;
when "0010" => return TODO_PATTERN_FOR_2;
when others => return "1111111";
end case;
end function;
signal cents : unsigned(4 downto 0);
signal tens : unsigned(3 downto 0);
signal ones : unsigned(3 downto 0);
-- ...
cents <= TODO_CREDIT_AS_CENTS;
tens <= TODO_TENS_DIGIT;
ones <= TODO_ONES_DIGIT;
HEX0 <= TODO_ONES_DISPLAY;
HEX1 <= TODO_TENS_DISPLAY;(Bônus) Edite a entidade da máquina de venda: acrescente uma porta
HEX1 : out std_logic_vector(6 downto 0)à lista de portas, adicione o decodificador decimalseg_dec, separe o crédito em dezenas e unidades, substitua a linha originalHEX0 <= seg(credit);pelos novos controladores deHEX0eHEX1e controleHEX1:HEX0.Selecione Sintetizar (
Synthesize), corrija qualquer erro de digitação e selecione Enviar para a FPGA (Upload to FPGA).Reinicie e insira moedas. Confirme que
HEX1:HEX0mostra00,05,10e15à medida que o crédito aumenta. Adapte o padrão para20somente se criar uma extensão separada com um estado de exibição de 20 centavos ou uma retenção própria; a extensão 3-C1 ainda devolve o display a00, enquantoLEDR(6)indica o troco.
(Bônus) Envie sua evidência. Faça uma captura da câmera com HEX1:HEX0 mostrando um crédito decimal de dois dígitos, por exemplo 10 ou 15, e anexe-a abaixo.
(Bônus) Para um crédito de 15 centavos, que dígitos de dezena e unidade o decodificador calcula, os valores que alimentam HEX1 e HEX0, e qual display mostra 5?
Fechamento do projeto final: o que você construiu ao longo do curso
8 min
Você construiu em hardware real o percurso principal pela lógica digital:
- Portas lógicas (Lição 1): AND, OR, NOT, NAND, NOR e XOR — os átomos de todo circuito — e a ideia de que VHDL *descreve hardware*, em vez de ser executado como um programa.
- Projeto combinacional e minimização (Lição 2): tabelas-verdade, forma canônica de soma de produtos, mapas de Karnaugh e extensões opcionais com produto de somas, multiplexador e decodificador — a passagem de uma especificação para um circuito mais simples que a atende.
- Memória (Lição 3): o flip-flop e o registrador de carga paralela — o momento em que um circuito ganha a capacidade de *lembrar*.
- Contadores (Lição 4): um bloco sequencial acionado por um divisor de clock, mais a disciplina de conferir se uma constante cabe no registrador; as extensões opcionais apresentaram BCD e registradores de deslocamento.
- Máquinas de estados finitos (Lição 5): um semáforo de Moore que age sobre um estado lembrado, com uma extensão opcional de detector de sequência Mealy.
- Um projeto final de FSM (esta lição): um controlador de máquina de venda automática que você *executou e explicou* a partir de uma tabela de transições; os checkpoints opcionais permitem acrescentar devolução de troco, seleção de produto ou display decimal e, se você os fizer, raciocinar sobre a quantidade de estados e flip-flops.
Esse é o núcleo de um curso introdutório de lógica digital, e você executou o percurso obrigatório em uma FPGA real.
Próximos caminhos. Algumas possibilidades, todas opcionais, caso queira continuar:
- Temporização — setup e hold. Flip-flops reais exigem que a entrada permaneça estável por uma pequena janela ao redor da borda do clock. Respeitar esses tempos de *setup* e *hold* permite que um projeto funcione na frequência de clock desejada e abre a porta para a análise estática de temporização.
- Aritmética e ALUs. Combine somadores, comparadores e lógica em uma unidade lógica e aritmética, o coração computacional de um processador.
- Pipeline. Divida um caminho combinacional longo em estágios com clock para aumentar a vazão, uma técnica central em hardware rápido.
- Outros tópicos de VHDL e simulação. Tópicos avançados de VHDL e a *simulação*, com testbenches e formas de onda, permitem verificar um projeto antes mesmo de chegar à placa.
Leitura adicional opcional. Os cursos gratuitos da [FPGA Academy](https://fpgacademy.org/courses.html) abordam em profundidade essa mesma família DE1-SoC, e Harris & Harris, *Digital Design and Computer Architecture*, capítulos 1–3, é um excelente texto para o conteúdo de portas lógicas a FSMs que você acabou de estudar. Nenhum deles é obrigatório: estão aqui caso queira se aprofundar.
Em algumas frases, descreva como a ideia de *memória* cresceu ao longo do curso: de um único flip-flop, na Lição 3, a um registrador e um contador, nas Lições 3–4, e então a uma máquina de estados finitos cujo estado tinha significado, nas Lições 5–6. O que a inclusão de memória permitiu que seus circuitos fizessem que portas puramente combinacionais não podiam fazer?
Em três frases, resuma seu projeto final: (1) o que o *estado* da máquina de venda representava e como uma moeda o alterava; (2) a evidência que você registrou para o caminho básico de liberação ou para um checkpoint opcional; e (3) uma situação em que o comportamento ativo em nível baixo ou a retenção de uma saída foi importante para enxergar o resultado na câmera.