<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>OneWire - MCU &amp; FPGA</title>
	<atom:link href="https://mcu.tec.br/categorias/protoclos/onewire/feed/" rel="self" type="application/rss+xml" />
	<link>https://mcu.tec.br</link>
	<description>Microcontroladores &#38; FPGA</description>
	<lastBuildDate>Sun, 30 Nov 2025 20:39:25 +0000</lastBuildDate>
	<language>pt-BR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>

<image>
	<url>https://mcu.tec.br/wp-content/uploads/2025/02/Robo-para-o-site-MCU.tec_.br-512x512-1-150x150.png</url>
	<title>OneWire - MCU &amp; FPGA</title>
	<link>https://mcu.tec.br</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Thermochron e Hygrochron iButtons: Guia Completo de Uso, Modelos e Exemplo de Data Logger com OneWire</title>
		<link>https://mcu.tec.br/sensores/thermochron-e-hygrochron-ibuttons-guia-completo-de-uso-modelos-e-exemplo-de-data-logger-com-onewire/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=thermochron-e-hygrochron-ibuttons-guia-completo-de-uso-modelos-e-exemplo-de-data-logger-com-onewire</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Sun, 30 Nov 2025 20:39:20 +0000</pubDate>
				<category><![CDATA[OneWire]]></category>
		<category><![CDATA[Sensores]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=925</guid>

					<description><![CDATA[<p>Os iButtons das famílias Thermochron e Hygrochron são data loggers compactos e robustos que registram temperatura — e umidade, no caso dos Hygrochron — utilizando o protocolo OneWire. Este artigo apresenta, de forma didática e acessível para iniciantes, os principais modelos disponíveis no mercado, suas faixas de operação, capacidade de memória e precisão. Explicamos como funcionam as missões de coleta, o armazenamento interno com timestamp e mostramos um exemplo prático de implementação em microcontroladores como ESP32 e STM32. Um guia ideal para quem deseja criar sistemas autônomos de monitoramento ambiental.</p>
<p>The post <a href="https://mcu.tec.br/sensores/thermochron-e-hygrochron-ibuttons-guia-completo-de-uso-modelos-e-exemplo-de-data-logger-com-onewire/">Thermochron e Hygrochron iButtons: Guia Completo de Uso, Modelos e Exemplo de Data Logger com OneWire</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<h1 class="wp-block-heading"><strong>Introdução aos Thermochron e Hygrochron iButtons</strong></h1>



<p class="wp-block-paragraph">Os iButtons da família <strong>Thermochron</strong> e <strong>Hygrochron</strong> representam uma das formas mais simples e confiáveis de implementar <em>data loggers</em> (registradores de dados) em aplicações industriais, laboratoriais e logísticas. Fabricados originalmente pela Dallas Semiconductor (hoje Maxim Integrated/Analog Devices), esses dispositivos encapsulam sensores de <strong>temperatura</strong> — e no caso da linha Hygrochron, também <strong>umidade relativa</strong> — dentro de um invólucro metálico de aço inoxidável no formato de uma pequena moeda. Esse encapsulamento robusto protege o circuito interno contra choques mecânicos, poeira, umidade e variações ambientais, tornando-os especialmente adequados para monitoramento de longo prazo.</p>



<p class="wp-block-paragraph">O grande diferencial dos iButtons é a filosofia de uso baseada em <strong>missões</strong>: o usuário configura o dispositivo com um intervalo de amostragem (por exemplo, a cada 5 minutos), define alarmes ou limites de operação e, a partir daí, o iButton registra automaticamente os dados no seu próprio armazenamento interno, com carimbo de tempo (timestamp). Quando a missão termina, os dados são lidos via <strong>OneWire</strong>, um barramento extremamente simples que utiliza apenas um fio de dados e o retorno de terra.</p>


<div class="wp-block-image">
<figure class="alignleft size-full"><img fetchpriority="high" decoding="async" width="397" height="238" src="https://mcu.tec.br/wp-content/uploads/2025/11/image-29.png" alt="" class="wp-image-926" srcset="https://mcu.tec.br/wp-content/uploads/2025/11/image-29.png 397w, https://mcu.tec.br/wp-content/uploads/2025/11/image-29-300x180.png 300w, https://mcu.tec.br/wp-content/uploads/2025/11/image-29-240x145.png 240w" sizes="(max-width: 397px) 100vw, 397px" /></figure>
</div>


<p class="wp-block-paragraph">Esses dispositivos são amplamente aplicados em monitoramento de transporte de alimentos e vacinas, controle ambiental de câmaras frias, rastreamento de temperatura em cadeias de suprimentos e até monitoramento de equipamentos industriais. A simplicidade do barramento OneWire permite integrá-los de forma prática em sistemas embarcados, como ESP32, STM32, AVR e outros microcontroladores populares.</p>



<p class="wp-block-paragraph">A seguir, iniciaremos a apresentação dos principais modelos de Thermochron e suas características técnicas.</p>



<h1 class="wp-block-heading"><strong>Modelos de Thermochron e Hygrochron iButtons</strong></h1>



<p class="wp-block-paragraph">A família Thermochron é composta por vários modelos, cada um projetado para faixas de temperatura, resoluções e capacidades de memória específicas. Essa diversidade permite selecionar o dispositivo ideal para diferentes condições ambientais, desde monitoramento de produtos refrigerados até aplicações de alta temperatura. Já a família Hygrochron incorpora, além do sensor térmico, um sensor de umidade relativa, voltado para monitoramento ambiental completo.</p>



<p class="wp-block-paragraph">A tabela a seguir resume os modelos Thermochron mais comuns e suas principais especificações técnicas. Essas características influenciam diretamente a precisão do monitoramento e a quantidade de dados que podem ser armazenados em uma única missão.</p>



<p class="wp-block-paragraph"><strong>Modelos Thermochron:</strong></p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Modelo</th><th>Faixa de Temperatura</th><th>Precisão</th><th>Resolução</th><th>Memória (Amostras)</th></tr></thead><tbody><tr><td>DS1921G</td><td>-40°C a +85°C</td><td>±1°C de -30°C a +70°C</td><td>0.5°C</td><td>2048</td></tr><tr><td>DS1921H</td><td>+15°C a +46°C</td><td>±1°C</td><td>0.125°C</td><td>2048</td></tr><tr><td>DS1921Z</td><td>-5°C a +26°C</td><td>±1°C</td><td>0.125°C</td><td>2048</td></tr><tr><td>DS1922L</td><td>-40°C a +85°C</td><td>±0.5°C de -10°C a +65°C</td><td>0.5°C ou 0.0625°C</td><td>8192 ou 4096</td></tr><tr><td>DS1922T</td><td>0°C a +125°C</td><td>±0.5°C de +20°C a +75°C</td><td>0.5°C ou 0.0625°C</td><td>8192 ou 4096</td></tr><tr><td>DS1922E</td><td>+15°C a +140°C</td><td>±1.5°C de +110°C a +140°C</td><td>0.5°C ou 0.0625°C</td><td>8192 ou 4096</td></tr><tr><td>DS1925L</td><td>-40°C a +85°C</td><td>±0.5°C</td><td>0.5°C ou 0.0625°C</td><td>122k ou 61k</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Os modelos <strong>DS1921</strong> são mais simples, voltados para aplicações gerais com baixa resolução e menor memória, enquanto a série <strong>DS1922</strong> já oferece maior resolução, precisão aprimorada e memória superior. O <strong>DS1925L</strong> representa uma geração mais recente, com impressionantes 122 mil amostras — ideal para longas missões.</p>



<p class="wp-block-paragraph">A linha Hygrochron, representada principalmente pelo <strong>DS1923</strong>, registra simultaneamente temperatura e umidade relativa. Ele utiliza o mesmo encapsulamento e protocolo OneWire, facilitando a integração em sistemas existentes.</p>



<p class="wp-block-paragraph">Com essa visão geral dos modelos, podemos avançar para o capítulo seguinte, onde explicaremos como esses dispositivos funcionam como data loggers na prática.</p>



<h1 class="wp-block-heading"><strong>Como os Thermochron e Hygrochron Funcionam como Data Loggers</strong></h1>



<p class="wp-block-paragraph">O funcionamento dos Thermochron e Hygrochron como data loggers é baseado em um conceito simples e extremamente eficiente: <strong>a missão</strong>. Uma missão consiste em um conjunto de parâmetros configurados no dispositivo antes do início da coleta: intervalo de amostragem, limites de alarme, modo de operação de memória e eventuais ajustes de resolução. Após configurado, o iButton passa a registrar automaticamente os dados ambientais no seu armazenamento interno, sem depender de qualquer intervenção externa.</p>


<div class="wp-block-image">
<figure class="alignright size-full is-resized"><img decoding="async" width="275" height="183" src="https://mcu.tec.br/wp-content/uploads/2025/11/image-30.png" alt="" class="wp-image-927" style="width:451px;height:auto"/></figure>
</div>


<p class="wp-block-paragraph">O microcontrolador interno do iButton registra cada amostra com um timestamp. Esse relógio interno pode ser sincronizado durante a inicialização da missão, garantindo que o histórico gerado possa ser analisado posteriormente de forma cronológica. A memória interna funciona como um buffer circular ou como uma memória linear, dependendo da configuração escolhida. No primeiro modo, quando a memória enche, os dados mais antigos são sobrescritos; já no modo linear, a gravação cessa ao atingir a capacidade total.</p>



<p class="wp-block-paragraph">No caso dos modelos Hygrochron, os sensores de temperatura e umidade são registrados simultaneamente e armazenados de modo intercalado, mantendo a coerência temporal entre os dados. Essa característica os torna especialmente úteis em monitoramento ambiental em depósitos, galpões e transporte sensível.</p>



<p class="wp-block-paragraph">A comunicação com o data logger é feita via barramento <strong>OneWire</strong>, que utiliza apenas um único fio de dados mais o retorno de terra. Toda a configuração e leitura dos dados é realizada por comandos trocados entre o microcontrolador hospedeiro (como um ESP32 ou STM32) e o iButton. O OneWire também fornece alimentação parasita para alguns modelos, eliminando a necessidade de fonte externa durante a comunicação.</p>



<p class="wp-block-paragraph">Agora que entendemos como o processo de registro funciona, podemos seguir para o próximo capítulo, onde apresentaremos um exemplo de implementação prática com microcontrolador.</p>



<h1 class="wp-block-heading"><strong>Exemplo Prático: Criando um Data Logger com Thermochron/Hygrochron e Microcontroladores</strong></h1>



<p class="wp-block-paragraph">Para demonstrar o uso dos iButtons Thermochron e Hygrochron em um sistema real, vamos considerar uma implementação baseada em microcontroladores populares como <strong>ESP32</strong> ou <strong>STM32</strong>. A lógica é essencialmente a mesma para qualquer plataforma, já que a comunicação ocorre por meio do protocolo <strong>OneWire</strong>, um barramento simples, robusto e amplamente suportado.</p>



<p class="wp-block-paragraph">Nosso objetivo será apresentar um exemplo didático que:</p>



<ol class="wp-block-list">
<li>Detecta um iButton no barramento OneWire.</li>



<li>Inicia uma missão configurando o intervalo de amostragem.</li>



<li>Lê periodicamente o status do dispositivo.</li>



<li>Faz a leitura completa dos dados registrados.</li>
</ol>



<p class="wp-block-paragraph">A seguir, apresento um pseudocódigo em estilo C, com foco na clareza para iniciantes, mas mantendo o rigor técnico necessário para compreensão do protocolo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Pseudocódigo em C para um Data Logger com iButton</strong></h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include "onewire.h"
#include "thermochron.h"
#include &lt;stdio.h>

// Exemplo: pino GPIO onde o OneWire está conectado
#define ONEWIRE_PIN 4

void app_main(void)
{
    onewire_bus_t ow;
    onewire_init(&amp;ow, ONEWIRE_PIN);

    uint8_t rom&#91;8&#93;;

    // Etapa 1: Procurar dispositivo no barramento
    if (!onewire_search(&amp;ow, rom)) {
        printf("Nenhum iButton encontrado.\n");
        return;
    }

    printf("iButton encontrado! ROM = ");
    for (int i = 0; i &lt; 8; i++) printf("%02X ", rom&#91;i&#93;);
    printf("\n");

    // Etapa 2: Iniciar missão
    thermochron_config_t config;
    config.sample_rate = 60;    // amostragem a cada 60 segundos
    config.start_delay = 0;     // iniciar imediatamente
    config.high_alarm = 30;     // alarme de temperatura alta (°C)
    config.low_alarm = 0;       // alarme de temperatura baixa (°C)

    if (!thermochron_start_mission(&amp;ow, rom, &amp;config)) {
        printf("Falha ao iniciar missão.\n");
        return;
    }

    printf("Missão iniciada com sucesso.\n");

    // Etapa 3: Aguardar coleta e verificar status
    while (1) {
        thermochron_status_t status;
        if (thermochron_read_status(&amp;ow, rom, &amp;status)) {
            printf("Amostras registradas: %d\n", status.samples);
            printf("Temperatura atual: %.2f°C\n", status.current_temp);
        }
        sleep(60);
    }

    // Etapa 4: Leitura completa da memória (após finalização)
    thermochron_log_t log;
    if (thermochron_read_log(&amp;ow, rom, &amp;log)) {
        for (int i = 0; i &lt; log.count; i++) {
            printf("T%d = %.2f°C\n", i, log.values&#91;i&#93;);
        }
    }
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">onewire.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">thermochron.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdio</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Exemplo: pino GPIO onde o OneWire está conectado</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">app_main</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">onewire_bus_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ow</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">onewire_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Etapa 1: Procurar dispositivo no barramento</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">onewire_search</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">)) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Nenhum iButton encontrado.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">iButton encontrado! ROM = </span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">%02X </span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Etapa 2: Iniciar missão</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">thermochron_config_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">config</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">config</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">sample_rate</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">60</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">    </span><span style="color: #616E88">// amostragem a cada 60 segundos</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">config</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">start_delay</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">     </span><span style="color: #616E88">// iniciar imediatamente</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">config</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">high_alarm</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">30</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">     </span><span style="color: #616E88">// alarme de temperatura alta (°C)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">config</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">low_alarm</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">       </span><span style="color: #616E88">// alarme de temperatura baixa (°C)</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">thermochron_start_mission</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">config</span><span style="color: #D8DEE9FF">)) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Falha ao iniciar missão.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Missão iniciada com sucesso.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Etapa 3: Aguardar coleta e verificar status</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">while</span><span style="color: #D8DEE9FF"> (</span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">thermochron_status_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">status</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">thermochron_read_status</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">status</span><span style="color: #D8DEE9FF">)) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Amostras registradas: %d</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">status</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">samples</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Temperatura atual: %.2f°C</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">status</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">current_temp</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">sleep</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">60</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Etapa 4: Leitura completa da memória (após finalização)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">thermochron_log_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">log</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">thermochron_read_log</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">log</span><span style="color: #D8DEE9FF">)) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">log</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">count</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">T%d = %.2f°C</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">log</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">values</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Explicação do Código</strong></h2>



<p class="wp-block-paragraph">O código é estruturado para ser facilmente adaptado a frameworks como ESP-IDF ou HAL da STMicroelectronics:</p>



<ul class="wp-block-list">
<li><strong>onewire_init()</strong> configura o GPIO no modo adequado para o barramento.</li>



<li><strong>onewire_search()</strong> encontra o iButton conectado e lê seu código ROM único de 64 bits.</li>



<li><strong>thermochron_start_mission()</strong> envia os comandos necessários para configurar a missão no Thermochron ou Hygrochron.</li>



<li><strong>thermochron_read_status()</strong> permite acompanhar o andamento da gravação, útil para sistemas embarcados que precisam exibir dados em tempo real.</li>



<li><strong>thermochron_read_log()</strong> extrai todos os valores armazenados ao final da missão.</li>
</ul>



<p class="wp-block-paragraph">Esse modelo é suficiente para construir sistemas reais de aquisição ambiental, podendo ser ampliado com RTC externo, armazenamento em SD card ou envio remoto via MQTT/WiFi.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading"><strong>Conclusão e Recomendações de Uso</strong></h1>



<p class="wp-block-paragraph">Os Thermochron e Hygrochron iButtons representam uma solução extremamente prática, robusta e tecnicamente elegante para monitoramento ambiental em formato de <em>data logger</em>. Seu encapsulamento metálico, aliado ao protocolo OneWire, torna-os ideais para aplicações em que simplicidade de instalação, resistência física e confiabilidade são essenciais. A filosofia baseada em “missões” elimina a necessidade de supervisão contínua, permitindo que o dispositivo realize amostragens de maneira completamente autônoma ao longo de semanas ou meses.</p>



<p class="wp-block-paragraph">A diversidade de modelos disponíveis permite escolher a solução exata para cada cenário: desde o DS1921, adequado a aplicações gerais e de baixo custo, até o DS1925L, com grande capacidade de memória para longas campanhas de medição. Para aplicações em que umidade também é um parâmetro crítico, o Hygrochron (como o DS1923) oferece monitoramento completo de ambiente em um único encapsulamento.</p>



<p class="wp-block-paragraph">Do ponto de vista de implementação em sistemas embarcados, o barramento OneWire simplifica a conectividade e facilita a integração com plataformas como ESP32, STM32, AVR ou mesmo SBCs como Raspberry Pi. O exemplo apresentado demonstra que, com poucas funções de controle e leitura, é possível configurar uma missão, acompanhar sua execução e extrair os dados coletados de maneira ordenada e precisa.</p>



<p class="wp-block-paragraph">Assim, seja para monitoramento de transporte de alimentos e vacinas, gestão ambiental de galpões, rastreamento térmico de equipamentos industriais ou projetos educacionais, os iButtons Thermochron e Hygrochron permanecem como ferramentas confiáveis e acessíveis para coleta de dados ambientais em escala compacta.</p><p>The post <a href="https://mcu.tec.br/sensores/thermochron-e-hygrochron-ibuttons-guia-completo-de-uso-modelos-e-exemplo-de-data-logger-com-onewire/">Thermochron e Hygrochron iButtons: Guia Completo de Uso, Modelos e Exemplo de Data Logger com OneWire</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">925</post-id>	</item>
		<item>
		<title>Sistema de Ronda com OneWire e iButton DS1904 usando ESP32: Implementação Completa, Multithread e à Prova de Falhas</title>
		<link>https://mcu.tec.br/algoritimos/sistema-de-ronda-com-onewire-e-ibutton-ds1904-usando-esp32-implementacao-completa-multithread-e-a-prova-de-falhas/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=sistema-de-ronda-com-onewire-e-ibutton-ds1904-usando-esp32-implementacao-completa-multithread-e-a-prova-de-falhas</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Sun, 30 Nov 2025 20:08:26 +0000</pubDate>
				<category><![CDATA[Algoritimos]]></category>
		<category><![CDATA[OneWire]]></category>
		<category><![CDATA[Sensores]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=920</guid>

					<description><![CDATA[<p>Este artigo apresenta uma implementação completa e profissional de um sistema de ronda baseado no barramento OneWire e no iButton DS1904, utilizando o microcontrolador ESP32 com FreeRTOS. Explicamos de forma detalhada como funciona o protocolo OneWire, como construir um driver seguro com mutex e critical sections, como ler o ID único e o relógio interno do DS1904 e como integrar tudo em uma arquitetura multithread que inclui tasks de ronda e de buzina com sincronização via notificações. O sistema detecta atrasos acima de 10 minutos, aciona alarme e registra eventos de forma organizada. A modularização do código facilita expansão para múltiplos pontos, integração com backend e auditoria profissional. Uma solução robusta, didática e ideal para aplicações de segurança patrimonial e automação.</p>
<p>The post <a href="https://mcu.tec.br/algoritimos/sistema-de-ronda-com-onewire-e-ibutton-ds1904-usando-esp32-implementacao-completa-multithread-e-a-prova-de-falhas/">Sistema de Ronda com OneWire e iButton DS1904 usando ESP32: Implementação Completa, Multithread e à Prova de Falhas</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<h3 class="wp-block-heading">O que é o barramento OneWire e por que ele é interessante para sistemas de segurança</h3>



<p class="wp-block-paragraph">O barramento OneWire é um padrão de comunicação serial desenvolvido originalmente pela Dallas Semiconductor (hoje Maxim Integrated / Analog Devices) que se destaca por um detalhe bem atraente para sistemas embarcados: ele usa apenas <strong>uma linha de dados</strong> mais o <strong>GND</strong> comum. Ou seja, em vez de precisar de vários fios como em SPI ou de duas linhas como em I²C, o OneWire permite que o microcontrolador converse com vários dispositivos usando apenas um único pino de E/S (GPIO) e um resistor de pull-up. Em aplicações como controle de acesso, identificação de pessoas e rondas de vigilância, essa simplicidade reduz custo, facilita instalação em campo e torna o sistema mais robusto na prática.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" width="640" height="240" src="https://mcu.tec.br/wp-content/uploads/2025/11/image-28.png" alt="" class="wp-image-922" srcset="https://mcu.tec.br/wp-content/uploads/2025/11/image-28.png 640w, https://mcu.tec.br/wp-content/uploads/2025/11/image-28-300x113.png 300w" sizes="(max-width: 640px) 100vw, 640px" /></figure>
</div>


<p class="wp-block-paragraph">Do ponto de vista elétrico, o OneWire usa um <strong>barramento open-drain</strong> (ou open-collector): nenhum dispositivo “empurra” o sinal para nível alto; todos apenas puxam a linha para o nível baixo quando necessário. Quem mantém a linha em nível lógico alto é um <strong>resistor de pull-up</strong> ligado à alimentação (típico de 4,7 kΩ em 3,3 V ou 5 V, dependendo dos dispositivos). O ESP32, atuando como mestre do barramento, configura um GPIO em modo open-drain e coordena toda a comunicação, gerando os pulsos de tempo corretos para reset, escrita e leitura de bits, enquanto os dispositivos OneWire (os escravos) respondem em instantes bem definidos de tempo. Isso significa que o protocolo é extremamente sensível a temporização, e é por isso que, mais à frente, vamos falar em <strong>código thread-safe</strong> e no cuidado com interrupções e tasks do FreeRTOS.</p>



<p class="wp-block-paragraph">Cada dispositivo OneWire possui um <strong>código ROM de 64 bits único no mundo</strong>, o que o torna perfeito para uso como “chave” de identificação. Os famosos iButtons são exatamente isso: pequenos “botões metálicos” encapsulando um CI OneWire, que pode armazenar dados e/ou fornecer um ID único. No nosso artigo vamos focar no <strong>DS1904</strong>, um iButton que reúne um <strong>RTC (relógio em tempo real)</strong> com interface OneWire. Ele não só permite identificar o vigilante pelo ID único, como também possibilita registrar horário de passagem nos pontos de ronda com alta confiabilidade temporal, algo ideal para sistemas de auditoria e segurança.</p>



<p class="wp-block-paragraph">Na prática, o barramento OneWire funciona com uma relação bem clara de <strong>mestre–escravos</strong>: apenas o ESP32 inicia as comunicações, envia comandos e define as janelas de tempo em que os escravos podem responder. Os escravos nunca falam “sozinhos”; eles apenas respondem quando o mestre permite, o que simplifica o controle da linha e evita colisões. A comunicação é feita em “slots de tempo” bem definidos: o mestre puxa a linha para baixo por alguns microssegundos para escrever um bit 0 ou 1, ou cria uma janela de leitura onde o escravo pode, ou não, puxar a linha para baixo para indicar o valor do bit. Apesar de parecer complicado à primeira vista, esse esquema é bastante estável e, uma vez encapsulado em uma <strong>camada de driver bem escrita</strong>, o programador de aplicação passa a enxergar o barramento apenas como funções de “ler ROM”, “escrever comando”, “ler dados”, de forma bem amigável.</p>



<p class="wp-block-paragraph">Em sistemas de segurança e ronda, a combinação <strong>“barramento simples + dispositivos robustos”</strong> é muito valiosa. Um iButton pode ser instalado em cada ponto de verificação (posto de ronda), o vigilante carrega seu “botão” pessoal (ou a central possui iButtons por ponto, dependendo da lógica do projeto) e o ESP32, ligado a um leitor OneWire em cada ponto, registra a passagem. Como o barramento permite cabos mais longos que protocolos como I²C (desde que respeitados alguns cuidados de impedância, resistência e capacitância de cabo, que discutiremos em capítulo específico), podemos ter um cabeamento relativamente extenso ligando diversos leitores ou uma placa central com vários canais.</p>



<p class="wp-block-paragraph">Ao longo dos próximos capítulos, vamos sair dessa visão conceitual e entrar em detalhes práticos: primeiro sobre sinais e temporização do OneWire, depois sobre como implementar um <strong>driver OneWire thread-safe no ESP32</strong> usando FreeRTOS, em seguida como conversar especificamente com o <strong>iButton DS1904</strong>, e finalmente como integrar tudo em um <strong>sistema de ronda</strong> que dispara uma buzina se o vigilante demorar mais de 10 minutos para alcançar o próximo ponto, usando tasks independentes e <strong>notificações de tarefa (thread notify)</strong> para ativar e desativar o alarme.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Como funciona a comunicação OneWire (reset, presença, leitura e escrita)</h3>



<p class="wp-block-paragraph">Para trabalhar de forma segura com o barramento OneWire, é essencial entender como a troca de dados acontece no nível elétrico e temporal. Mesmo que futuramente você utilize bibliotecas prontas, compreender esses detalhes permite ajustar o driver para cabos longos, vários dispositivos no barramento e cenários onde interrupções podem afetar a temporização — algo especialmente relevante no ESP32, que possui Wi-Fi, Bluetooth, tasks concorrentes e muitas interrupções.</p>



<p class="wp-block-paragraph">A comunicação OneWire segue quatro operações fundamentais:</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">1. <strong>Reset Pulse (pulso de reset)</strong></h4>



<p class="wp-block-paragraph">Toda transação começa com o mestre (ESP32) puxando a linha para baixo por aproximadamente <strong>480 µs</strong>. Este pulso longo serve como anúncio de que o mestre quer iniciar uma nova sessão no barramento.</p>



<p class="wp-block-paragraph">Após soltar a linha, o mestre aguarda entre <strong>15 µs e 60 µs</strong>, período em que qualquer escravo presente deve puxar a linha para baixo por cerca de <strong>60 a 240 µs</strong>, sinalizando o chamado <strong>Presence Pulse</strong>.<br>Esse evento confirma que ao menos um dispositivo OneWire está conectado e pronto para receber comandos.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">2. <strong>Presence Pulse (pulso de presença)</strong></h4>



<p class="wp-block-paragraph">Quando um dispositivo OneWire reconhece o pulso de reset, ele responde com um pulso curto de nível baixo, indicando que está disponível.<br>O mestre então prossegue enviando comandos.</p>



<p class="wp-block-paragraph">Para o sistema de ronda, essa etapa é crítica: se o leitor de iButton não receber o Presence Pulse, significa que o vigilante não encostou o DS1904 corretamente — algo que a aplicação deve detectar.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">3. <strong>Escrita de Bits (Write 0 / Write 1)</strong></h4>



<p class="wp-block-paragraph">A escrita funciona em <strong>slots de tempo</strong> de aproximadamente 60–70 µs:</p>



<ul class="wp-block-list">
<li><strong>Write 1:</strong><br>O mestre puxa a linha para baixo por <strong>6–10 µs</strong> e então libera.<br>O escravo interpreta isso como bit “1”.</li>



<li><strong>Write 0:</strong><br>O mestre mantém a linha baixa por <strong>60 µs</strong> completos.<br>O escravo interpreta isso como bit “0”.</li>
</ul>



<p class="wp-block-paragraph">Note como o tempo determina tudo — qualquer jitter ou atraso pode corromper a comunicação.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">4. <strong>Leitura de Bits (Read Slot)</strong></h4>



<p class="wp-block-paragraph">A leitura funciona assim:</p>



<ol class="wp-block-list">
<li>O mestre abaixa a linha por ~6 µs.</li>



<li>Libera a linha.</li>



<li>Após ~9 µs, ele amostra o valor lógico.</li>



<li>O escravo pode (ou não) puxar a linha para baixo para informar um “0”.</li>



<li>Se não fizer nada, a linha permanece em “1”.</li>
</ol>



<p class="wp-block-paragraph">Essa janela precisa ser muito precisa. É aqui que uma implementação thread-safe no ESP32 faz toda a diferença — qualquer preempção pode quebrar a leitura.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Por que isso importa para o ESP32?</h3>



<p class="wp-block-paragraph">O ESP32 é extremamente multitarefa:</p>



<ul class="wp-block-list">
<li>interrupções de Wi-Fi,</li>



<li>Bluetooth,</li>



<li>tarefas de FreeRTOS concorrentes,</li>



<li>watchdog timers.</li>
</ul>



<p class="wp-block-paragraph">Se o código OneWire não for protegido, a temporização pode falhar e o DS1904 será mal interpretado.</p>



<p class="wp-block-paragraph">Por isso:</p>



<ul class="wp-block-list">
<li>Usaremos <strong>gpio_set_level()</strong> com pino configurado em <strong>open-drain</strong>.</li>



<li>Desativaremos interrupções apenas dentro das janelas críticas.</li>



<li>Utilizaremos <strong>mutex</strong> para garantir thread safety.</li>



<li>Encapsularemos toda a temporização crítica em funções atômicas.</li>
</ul>



<p class="wp-block-paragraph">Nos próximos capítulos você terá um driver completo e seguro.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Por que o OneWire é especialmente útil com o DS1904?</h3>



<p class="wp-block-paragraph">O DS1904 combina duas características úteis:</p>



<ul class="wp-block-list">
<li><strong>ID único (ROM de 64 bits)</strong> — permite identificar quem está executando a ronda.</li>



<li><strong>RTC interno</strong> — registra horário da leitura, permitindo auditoria confiável.</li>
</ul>



<p class="wp-block-paragraph">Quando o vigilante encosta o iButton no leitor, o sistema pode:</p>



<ol class="wp-block-list">
<li>Ler o ID → identifica o funcionário.</li>



<li>Ler o relógio interno → captura timestamp sólido.</li>



<li>Gravar ponto de ronda.</li>



<li>Resetar um timer de 10 minutos até o próximo ponto.</li>
</ol>



<p class="wp-block-paragraph">Se o próximo ponto não for alcançado dentro do tempo, o sistema aciona uma buzina.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Construção de um Driver OneWire Seguro no ESP32: Mutex + Critical Sections (FreeRTOS)</h3>



<p class="wp-block-paragraph">Para trabalhar corretamente com o barramento OneWire no ESP32 é preciso mais que simplesmente manipular GPIOs. O protocolo exige <strong>temporização em microssegundos extremamente estrita</strong>, e isso pode ser facilmente prejudicado pelo ambiente multitarefa do FreeRTOS, interrupções internas do chip (Wi-Fi/Bluetooth), watchdogs e trocas de contexto. Se o tempo de um pulso variar alguns microssegundos, uma leitura pode ser interpretada como “0” em vez de “1”, corrompendo toda a comunicação.</p>



<p class="wp-block-paragraph">Por esse motivo, a abordagem mais robusta combina duas camadas de proteção:</p>



<ol class="wp-block-list">
<li><strong>Mutex (Semáforo de exclusão mútua)</strong><br>Impede que duas tasks tentem usar o barramento ao mesmo tempo.</li>



<li><strong>Critical Sections (taskENTER_CRITICAL)</strong><br>Desabilitam interrupções durante trechos de tempo crítico, garantindo que o código não seja interrompido bem no meio de um slot OneWire (que dura cerca de 60 µs).</li>
</ol>



<p class="wp-block-paragraph">Usar apenas mutex não é suficiente, pois o FreeRTOS pode preemptar a task dentro da janela sensível do protocolo. Já usar apenas critical sections é perigoso, pois tasks podem interferir entre si. A solução mais segura é combinar os dois, garantindo simultaneamente <strong>exclusão mútua entre threads e preservação absoluta de temporização</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Arquitetura Geral do Driver</h2>



<p class="wp-block-paragraph">Nosso driver OneWire para o ESP32 será composto por:</p>



<ul class="wp-block-list">
<li>inicialização do GPIO em modo <strong>open-drain</strong> (fundamental para barramentos OneWire);</li>



<li>um <strong>mutex global</strong> para proteger chamadas de alto nível;</li>



<li>um <strong>spinlock</strong> para controlar critical sections e impedir interrupções nos pulsos;</li>



<li>funções críticas (bit a bit) protegidas por critical sections;</li>



<li>funções de alto nível (reset, write byte, read byte) protegidas por mutex.</li>
</ul>



<p class="wp-block-paragraph">Dessa forma, garantimos:</p>



<ul class="wp-block-list">
<li>estabilidade do protocolo mesmo com Wi-Fi ativo;</li>



<li>robustez quando várias tasks coexistem;</li>



<li>nenhum risco de corrupção por interrupções no meio da leitura;</li>



<li>compatibilidade com qualquer dispositivo OneWire, incluindo nosso foco: o iButton DS1904.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Código completo do driver OneWire (ESP32 + FreeRTOS, thread-safe e timing-safe)</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "driver/gpio.h"
#include "esp32/rom/ets_sys.h"

#define ONEWIRE_PIN 4

// Mutex para exclusão mútua entre tasks
static SemaphoreHandle_t ow_mutex = NULL;

// Spinlock / mux para critical section (desabilita interrupções no core)
static portMUX_TYPE ow_spinlock = portMUX_INITIALIZER_UNLOCKED;

/**
 * @brief Inicializa o barramento OneWire no pino definido.
 *        Configura o GPIO como open-drain e cria o mutex.
 */
void onewire_init(void)
{
    if (ow_mutex == NULL) {
        ow_mutex = xSemaphoreCreateMutex();
    }

    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL &lt;&lt; ONEWIRE_PIN),
        .mode = GPIO_MODE_INPUT_OUTPUT_OD,   // open-drain
        .pull_up_en = GPIO_PULLUP_DISABLE,   // usar pull-up EXTERNO
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&amp;io_conf);

    gpio_set_level(ONEWIRE_PIN, 1); // libera a linha
}

/**
 * @brief Envia pulso de reset e detecta presence pulse em modo protegido.
 *
 * @return true se algum dispositivo respondeu (presence detectado).
 */
bool onewire_reset(void)
{
    bool presence = false;

    // Garante que só uma task use o barramento por vez
    xSemaphoreTake(ow_mutex, portMAX_DELAY);

    // Região crítica: temporização de reset em microssegundos
    taskENTER_CRITICAL(&amp;ow_spinlock);

    // 1) Mestre puxa a linha para LOW por ~480µs
    gpio_set_level(ONEWIRE_PIN, 0);
    ets_delay_us(480);

    // 2) Libera a linha (pull-up externo leva a HIGH)
    gpio_set_level(ONEWIRE_PIN, 1);

    // 3) Aguarda 70µs e lê o presence
    ets_delay_us(70);
    presence = (gpio_get_level(ONEWIRE_PIN) == 0);

    // 4) Espera o restante da janela de reset
    ets_delay_us(410);

    taskEXIT_CRITICAL(&amp;ow_spinlock);

    xSemaphoreGive(ow_mutex);

    return presence;
}

/**
 * @brief Envia um único bit no barramento (slot de escrita).
 *        Protegido por critical section para manter temporização.
 */
static inline void onewire_write_bit(int bit)
{
    taskENTER_CRITICAL(&amp;ow_spinlock);

    // Início do slot: sempre puxa para LOW
    gpio_set_level(ONEWIRE_PIN, 0);

    if (bit) {
        // Write '1' – pulso curto LOW, depois libera
        ets_delay_us(6);
        gpio_set_level(ONEWIRE_PIN, 1);
        ets_delay_us(64);  // completa o slot (~70µs)
    } else {
        // Write '0' – mantém LOW por quase todo o slot
        ets_delay_us(60);
        gpio_set_level(ONEWIRE_PIN, 1);
        ets_delay_us(10);
    }

    taskEXIT_CRITICAL(&amp;ow_spinlock);
}

/**
 * @brief Lê um único bit do barramento (slot de leitura).
 *        Protegido por critical section para garantir a janela de amostragem.
 */
static inline int onewire_read_bit(void)
{
    int bit;

    taskENTER_CRITICAL(&amp;ow_spinlock);

    // Início do slot de leitura: mestre puxa para LOW rapidamente
    gpio_set_level(ONEWIRE_PIN, 0);
    ets_delay_us(6);

    // Libera linha para que o escravo possa responder
    gpio_set_level(ONEWIRE_PIN, 1);

    // Aguarda ~9µs até o ponto de amostragem
    ets_delay_us(9);
    bit = gpio_get_level(ONEWIRE_PIN);

    // Espera fim do slot (~55µs restantes)
    ets_delay_us(55);

    taskEXIT_CRITICAL(&amp;ow_spinlock);

    return bit;
}

/**
 * @brief Escreve um byte (8 bits LSB-first) no barramento.
 *        NÃO usa mutex nem critical direto – assume que quem chamar
 *        já está com o mutex travado. A temporização está dentro
 *        das funções de bit com critical section.
 */
static inline void onewire_write_byte_internal(uint8_t data)
{
    for (int i = 0; i &lt; 8; i++) {
        onewire_write_bit((data >> i) &amp; 0x01);
    }
}

/**
 * @brief Lê um byte (8 bits LSB-first) do barramento.
 *        Também assume mutex já travado.
 */
static inline uint8_t onewire_read_byte_internal(void)
{
    uint8_t val = 0;

    for (int i = 0; i &lt; 8; i++) {
        val |= (onewire_read_bit() &lt;&lt; i);
    }

    return val;
}

/**
 * @brief Função pública para escrever um byte no barramento
 *        com proteção de mutex (thread-safe).
 */
void onewire_write_byte(uint8_t data)
{
    xSemaphoreTake(ow_mutex, portMAX_DELAY);
    onewire_write_byte_internal(data);
    xSemaphoreGive(ow_mutex);
}

/**
 * @brief Função pública para ler um byte no barramento
 *        com proteção de mutex (thread-safe).
 */
uint8_t onewire_read_byte(void)
{
    xSemaphoreTake(ow_mutex, portMAX_DELAY);
    uint8_t r = onewire_read_byte_internal();
    xSemaphoreGive(ow_mutex);
    return r;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">freertos/FreeRTOS.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">freertos/semphr.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">driver/gpio.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">esp32/rom/ets_sys.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Mutex para exclusão mútua entre tasks</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">SemaphoreHandle_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Spinlock / mux para critical section (desabilita interrupções no core)</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">portMUX_TYPE</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ow_spinlock</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">portMUX_INITIALIZER_UNLOCKED</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Inicializa o barramento OneWire no pino definido.</span></span>
<span class="line"><span style="color: #616E88"> *        Configura o GPIO como open-drain e cria o mutex.</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">xSemaphoreCreateMutex</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">gpio_config_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">io_conf</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">pin_bit_mask</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (1</span><span style="color: #D8DEE9">ULL</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">mode</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">GPIO_MODE_INPUT_OUTPUT_OD</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">   </span><span style="color: #616E88">// open-drain</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">pull_up_en</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">GPIO_PULLUP_DISABLE</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">   </span><span style="color: #616E88">// usar pull-up EXTERNO</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">pull_down_en</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">GPIO_PULLDOWN_DISABLE</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">intr_type</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">GPIO_INTR_DISABLE</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_config</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">io_conf</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// libera a linha</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Envia pulso de reset e detecta presence pulse em modo protegido.</span></span>
<span class="line"><span style="color: #616E88"> *</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">return</span><span style="color: #616E88"> true se algum dispositivo respondeu (presence detectado).</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_reset</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">presence</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Garante que só uma task use o barramento por vez</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xSemaphoreTake</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">portMAX_DELAY</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Região crítica: temporização de reset em microssegundos</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">taskENTER_CRITICAL</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow_spinlock</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 1) Mestre puxa a linha para LOW por ~480µs</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">480</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 2) Libera a linha (pull-up externo leva a HIGH)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 3) Aguarda 70µs e lê o presence</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">70</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">presence</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">gpio_get_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 4) Espera o restante da janela de reset</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">410</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">taskEXIT_CRITICAL</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow_spinlock</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xSemaphoreGive</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">presence</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Envia um único bit no barramento (slot de escrita).</span></span>
<span class="line"><span style="color: #616E88"> *        Protegido por critical section para manter temporização.</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">inline</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_write_bit</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">bit</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">taskENTER_CRITICAL</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow_spinlock</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Início do slot: sempre puxa para LOW</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">bit</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// Write &#39;1&#39; – pulso curto LOW, depois libera</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">6</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">64</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// completa o slot (~70µs)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// Write &#39;0&#39; – mantém LOW por quase todo o slot</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">60</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">10</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">taskEXIT_CRITICAL</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow_spinlock</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Lê um único bit do barramento (slot de leitura).</span></span>
<span class="line"><span style="color: #616E88"> *        Protegido por critical section para garantir a janela de amostragem.</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">inline</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_read_bit</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">bit</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">taskENTER_CRITICAL</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow_spinlock</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Início do slot de leitura: mestre puxa para LOW rapidamente</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">6</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Libera linha para que o escravo possa responder</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Aguarda ~9µs até o ponto de amostragem</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">9</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">bit</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">gpio_get_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Espera fim do slot (~55µs restantes)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ets_delay_us</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">55</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">taskEXIT_CRITICAL</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">ow_spinlock</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">bit</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Escreve um byte (8 bits LSB-first) no barramento.</span></span>
<span class="line"><span style="color: #616E88"> *        NÃO usa mutex nem critical direto – assume que quem chamar</span></span>
<span class="line"><span style="color: #616E88"> *        já está com o mutex travado. A temporização está dentro</span></span>
<span class="line"><span style="color: #616E88"> *        das funções de bit com critical section.</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">inline</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_write_byte_internal</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">onewire_write_bit</span><span style="color: #D8DEE9FF">((</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x01</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Lê um byte (8 bits LSB-first) do barramento.</span></span>
<span class="line"><span style="color: #616E88"> *        Também assume mutex já travado.</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">inline</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_read_byte_internal</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">val</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">val</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">onewire_read_bit</span><span style="color: #D8DEE9FF">() </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">val</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Função pública para escrever um byte no barramento</span></span>
<span class="line"><span style="color: #616E88"> *        com proteção de mutex (thread-safe).</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_write_byte</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xSemaphoreTake</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">portMAX_DELAY</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">onewire_write_byte_internal</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xSemaphoreGive</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">/**</span></span>
<span class="line"><span style="color: #616E88"> * </span><span style="color: #ECEFF4">@</span><span style="color: #8FBCBB">brief</span><span style="color: #616E88"> Função pública para ler um byte no barramento</span></span>
<span class="line"><span style="color: #616E88"> *        com proteção de mutex (thread-safe).</span></span>
<span class="line"><span style="color: #616E88"> */</span></span>
<span class="line"><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_read_byte</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xSemaphoreTake</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">portMAX_DELAY</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">r</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_read_byte_internal</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xSemaphoreGive</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">ow_mutex</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">r</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Interpretação didática dessa arquitetura</h2>



<p class="wp-block-paragraph">O driver acima entrega três garantias fundamentais:</p>



<h3 class="wp-block-heading">1. <strong>Ninguém interrompe uma operação OneWire</strong></h3>



<p class="wp-block-paragraph">Ao usar <code>taskENTER_CRITICAL</code>, garantimos que nenhuma interrupção (Wi-Fi, Bluetooth, timers internos) vai alterar o tempo dos pulsos.<br>O protocolo OneWire depende de:</p>



<ul class="wp-block-list">
<li>6–10 µs para escrever “1”</li>



<li>60 µs para escrever “0”</li>



<li>janelas de amostragem entre 6 e 15 µs</li>
</ul>



<p class="wp-block-paragraph">Qualquer preempção quebraria essas janelas.</p>



<h3 class="wp-block-heading">2. <strong>Nenhuma task concorre pelo barramento</strong></h3>



<p class="wp-block-paragraph">O mutex impede que tasks paralelas afetem o barramento.<br>Exemplo:</p>



<ul class="wp-block-list">
<li>task de ronda lendo DS1904</li>



<li>task de diagnóstico testando presença</li>



<li>task de logs lendo ROM</li>
</ul>



<p class="wp-block-paragraph">Sem mutex → desastre.</p>



<h3 class="wp-block-heading">3. <strong>Bloqueio apenas onde é realmente necessário</strong></h3>



<p class="wp-block-paragraph">A critical section só envolve:</p>



<ul class="wp-block-list">
<li>write_bit</li>



<li>read_bit</li>



<li>reset</li>
</ul>



<p class="wp-block-paragraph">Ou seja, trechos curtíssimos.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Comunicando com o iButton DS1904: Leitura do ID e do Relógio RTC</h3>



<p class="wp-block-paragraph">Com o driver OneWire já estável, thread-safe e protegido contra variações de temporização, podemos finalmente trabalhar diretamente com o <strong>iButton DS1904</strong>, que é o “coração” do nosso sistema de ronda. Ele combina duas funções que interessam muito em segurança:</p>



<ol class="wp-block-list">
<li><strong>Identificação única (ROM de 64 bits)</strong><br>Cada DS1904 possui um código único mundialmente, usado para identificar o vigilante.</li>



<li><strong>RTC interno (Relógio de Tempo Real)</strong><br>Permite registrar o momento exato em que o vigilante passou pelo ponto de ronda, tornando o sistema auditável.</li>
</ol>



<p class="wp-block-paragraph">O protocolo do DS1904 segue estritamente o padrão OneWire: a primeira etapa de qualquer comunicação é enviar um <strong>comando ROM</strong> (Match ROM, Read ROM, Skip ROM), seguido pelos <strong>comandos de função específicos do dispositivo</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4.1 Estrutura da ROM de 64 bits</h2>



<p class="wp-block-paragraph">O código ROM possui:</p>



<ul class="wp-block-list">
<li>8 bits: <strong>Family Code</strong></li>



<li>48 bits: <strong>Número de série</strong></li>



<li>8 bits: <strong>CRC</strong></li>
</ul>



<p class="wp-block-paragraph">Para o DS1904, o <strong>Family Code é 0x24</strong>.</p>



<p class="wp-block-paragraph">Esse ID é perfeito para uso como chave de autenticação do vigilante.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4.2 Comandos ROM importantes</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Comando</th><th>Código</th><th>Função</th></tr></thead><tbody><tr><td><strong>READ ROM</strong></td><td>0x33</td><td>Lê ID quando há apenas um dispositivo no barramento</td></tr><tr><td><strong>MATCH ROM</strong></td><td>0x55</td><td>Seleciona um dispositivo específico</td></tr><tr><td><strong>SKIP ROM</strong></td><td>0xCC</td><td>Usa quando há apenas um dispositivo no barramento</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Para um sistema com leitor único por ponto de ronda, podemos usar o <strong>SKIP ROM</strong>, mas como vamos registrar vigilantes <em>diferentes</em>, utilizaremos preferencialmente o <strong>READ ROM</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4.3 Comandos específicos do DS1904</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Comando</th><th>Código</th><th>Descrição</th></tr></thead><tbody><tr><td><strong>READ CLOCK</strong></td><td>0x66</td><td>Lê o contador RTC (32 bits)</td></tr><tr><td><strong>WRITE CLOCK</strong></td><td>0x99</td><td>Ajusta o valor do clock</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">O RTC do DS1904 conta segundos desde um “epoch” interno do chip.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4.4 Função: Ler o ID (ROM)</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>bool ds1904_read_rom(uint8_t rom&#91;8&#93;)
{
    if (!onewire_reset()) return false;

    // Comando READ ROM
    onewire_write_byte(0x33);

    for (int i = 0; i &lt; 8; i++)
        rom&#91;i&#93; = onewire_read_byte();

    return true;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_read_rom</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">onewire_reset</span><span style="color: #D8DEE9FF">()) </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Comando READ ROM</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">onewire_write_byte</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0x33</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_read_byte</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Explicação</h3>



<ol class="wp-block-list">
<li><strong>Reset</strong> – sincroniza barramento.</li>



<li><strong>READ ROM (0x33)</strong> – pede que o chip envie seu ID.</li>



<li>Le os 8 bytes de ID.</li>



<li>Guarda em <code>rom[8]</code>.</li>
</ol>



<p class="wp-block-paragraph">Esse ID será usado para identificar qual vigilante tocou o iButton no ponto.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4.5 Função: Selecionar um DS1904 pelo ID (MATCH ROM)</h2>



<p class="wp-block-paragraph">Quando temos um único vigilante por ponto, ainda assim é bom garantir que estamos falando com o DS1904 correto, especialmente se o sistema crescer.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>bool ds1904_match_rom(uint8_t rom&#91;8&#93;)
{
    if (!onewire_reset()) return false;

    onewire_write_byte(0x55); // MATCH ROM

    for (int i = 0; i &lt; 8; i++)
        onewire_write_byte(rom&#91;i&#93;);

    return true;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_match_rom</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">onewire_reset</span><span style="color: #D8DEE9FF">()) </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">onewire_write_byte</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0x55</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// MATCH ROM</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">onewire_write_byte</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4.6 Função: Ler o relógio interno (RTC)</h2>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>bool ds1904_read_clock(uint32_t *clock_value)
{
    uint8_t rom&#91;8&#93;;

    // Identifica qual DS1904 está conectado
    if (!ds1904_read_rom(rom))
        return false;

    // Seleciona o dispositivo pelo ID
    if (!ds1904_match_rom(rom))
        return false;

    // Envia comando READ CLOCK
    onewire_write_byte(0x66);

    uint32_t val = 0;
    for (int i = 0; i &lt; 4; i++) {
        val |= ((uint32_t)onewire_read_byte()) &lt;&lt; (8 * i);
    }

    *clock_value = val;
    return true;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_read_clock</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">clock_value</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Identifica qual DS1904 está conectado</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">ds1904_read_rom</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Seleciona o dispositivo pelo ID</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">ds1904_match_rom</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Envia comando READ CLOCK</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">onewire_write_byte</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0x66</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">val</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">4</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">val</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">|=</span><span style="color: #D8DEE9FF"> ((</span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #88C0D0">onewire_read_byte</span><span style="color: #D8DEE9FF">()) </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> (</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">clock_value</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">val</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Explicação detalhada</h3>



<ol class="wp-block-list">
<li>Primeiro lemos a ROM → identificamos o chip.</li>



<li>Depois usamos MATCH ROM → selecionamos explicitamente esse DS1904.</li>



<li>Enviamos <strong>READ CLOCK (0x66)</strong>.</li>



<li>O chip devolve 4 bytes LSB-first.</li>



<li>Montamos o valor de 32 bits.</li>
</ol>



<p class="wp-block-paragraph">Esse valor é o timestamp interno do DS1904 (não é o mesmo epoch do Unix; a conversão vem depois).</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4.7 Validação do vigilante</h2>



<p class="wp-block-paragraph">O sistema pode ter uma tabela (em flash, EEPROM ou servidor) com os IDs autorizados.<br>Por exemplo:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>uint8_t vigilantes_autorizados[]&#91;8&#93; = {
    { 0x24, 0xA2, 0x17, 0x03, 0x4B, 0x00, 0x00, 0x9F },
    { 0x24, 0x98, 0xFF, 0x22, 0x17, 0x00, 0x00, 0xE4 }
};
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">vigilantes_autorizados</span><span style="color: #D8DEE9FF">[]&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x24</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0xA2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x17</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x03</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x4B</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x00</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x00</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x9F</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">},</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x24</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x98</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0xFF</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x22</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x17</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x00</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x00</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0xE4</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Após ler o ID da ROM, o sistema verifica:</p>



<ul class="wp-block-list">
<li>se o vigilante é autorizado,</li>



<li>se está no ponto correto,</li>



<li>registra horário,</li>



<li>notifica o sistema para reiniciar o cronômetro de 10 minutos.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Agora já podemos:</h3>



<ul class="wp-block-list">
<li><strong>Identificar o vigilante</strong> pelo ID único do DS1904.</li>



<li><strong>Registrar o horário exato</strong> usando o RTC interno.</li>



<li>Integrar isso com o sistema de ronda.</li>
</ul>



<h3 class="wp-block-heading">Sistema de Ronda Multithread: Tasks, Notificações e Buzina de Alarme (10 minutos)</h3>



<p class="wp-block-paragraph">Agora vamos juntar tudo em uma aplicação prática com o ESP32 rodando FreeRTOS: um <strong>sistema de ronda</strong> em que o vigilante precisa se identificar com seu iButton DS1904 em cada ponto de verificação. Se ele demorar <strong>mais de 10 minutos</strong> entre um ponto e outro, o sistema aciona uma <strong>buzina de alarme</strong>.</p>



<p class="wp-block-paragraph">A ideia central é usar:</p>



<ul class="wp-block-list">
<li><strong>Uma task para cuidar da ronda</strong> (leitura do DS1904, validação e registro);</li>



<li><strong>Uma task para controlar a buzina</strong>, baseada em <strong>notificações de tarefa</strong> (<code>task notifications</code>);</li>



<li>O <strong>driver OneWire thread-safe</strong> que você já viu (mutex + critical sections).</li>
</ul>



<p class="wp-block-paragraph">Assim, cada “ação” importante fica em uma thread separada e bem definida:</p>



<ul class="wp-block-list">
<li>Task 1 → “Ronda”: lê o iButton (OneWire + DS1904) e, a cada passagem válida, <strong>notifica</strong> a task da buzina para reiniciar o “relógio” de 10 minutos.</li>



<li>Task 2 → “Buzina”: fica bloqueada esperando notificações; se não receber nenhuma por 10 minutos, considera atraso na ronda e <strong>liga a buzina</strong>, mantendo-a ligada até a próxima notificação.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5.1 Conceito de Task Notification no FreeRTOS</h2>



<p class="wp-block-paragraph">Em vez de usar filas ou timers de software, vamos usar as <strong>notificações de tarefa</strong>:</p>



<ul class="wp-block-list">
<li><code>ulTaskNotifyTake()</code> pode bloquear uma task <strong>até</strong>:
<ul class="wp-block-list">
<li>Receber uma notificação (de outra task), ou</li>



<li>Expirar um tempo máximo de espera (timeout).</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Esse padrão encaixa perfeitamente no nosso requisito:</p>



<ul class="wp-block-list">
<li>“Se em 10 minutos <strong>não</strong> chegar uma nova notificação (ou seja, o vigilante não passou no próximo ponto), toca a buzina.”</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5.2 Pinos de hardware</h2>



<p class="wp-block-paragraph">Vamos supor:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>#define ONEWIRE_PIN  4   // Já usado no driver OneWire
#define BUZZER_PIN   5   // Saída digital para a buzina
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ONEWIRE_PIN</span><span style="color: #D8DEE9FF">  </span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">   </span><span style="color: #616E88">// Já usado no driver OneWire</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUZZER_PIN</span><span style="color: #D8DEE9FF">   </span><span style="color: #B48EAD">5</span><span style="color: #D8DEE9FF">   </span><span style="color: #616E88">// Saída digital para a buzina</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">A buzina pode ser acionada diretamente (se for de baixa corrente) ou via transistor / relé, dependendo do projeto.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5.3 Inicialização da buzina</h2>



<p class="wp-block-paragraph">Uma função simples para configurar o pino de saída:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static void buzzer_init(void)
{
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL &lt;&lt; BUZZER_PIN),
        .mode = GPIO_MODE_OUTPUT,
        .pull_up_en = GPIO_PULLUP_DISABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE
    };
    gpio_config(&amp;io_conf);

    gpio_set_level(BUZZER_PIN, 0); // buzina inicialmente desligada
}

static void buzzer_on(void)
{
    gpio_set_level(BUZZER_PIN, 1);
}

static void buzzer_off(void)
{
    gpio_set_level(BUZZER_PIN, 0);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buzzer_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">gpio_config_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">io_conf</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">pin_bit_mask</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (1</span><span style="color: #D8DEE9">ULL</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUZZER_PIN</span><span style="color: #D8DEE9FF">)</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">mode</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">GPIO_MODE_OUTPUT</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">pull_up_en</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">GPIO_PULLUP_DISABLE</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">pull_down_en</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">GPIO_PULLDOWN_DISABLE</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        .</span><span style="color: #D8DEE9">intr_type</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">GPIO_INTR_DISABLE</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_config</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">io_conf</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">BUZZER_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// buzina inicialmente desligada</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buzzer_on</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">BUZZER_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buzzer_off</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">gpio_set_level</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">BUZZER_PIN</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5.4 Handles das tasks</h2>



<p class="wp-block-paragraph">Vamos declarar os handles globalmente:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>static TaskHandle_t buzzerTaskHandle = NULL;
static TaskHandle_t rondaTaskHandle  = NULL;
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">TaskHandle_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">buzzerTaskHandle</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">TaskHandle_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rondaTaskHandle</span><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<ul class="wp-block-list">
<li><code>buzzerTaskHandle</code>: necessário para que a task de ronda possa chamar <code>xTaskNotifyGive()</code> e sinalizar eventos de “passagem de ponto”.</li>



<li><code>rondaTaskHandle</code>: aqui não é estritamente necessário que outra task o notifique, mas deixamos declarado para extensões futuras (como supervisão externa, comandos remotos etc.).</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5.5 Task da Buzina (esperando notificação ou timeout de 10 minutos)</h2>



<p class="wp-block-paragraph">Essa task é o “relógio de segurança” do sistema:</p>



<ul class="wp-block-list">
<li>Ela espera receber uma notificação da task de ronda toda vez que o vigilante passa em um ponto;</li>



<li>Se <strong>10 minutos</strong> se passarem sem notificação, ela entende que houve atraso e aciona a buzina.</li>
</ul>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>void buzzer_task(void *pvParameters)
{
    const TickType_t dez_minutos = pdMS_TO_TICKS(10 * 60 * 1000);

    buzzer_off();

    for (;;)
    {
        // Espera por uma notificação por até 10 minutos
        uint32_t notified = ulTaskNotifyTake(pdTRUE, dez_minutos);

        if (notified > 0) {
            // Recebeu notificação ANTES de 10 minutos:
            // significa que o vigilante passou em mais um ponto a tempo.
            // Garante que a buzina esteja desligada e reinicia o ciclo.
            buzzer_off();
            // volta ao início do loop e espera novamente até 10min
        } else {
            // Timeout: NÃO houve notificação em 10 minutos.
            // Considera atraso de ronda -> aciona buzina.
            buzzer_on();

            // Agora espera até a próxima notificação para desligar a buzina.
            ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
            buzzer_off();
            // Após desligar, volta ao loop e o ciclo recomeça (mais 10min)
        }
    }
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buzzer_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">pvParameters</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">TickType_t</span><span style="color: #D8DEE9FF"> dez_minutos </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">10</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">60</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1000</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">buzzer_off</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// Espera por uma notificação por até 10 minutos</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">notified</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ulTaskNotifyTake</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">pdTRUE</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">dez_minutos</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">notified</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// Recebeu notificação ANTES de 10 minutos:</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// significa que o vigilante passou em mais um ponto a tempo.</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// Garante que a buzina esteja desligada e reinicia o ciclo.</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">buzzer_off</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// volta ao início do loop e espera novamente até 10min</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// Timeout: NÃO houve notificação em 10 minutos.</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// Considera atraso de ronda -&gt; aciona buzina.</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">buzzer_on</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// Agora espera até a próxima notificação para desligar a buzina.</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">ulTaskNotifyTake</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">pdTRUE</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">portMAX_DELAY</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">buzzer_off</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// Após desligar, volta ao loop e o ciclo recomeça (mais 10min)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Leitura didática:</strong></p>



<ul class="wp-block-list">
<li><code>ulTaskNotifyTake(pdTRUE, dez_minutos)</code> bloqueia a task:
<ul class="wp-block-list">
<li>Se a task receber uma notificação antes de 10 minutos → <code>notified > 0</code>.</li>



<li>Se o tempo esgotar sem notificação → retorna 0 (timeout).</li>
</ul>
</li>



<li>Cada chamada a <code>xTaskNotifyGive(buzzerTaskHandle)</code> feita pela task de ronda indica:
<ul class="wp-block-list">
<li>“O vigilante passou em um ponto. Resetar o contador de 10 minutos e manter/desligar buzina.”</li>
</ul>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5.6 Task da Ronda (leitura do DS1904 e reinício do timer de 10 minutos)</h2>



<p class="wp-block-paragraph">A task de ronda faz:</p>



<ol class="wp-block-list">
<li>Fica monitorando o barramento OneWire esperando um DS1904 ser conectado ao leitor;</li>



<li>Quando detecta e lê um iButton:
<ul class="wp-block-list">
<li>Lê a ROM (ID do vigilante);</li>



<li>Lê o clock interno (timestamp);</li>



<li>Faz a validação/autenticação (pode ser uma checagem simples em memória ou em servidor);</li>



<li><strong>Notifica a task da buzina</strong> para resetar o contador de 10 minutos;</li>



<li>Registra log (por enquanto via <code>printf</code>, mas você pode depois mandar para flash, SD, servidor etc.).</li>
</ul>
</li>
</ol>



<p class="wp-block-paragraph">Um exemplo simples:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>extern bool ds1904_read_rom(uint8_t rom&#91;8&#93;);
extern bool ds1904_read_clock(uint32_t *clock_value);
// As funções acima foram apresentadas no capítulo anterior.

void ronda_task(void *pvParameters)
{
    uint8_t  rom&#91;8&#93;;
    uint32_t clock_val;

    for (;;)
    {
        // Tenta detectar um DS1904 no barramento
        if (onewire_reset())
        {
            // Lê ID do vigilante
            if (ds1904_read_rom(rom))
            {
                // Lê o relógio interno
                if (ds1904_read_clock(&amp;clock_val))
                {
                    // Aqui você poderia validar o ID contra uma lista de vigilantes autorizados
                    // e registrar o horário de passagem deste ponto.
                    printf("Ronda: ID DS1904 = ");
                    for (int i = 0; i &lt; 8; i++) {
                        printf("%02X ", rom&#91;i&#93;);
                    }
                    printf(" | Clock = %u segundos\n", (unsigned)clock_val);

                    // Notifica a task da buzina: vigilante passou neste ponto
                    if (buzzerTaskHandle != NULL) {
                        xTaskNotifyGive(buzzerTaskHandle);
                    }

                    // Aguarda o vigilante remover o iButton antes de aceitar nova leitura
                    vTaskDelay(pdMS_TO_TICKS(2000));
                }
            }
        }
        else
        {
            // Nenhum DS1904 detectado no momento, espera um pouco e tenta de novo
            vTaskDelay(pdMS_TO_TICKS(500));
        }
    }
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">extern</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_read_rom</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">extern</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_read_clock</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">clock_value</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #616E88">// As funções acima foram apresentadas no capítulo anterior.</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ronda_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">pvParameters</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">clock_val</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">;;</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// Tenta detectar um DS1904 no barramento</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">onewire_reset</span><span style="color: #D8DEE9FF">())</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// Lê ID do vigilante</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">ds1904_read_rom</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">                </span><span style="color: #616E88">// Lê o relógio interno</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">ds1904_read_clock</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">clock_val</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">                    </span><span style="color: #616E88">// Aqui você poderia validar o ID contra uma lista de vigilantes autorizados</span></span>
<span class="line"><span style="color: #ECEFF4">                    </span><span style="color: #616E88">// e registrar o horário de passagem deste ponto.</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Ronda: ID DS1904 = </span><span style="color: #ECEFF4">&quot;</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                        </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">%02X </span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C"> | Clock = %u segundos</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">unsigned</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">clock_val</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">                    </span><span style="color: #616E88">// Notifica a task da buzina: vigilante passou neste ponto</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">buzzerTaskHandle</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">NULL</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">                        </span><span style="color: #88C0D0">xTaskNotifyGive</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">buzzerTaskHandle</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">                    </span><span style="color: #616E88">// Aguarda o vigilante remover o iButton antes de aceitar nova leitura</span></span>
<span class="line"><span style="color: #D8DEE9FF">                    </span><span style="color: #88C0D0">vTaskDelay</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">2000</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">                </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">else</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">            </span><span style="color: #616E88">// Nenhum DS1904 detectado no momento, espera um pouco e tenta de novo</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">vTaskDelay</span><span style="color: #D8DEE9FF">(</span><span style="color: #88C0D0">pdMS_TO_TICKS</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">500</span><span style="color: #D8DEE9FF">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph"><strong>Explicação didática:</strong></p>



<ul class="wp-block-list">
<li><code>onewire_reset()</code> → verifica se há um dispositivo OneWire presente.</li>



<li><code>ds1904_read_rom()</code> → obtém o ID do iButton (quem é o vigilante).</li>



<li><code>ds1904_read_clock()</code> → obtém o timestamp do RTC interno (quando ele passou).</li>



<li><code>xTaskNotifyGive(buzzerTaskHandle)</code> → informa à task da buzina: “recomece a contar 10 minutos a partir de agora; se ninguém passar até lá, dispare o alarme”.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5.7 Função <code>app_main</code>: amarrando tudo</h2>



<p class="wp-block-paragraph">Por fim, precisamos inicializar o driver OneWire, o pino da buzina e criar as tasks:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>void app_main(void)
{
    // Inicializa barramento OneWire (driver thread-safe)
    onewire_init();

    // Inicializa o pino da buzina
    buzzer_init();

    // Cria a task da buzina
    xTaskCreate(
        buzzer_task,
        "buzzer_task",
        2048,
        NULL,
        5,
        &amp;buzzerTaskHandle
    );

    // Cria a task da ronda
    xTaskCreate(
        ronda_task,
        "ronda_task",
        4096,
        NULL,
        6,              // prioridade ligeiramente maior que a da buzina, se desejar
        &amp;rondaTaskHandle
    );

    // Opcional: você poderia, aqui, enviar uma notificação inicial para a buzina
    // caso queira começar a contagem imediatamente após o sistema iniciar:
    // if (buzzerTaskHandle != NULL) {
    //     xTaskNotifyGive(buzzerTaskHandle);
    // }
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">app_main</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Inicializa barramento OneWire (driver thread-safe)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">onewire_init</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Inicializa o pino da buzina</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">buzzer_init</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Cria a task da buzina</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xTaskCreate</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">buzzer_task</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">buzzer_task</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">2048</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">5</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">buzzerTaskHandle</span></span>
<span class="line"><span style="color: #D8DEE9FF">    )</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Cria a task da ronda</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xTaskCreate</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">ronda_task</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ronda_task</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">4096</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">6</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF">              </span><span style="color: #616E88">// prioridade ligeiramente maior que a da buzina, se desejar</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">rondaTaskHandle</span></span>
<span class="line"><span style="color: #D8DEE9FF">    )</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Opcional: você poderia, aqui, enviar uma notificação inicial para a buzina</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// caso queira começar a contagem imediatamente após o sistema iniciar:</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// if (buzzerTaskHandle != NULL) {</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">//     xTaskNotifyGive(buzzerTaskHandle);</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// }</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5.8 Resumindo a lógica do sistema</h2>



<ul class="wp-block-list">
<li><strong>Quando o sistema inicia</strong>, a task da buzina começa esperando por uma notificação de “passagem de ponto”.</li>



<li><strong>Cada vez que o vigilante encosta o DS1904</strong>:
<ul class="wp-block-list">
<li>A task de ronda lê o ID e o relógio;</li>



<li>Registra o evento (log);</li>



<li>Chama <code>xTaskNotifyGive(buzzerTaskHandle)</code> → reinicia o cronômetro de 10 minutos na task da buzina.</li>
</ul>
</li>



<li><strong>Se em 10 minutos</strong> não houver <strong>nova</strong> notificação:
<ul class="wp-block-list">
<li><code>ulTaskNotifyTake()</code> volta por timeout;</li>



<li>A task da buzina chama <code>buzzer_on()</code>;</li>



<li>O alarme fica ligado até que o vigilante finalmente passe em algum ponto (causando nova notificação).</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Assim, você obtém um sistema de ronda simples, mas bem estruturado:</p>



<ul class="wp-block-list">
<li>Driver OneWire robusto (mutex + critical section);</li>



<li>Integração com iButton DS1904 para identificação e horário;</li>



<li>Lógica de ronda baseada em tasks e notificações, sem necessidade de timers externos.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Modularizando o Sistema e Caminhos de Evolução</h3>



<p class="wp-block-paragraph">Até aqui trabalhamos tudo em um único bloco de código para facilitar a compreensão passo a passo. Em um projeto real, porém, é importante separar responsabilidades em módulos bem definidos, com headers claros e arquivos <code>.c</code> independentes. Isso facilita manutenção, testes, reuso em outros projetos e, principalmente, evita que o código de aplicação (como a lógica da ronda) fique misturado com detalhes de baixo nível do barramento OneWire ou do DS1904.</p>



<p class="wp-block-paragraph">Uma organização simples e já bem profissional poderia ser algo como:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>main/
  ├─ main.c          // app_main, criação das tasks
  ├─ onewire.c       // driver de barramento OneWire
  ├─ onewire.h
  ├─ ds1904.c        // funções específicas do iButton DS1904
  ├─ ds1904.h
  ├─ ronda.c         // lógica da ronda e task correspondente
  ├─ ronda.h
  ├─ buzzer.c        // controle da buzina e task
  └─ buzzer.h
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #D8DEE9">main</span><span style="color: #81A1C1">/</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ├─ </span><span style="color: #D8DEE9">main</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">c</span><span style="color: #D8DEE9FF">          </span><span style="color: #616E88">// app_main, criação das tasks</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ├─ </span><span style="color: #D8DEE9">onewire</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">c</span><span style="color: #D8DEE9FF">       </span><span style="color: #616E88">// driver de barramento OneWire</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ├─ </span><span style="color: #D8DEE9">onewire</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ├─ </span><span style="color: #D8DEE9">ds1904</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">c</span><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">// funções específicas do iButton DS1904</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ├─ </span><span style="color: #D8DEE9">ds1904</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ├─ </span><span style="color: #D8DEE9">ronda</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">c</span><span style="color: #D8DEE9FF">         </span><span style="color: #616E88">// lógica da ronda e task correspondente</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ├─ </span><span style="color: #D8DEE9">ronda</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span></span>
<span class="line"><span style="color: #D8DEE9FF">  ├─ </span><span style="color: #D8DEE9">buzzer</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">c</span><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">// controle da buzina e task</span></span>
<span class="line"><span style="color: #D8DEE9FF">  └─ </span><span style="color: #D8DEE9">buzzer</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">A ideia é que <code>main.c</code> apenas “monte o Lego”: chame inicializações, crie tasks e faça a cola entre os módulos, enquanto cada arquivo <code>.c</code> se concentra em uma responsabilidade única, com a interface pública declarada no respectivo <code>.h</code>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">6.1 – Interface do driver OneWire (<code>onewire.h</code> / <code>onewire.c</code>)</h4>



<p class="wp-block-paragraph">O módulo <code>onewire</code> encapsula toda a complexidade do protocolo. A aplicação não precisa conhecer detalhes de slots de tempo, pulses de reset ou critical sections. Ela apenas chama funções como <code>onewire_reset()</code>, <code>onewire_write_byte()</code> e <code>onewire_read_byte()</code>. Um header enxuto e funcional poderia ser:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// onewire.h
#pragma once
#include &lt;stdbool.h>
#include &lt;stdint.h>

void onewire_init(void);
bool onewire_reset(void);
void onewire_write_byte(uint8_t data);
uint8_t onewire_read_byte(void);
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// onewire.h</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">pragma</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">once</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdbool</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdint</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_reset</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_write_byte</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">onewire_read_byte</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Dentro de <code>onewire.c</code> fica tudo aquilo que já desenvolvemos: configuração do GPIO em open-drain, criação do mutex, uso do <code>portMUX_TYPE</code> e das critical sections, além das funções internas de leitura e escrita de bits. A aplicação vê um conjunto de funções simples, mas que internamente respeitam o timing e são thread-safe.</p>



<p class="wp-block-paragraph">Essa separação também permite, futuramente, portar o driver para outro microcontrolador apenas reescrevendo <code>onewire.c</code> e mantendo o mesmo <code>onewire.h</code>, algo muito útil quando se pensa em bibliotecas reutilizáveis.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">6.2 – Interface específica do DS1904 (<code>ds1904.h</code> / <code>ds1904.c</code>)</h4>



<p class="wp-block-paragraph">O DS1904 é apenas um dos muitos dispositivos OneWire possíveis. Por isso, faz sentido ter um módulo próprio para ele, que dependa de <code>onewire.h</code> mas esconda seus detalhes de comandos de função e formatação de dados. Um header típico poderia ser:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// ds1904.h
#pragma once
#include &lt;stdbool.h>
#include &lt;stdint.h>

#define DS1904_FAMILY_CODE 0x24

bool ds1904_read_rom(uint8_t rom&#91;8&#93;);
bool ds1904_match_rom(const uint8_t rom&#91;8&#93;);
bool ds1904_read_clock(uint32_t *clock_value);
bool ds1904_write_clock(uint32_t clock_value);
bool ds1904_is_family_ds1904(const uint8_t rom&#91;8&#93;);
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// ds1904.h</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">pragma</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">once</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdbool</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9">stdint</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9">h</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">define</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">DS1904_FAMILY_CODE</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x24</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_read_rom</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_match_rom</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_read_clock</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">clock_value</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_write_clock</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint32_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">clock_value</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ds1904_is_family_ds1904</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rom</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">No <code>ds1904.c</code>, você implementa as funções usando a API do <code>onewire</code>. A função <code>ds1904_is_family_ds1904()</code> pode, por exemplo, verificar se o primeiro byte da ROM (family code) é igual a <code>0x24</code>, descartando dispositivos de outro tipo no mesmo barramento. As funções de leitura de clock seguem o padrão que já vimos: <code>onewire_reset()</code>, envio de comando ROM, envio do comando de função (<code>READ CLOCK</code>), leitura de 4 bytes e composição de um <code>uint32_t</code>.</p>



<p class="wp-block-paragraph">Essa camada é onde você aplica toda a “semântica” do DS1904: saber que aqueles 4 bytes representam um contador de segundos desde um epoch específico, saber que o family code deve ser verificado, tratar eventuais erros de CRC se você desejar algo mais sofisticado, entre outros cuidados.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">6.3 – Módulo da buzina (<code>buzzer.h</code> / <code>buzzer.c</code>)</h4>



<p class="wp-block-paragraph">O controle da buzina também merece um módulo próprio, mesmo sendo algo aparentemente simples. No header, você declara a interface tanto para inicialização quanto para a task de monitoramento:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// buzzer.h
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

extern TaskHandle_t buzzerTaskHandle;

void buzzer_init(void);
void buzzer_on(void);
void buzzer_off(void);
void buzzer_task(void *pvParameters);
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// buzzer.h</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">pragma</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">once</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">freertos/FreeRTOS.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">freertos/task.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">extern</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">TaskHandle_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">buzzerTaskHandle</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buzzer_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buzzer_on</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buzzer_off</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">buzzer_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">pvParameters</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">No <code>buzzer.c</code> ficam a configuração do GPIO, as funções <code>buzzer_on()</code> e <code>buzzer_off()</code> e a <code>buzzer_task()</code> com a lógica da notificação e do timeout de 10 minutos. Desse modo, qualquer outro ponto do código que queira acionar ou garantir que a buzina esteja desligada não precisa saber qual pino é usado ou como a task está implementada. Basta chamar as funções declaradas no header.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">6.4 – Módulo de ronda (<code>ronda.h</code> / <code>ronda.c</code>)</h4>



<p class="wp-block-paragraph">A lógica de negócio da ronda também deve ficar isolada em um módulo: é ele que sabe o que significa “passar no ponto de verificação”, como validar o DS1904, como registrar o horário e como notificar a buzina.</p>



<p class="wp-block-paragraph">Um header simples poderia ser:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// ronda.h
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

extern TaskHandle_t rondaTaskHandle;

void ronda_task(void *pvParameters);
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// ronda.h</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">pragma</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">once</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">freertos/FreeRTOS.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">freertos/task.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">extern</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">TaskHandle_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rondaTaskHandle</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ronda_task</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">pvParameters</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Dentro de <code>ronda.c</code> você inclui <code>ds1904.h</code> e implementa a lógica que já desenhamos: loop contínuo, tentativa de detecção de iButton, leitura de ROM e clock, validação de ID (por enquanto em tabela fixa, futuramente em configuração externa), registro em log e chamada a <code>xTaskNotifyGive(buzzerTaskHandle)</code> sempre que uma passagem for considerada válida. Essa divisão deixa claro que a task de ronda é uma “task de aplicação”, enquanto <code>onewire</code> e <code>ds1904</code> são camadas de infraestrutura.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">6.5 – Arquivo principal do projeto (<code>main.c</code>)</h4>



<p class="wp-block-paragraph">Com todos os módulos prontos, <code>main.c</code> se torna bastante simples, o que é uma boa característica em sistemas embarcados bem estruturados. Ele passa a ser essencialmente um “ponto de entrada” que faz a orquestração inicial:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// main.c
#include "onewire.h"
#include "ds1904.h"
#include "buzzer.h"
#include "ronda.h"

void app_main(void)
{
    onewire_init();
    buzzer_init();

    xTaskCreate(
        buzzer_task,
        "buzzer_task",
        2048,
        NULL,
        5,
        &amp;buzzerTaskHandle
    );

    xTaskCreate(
        ronda_task,
        "ronda_task",
        4096,
        NULL,
        6,
        &amp;rondaTaskHandle
    );

    // Se desejar iniciar já contando 10 minutos a partir do boot:
    // if (buzzerTaskHandle != NULL) {
    //     xTaskNotifyGive(buzzerTaskHandle);
    // }
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// main.c</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">onewire.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ds1904.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">buzzer.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">include</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ronda.h</span><span style="color: #ECEFF4">&quot;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">app_main</span><span style="color: #D8DEE9FF">(</span><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">onewire_init</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">buzzer_init</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xTaskCreate</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">buzzer_task</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">buzzer_task</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">2048</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">5</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">buzzerTaskHandle</span></span>
<span class="line"><span style="color: #D8DEE9FF">    )</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">xTaskCreate</span><span style="color: #D8DEE9FF">(</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">ronda_task</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">ronda_task</span><span style="color: #ECEFF4">&quot;</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">4096</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">NULL</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">6</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9">rondaTaskHandle</span></span>
<span class="line"><span style="color: #D8DEE9FF">    )</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Se desejar iniciar já contando 10 minutos a partir do boot:</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// if (buzzerTaskHandle != NULL) {</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">//     xTaskNotifyGive(buzzerTaskHandle);</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// }</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Perceba como <code>app_main()</code> não sabe nada de detalhes de pulso OneWire, nem de como o DS1904 lê o clock, tampouco de como a buzina é acionada em nível elétrico. Ele apenas chama funções em uma sequência lógica. Essa é uma característica importante de uma boa arquitetura: cada camada conhece apenas o necessário da camada imediatamente abaixo.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h4 class="wp-block-heading">6.6 – Extensões naturais do sistema de ronda</h4>



<p class="wp-block-paragraph">Uma vez modularizado, fica muito mais fácil evoluir esse sistema para cenários mais complexos, sem transformar o código em um monolito incontrolável. Algumas extensões bem naturais são:</p>



<p class="wp-block-paragraph">Uma delas é o suporte a múltiplos pontos de ronda. Hoje, a lógica trata implicitamente “um ponto” e estima o atraso com base no tempo entre uma passagem e outra. Você pode avançar para um modelo onde cada ponto de ronda tenha um identificador lógico, talvez armazenado junto com a leitura do DS1904 ou mapeado em tabela. A partir disso, é possível validar não apenas se o vigilante está rodando dentro do tempo, mas também se ele segue uma sequência de pontos obrigatória (por exemplo, ponto 1 → ponto 2 → ponto 3 → retorno à base). Essa lógica continua no módulo <code>ronda.c</code>, que passa a decidir quando uma passagem é válida e quando deve ser registrada como falha.</p>



<p class="wp-block-paragraph">Outra evolução interessante é o registro persistente dos eventos. Em vez de apenas imprimir no console com <code>printf</code>, você pode criar uma função de log que escreva em uma memória externa, cartão SD ou envie via rede para um servidor central, dependendo do contexto da aplicação. A beleza da modularização é que isso pode ser encapsulado em um módulo específico, como <code>log_ronda.c</code>, consumido pela task de ronda sem alterar a API de <code>onewire</code> ou <code>ds1904</code>.</p>



<p class="wp-block-paragraph">Além disso, o controle da buzina pode ser sofisticado para um padrão mais amigável ou mais agressivo, como disparos intermitentes, escalonamento de níveis de alarme ou integração com outros atuadores (luzes de corredor, mensagens em um painel, envio de notificação para uma central). Tudo isso continua concentrado no módulo <code>buzzer.c</code>, mantendo o resto do sistema limpo.</p>



<p class="wp-block-paragraph">Por fim, o tratamento de erros pode ser expandido para detectar e discriminar diferentes tipos de falhas, como ausência de iButton, iButton com family code incorreto, falha na leitura do clock, problemas no barramento (cabo rompido, curto), ou ainda falhas na própria task (por exemplo, watchdog acionando se a task travar). Cada tipo de erro pode ser mapeado para ações diferentes, desde simples logs até acionar alarmes distintos ou bloquear o sistema. Essas estratégias de robustez ganham clareza quando o código está modularizado e cada componente tem uma responsabilidade bem definida.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">Estratégias de Validação da Ronda, Estruturas de Dados e Integração com Backend</h3>



<p class="wp-block-paragraph">Agora que o sistema básico está funcionando (driver OneWire, DS1904, tasks de ronda e buzina), vale a pena dar um passo para trás e enxergar isso como um <strong>sistema de rondas completo</strong>, não apenas “código que lê um iButton e toca uma buzina”. Aqui entra a parte de <strong>modelagem</strong>, <strong>validação</strong> e <strong>integração</strong> – que é o que transforma um protótipo em um produto de segurança utilizável.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7.1 Representando vigilantes, pontos e eventos de ronda</h2>



<p class="wp-block-paragraph">Na prática, o sistema lida com três tipos principais de informação:</p>



<ul class="wp-block-list">
<li><strong>Vigilante</strong> – quem está fazendo a ronda (identificado pelo ROM do DS1904).</li>



<li><strong>Ponto de ronda</strong> – onde o vigilante está (ponto físico, posto, setor).</li>



<li><strong>Evento de ronda</strong> – quando alguém passou em determinado ponto.</li>
</ul>



<p class="wp-block-paragraph">Mesmo em um ESP32, vale a pena ter uma estrutura minimamente organizada, por exemplo:</p>



<pre class="wp-block-code"><code>typedef struct {
    uint8_t rom&#91;8];      // ID completo do DS1904
    uint32_t codigo;     // ID lógico interno (ex: 1001, 1002...)
} Vigilante_t;

typedef struct {
    uint16_t id_ponto;   // Identificador lógico do ponto (1, 2, 3...)
    uint32_t tempo_max;  // tempo máximo em segundos até o próximo ponto
} PontoRonda_t;

typedef struct {
    uint32_t timestamp_rtc;  // valor lido do DS1904
    uint16_t id_ponto;       // ponto onde ocorreu
    uint32_t id_vigilante;   // código lógico do vigilante
    bool atraso;             // true se chegou atrasado
} EventoRonda_t;
</code></pre>



<p class="wp-block-paragraph">A lógica de negócio (em <code>ronda.c</code>) passa a trabalhar com esses tipos, em vez de apenas imprimir o ROM bruto. Isso facilita:</p>



<ul class="wp-block-list">
<li>gravar eventos em memória;</li>



<li>enviar para um servidor;</li>



<li>reprocessar logs depois (auditoria).</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7.2 Validando a sequência e o tempo entre pontos</h2>



<p class="wp-block-paragraph">No exemplo base, consideramos apenas “10 minutos sem notificação → buzina”. Mas um sistema de ronda real costuma ter:</p>



<ul class="wp-block-list">
<li><strong>Uma sequência obrigatória de pontos</strong> (por exemplo: 1 → 2 → 3 → 4 → 1 → …);</li>



<li><strong>Tempos máximos diferentes</strong> entre cada trecho (ex: 5 min entre 1 e 2, 12 min entre 2 e 3, etc.).</li>
</ul>



<p class="wp-block-paragraph">Você pode modelar isso como um pequeno <strong>autômato de estados</strong> ou simplesmente como uma lista ordenada de pontos:</p>



<pre class="wp-block-code"><code>PontoRonda_t rota&#91;] = {
    { .id_ponto = 1, .tempo_max = 300 },   // 5 minutos
    { .id_ponto = 2, .tempo_max = 600 },   // 10 minutos
    { .id_ponto = 3, .tempo_max = 480 },   // 8 minutos
    { .id_ponto = 4, .tempo_max = 900 }    // 15 minutos
};

static uint8_t indice_ponto_atual = 0;
</code></pre>



<p class="wp-block-paragraph">Quando o vigilante passa em um ponto, a lógica pode verificar:</p>



<ol class="wp-block-list">
<li><strong>Se ele está no ponto esperado</strong> (por exemplo, se esperávamos o ponto 2 e ele apareceu no 4, pode ser uma falha de rota).</li>



<li><strong>Quanto tempo passou desde o último evento válido</strong>:
<ul class="wp-block-list">
<li>lê <code>timestamp_rtc</code> do DS1904,</li>



<li>compara com o timestamp anterior,</li>



<li>verifica se excede <code>tempo_max</code> do trecho atual.</li>
</ul>
</li>
</ol>



<p class="wp-block-paragraph">Isso permite:</p>



<ul class="wp-block-list">
<li>tocar a buzina não apenas por “10 minutos absolutos”, mas por atraso em relação à rota;</li>



<li>marcar eventos com <code>atraso = true</code> para relatório posterior;</li>



<li>identificar “pulos de ponto” ou rondas feitas fora de ordem.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7.3 Tratamento de erros e robustez</h2>



<p class="wp-block-paragraph">Aplicações em campo sempre lidam com condições imperfeitas. Alguns exemplos:</p>



<ul class="wp-block-list">
<li>o vigilante encosta o iButton de forma rápida demais e a leitura falha;</li>



<li>cabo do leitor OneWire com mau contato;</li>



<li>DS1904 de outro funcionário (não autorizado) é usado.</li>
</ul>



<p class="wp-block-paragraph">A aplicação deve tratar isso de forma clara:</p>



<ul class="wp-block-list">
<li>Se <code>onewire_reset()</code> falhar repetidamente, você pode:
<ul class="wp-block-list">
<li>acender um LED de “falha de leitura”;</li>



<li>registrar um log de erro (cabo rompido, sem dispositivo, etc.).</li>
</ul>
</li>



<li>Se o <code>family code</code> da ROM não for <code>0x24</code>, você pode recusar a leitura e indicar “dispositivo inválido”.</li>



<li>Se o ID do vigilante não estiver na lista de autorizados:
<ul class="wp-block-list">
<li>ignorar o evento para fins de ronda;</li>



<li>opcionalmente registrar como tentativa de uso não autorizado.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Essa robustez faz diferença enorme na prática: evita falsas acusações ao funcionário (“não passou no ponto”) quando, na verdade, era um problema de cabo ou leitor.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7.4 Integração com backend (HTTP, MQTT, etc.)</h2>



<p class="wp-block-paragraph">Um ESP32 conectado (Wi-Fi/Ethernet) abre espaço para monitorar a ronda em tempo real:</p>



<ul class="wp-block-list">
<li>cada <code>EventoRonda_t</code> pode ser:
<ul class="wp-block-list">
<li>enviado via <strong>HTTP POST</strong> para um servidor;</li>



<li>publicado em um tópico <strong>MQTT</strong> (por exemplo, <code>empresa/ronda/ponto1</code>);</li>



<li>armazenado localmente em flash/SD e sincronizado depois.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">Exemplo conceitual em MQTT (sem entrar no código de rede):</p>



<ul class="wp-block-list">
<li>Tópico: <code>ronda/vigilante/&lt;id_vigilante>/ponto/&lt;id_ponto></code></li>



<li>Payload (JSON): <code>{ "timestamp_rtc": 123456789, "atraso": false, "rota_ok": true }</code></li>
</ul>



<p class="wp-block-paragraph">No servidor, um painel web pode:</p>



<ul class="wp-block-list">
<li>desenhar timeline da ronda;</li>



<li>destacar atrasos;</li>



<li>gerar relatórios diários/semanais.</li>
</ul>



<p class="wp-block-paragraph">A modularização ajuda muito: <code>ronda.c</code> apenas chama uma função “enviar_evento_ronda()” que você implementa em um módulo de comunicação. Assim, mudar de HTTP para MQTT ou vice-versa não quebra o núcleo do sistema.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7.5 Segurança lógica e prevenção de fraude</h2>



<p class="wp-block-paragraph">Um sistema de ronda também precisa se proteger contra alguns comportamentos maliciosos, por exemplo:</p>



<ul class="wp-block-list">
<li>um vigilante tentando “burlar” o sistema encostando o iButton várias vezes no mesmo ponto;</li>



<li>alguém copiando um DS1904 ou tentando usar um token não autorizado.</li>
</ul>



<p class="wp-block-paragraph">Algumas ideias de mitigação:</p>



<ul class="wp-block-list">
<li><strong>Tempo mínimo entre leituras no mesmo ponto</strong>: por exemplo, ignorar leituras no mesmo ponto em janelas menores que X segundos.</li>



<li><strong>Cross-check com dados externos</strong>: cruzar os horários de ronda com controle de acesso (catraca, portão) para ver se o vigilante realmente estava na empresa.</li>



<li><strong>Assinatura dos registros</strong>: se você envia dados a um backend, pode usar um segredo compartilhado ou um token para evitar que um dispositivo não autorizado injete eventos falsos na rede.</li>
</ul>



<p class="wp-block-paragraph">A base tecnológica (OneWire + DS1904 + ESP32) já te dá uma fundação forte; o restante é desenho de políticas.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">7.6 Amarrando tudo com o barramento OneWire</h2>



<p class="wp-block-paragraph">Fechando o ciclo:</p>



<ul class="wp-block-list">
<li>O <strong>OneWire</strong> simplifica o hardware: um único fio de dados + GND, resistor de pull-up e encapsulamento robusto (iButton).</li>



<li>O driver thread-safe com mutex + critical sections torna a solução confiável mesmo com multitarefa pesada.</li>



<li>O <strong>DS1904</strong> entrega identificação única e RTC no mesmo dispositivo, perfeito para sistemas de ronda.</li>



<li>As tasks do FreeRTOS e as notificações permitem uma lógica clara:
<ul class="wp-block-list">
<li>task de ronda detecta passagem → notifica task da buzina → reseta janela de 10 minutos;</li>



<li>task da buzina vigia atrasos e aciona o alarme.</li>
</ul>
</li>
</ul>



<p class="wp-block-paragraph">A partir daqui, o que diferencia um protótipo de um <strong>produto comercial</strong> é principalmente:</p>



<ul class="wp-block-list">
<li>qualidade da modelagem de dados;</li>



<li>robustez contra falhas;</li>



<li>capacidade de integrar com sistemas maiores (servidor, app, dashboard).</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading"><strong>Resumo Final</strong></h3>



<p class="wp-block-paragraph">O barramento OneWire se destaca por sua simplicidade elétrica — apenas um fio de dados mais o GND — e pela robustez dos seus dispositivos, como os iButtons. Essa combinação torna a tecnologia especialmente adequada para sistemas de ronda e controle de presença em ambientes industriais e de segurança. No núcleo do OneWire estão operações temporizadas em microssegundos (reset, presence pulse, read/write), que precisam ser rigorosamente respeitadas para que haja comunicação estável. Por isso, a implementação em microcontroladores multitarefa, como o ESP32, exige mecanismos que garantam tanto exclusão mútua entre tarefas quanto proteção contra interrupções que possam distorcer a temporização. A solução prática é combinar <strong>mutex</strong> (para evitar concorrência entre tasks) com <strong>critical sections</strong> (para desabilitar interrupções nos momentos em que o protocolo requer precisão temporal).</p>



<p class="wp-block-paragraph">O iButton DS1904 é particularmente atraente para aplicações de ronda porque reúne dois elementos essenciais: um <strong>ID único mundialmente</strong> e um <strong>RTC interno</strong> que fornece um timestamp confiável sempre que o vigilante encosta o dispositivo no leitor. Isso permite que o sistema identifique quem passou e exatamente quando passou em cada ponto de verificação, registrando eventos com precisão. Ao modularizar o código em camadas — <code>onewire</code> (nivel baixo), <code>ds1904</code> (interpretação do dispositivo), <code>ronda</code> (lógica de negócio) e <code>buzzer</code> (atuador) — obtém-se um sistema flexível, fácil de manter e altamente reutilizável. A task de ronda lê o DS1904, valida o vigilante, gera um evento e envia uma <strong>notificação</strong> para a task da buzina, que reinicia uma janela de tempo pré-definida (por padrão, 10 minutos). Se nenhuma nova notificação chegar dentro desse período, a buzina é acionada até que uma nova passagem seja registrada. Essa lógica usa diretamente recursos do FreeRTOS como <code>ulTaskNotifyTake()</code> e <code>xTaskNotifyGive()</code>, que fornecem uma forma eficiente de sincronização entre tasks sem necessidade de filas ou timers adicionais.</p>



<p class="wp-block-paragraph">Uma vez estruturado, o sistema pode evoluir naturalmente: é possível incluir vários pontos de ronda, sequências obrigatórias, tempos distintos entre pontos, tratamento de erros avançado (device inválido, cabo danificado, leitura incompleta), registro persistente em memória ou cartão SD, e integração com servidores remotos via HTTP ou MQTT. Cada leitura DS1904 pode se transformar em um evento auditável, permitindo painéis administrativos que acompanham a ronda em tempo real. O sistema também pode incorporar segurança lógica para prevenir abusos, como leituras repetidas no mesmo ponto, uso de tokens não autorizados ou tentativas de fraude.</p>



<p class="wp-block-paragraph">Em síntese, o OneWire associado ao DS1904 e ao ESP32 forma uma solução elegante, robusta e de fácil expansão para implementar rondas profissionais. A comunicação é simples no hardware, confiável no software graças ao tratamento cuidadoso do protocolo, e rica em possibilidades quando inserida em uma arquitetura modular e multitarefa. O resultado é um sistema de ronda eficiente, escalável e pronto para usos reais em segurança patrimonial, industrial e corporativa.</p><p>The post <a href="https://mcu.tec.br/algoritimos/sistema-de-ronda-com-onewire-e-ibutton-ds1904-usando-esp32-implementacao-completa-multithread-e-a-prova-de-falhas/">Sistema de Ronda com OneWire e iButton DS1904 usando ESP32: Implementação Completa, Multithread e à Prova de Falhas</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">920</post-id>	</item>
		<item>
		<title>DS28E17: Como Converter One-Wire em I²C e Estender Sensores a Longas Distâncias</title>
		<link>https://mcu.tec.br/protoclos/ds28e17-como-converter-one-wire-em-i%c2%b2c-e-estender-sensores-a-longas-distancias/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ds28e17-como-converter-one-wire-em-i%25c2%25b2c-e-estender-sensores-a-longas-distancias</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Sun, 30 Nov 2025 16:48:36 +0000</pubDate>
				<category><![CDATA[I2C]]></category>
		<category><![CDATA[OneWire]]></category>
		<category><![CDATA[protocolos]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=910</guid>

					<description><![CDATA[<p>O DS28E17 é um circuito integrado projetado para atuar como uma ponte entre o protocolo One-Wire e o barramento I²C, permitindo que sensores, memórias e periféricos remotos sejam acessados com estabilidade mesmo em longas distâncias. Este artigo apresenta uma explicação didática e rigorosa sobre seu funcionamento, destacando como o dispositivo converte comandos 1-Wire em transações I²C completas, mantendo ACK, STOP, START, clock stretching e integridade por CRC. Também discute como o uso do DS28E17 simplifica o firmware em microcontroladores STM32F411, reduzindo cabos, aumentando a robustez e viabilizando arquiteturas distribuídas para IoT, automação industrial e projetos de eletrônica embarcada. Exemplos em pseudocódigo C demonstram como implementar operações de leitura, escrita e acesso a registradores remotos.</p>
<p>The post <a href="https://mcu.tec.br/protoclos/ds28e17-como-converter-one-wire-em-i%c2%b2c-e-estender-sensores-a-longas-distancias/">DS28E17: Como Converter One-Wire em I²C e Estender Sensores a Longas Distâncias</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading"><strong>Introdução ao DS28E17 e ao Conceito de Ponte One-Wire <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2194.png" alt="↔" class="wp-smiley" style="height: 1em; max-height: 1em;" /> I²C</strong></h2>



<p class="wp-block-paragraph">O DS28E17 é um circuito integrado da Analog Devices projetado para atuar como uma ponte (“bridge”) entre o barramento <strong>1-Wire</strong>, conhecido por sua simplicidade extrema e por exigir apenas um único fio de dados, e o barramento <strong>I²C</strong>, amplamente utilizado em sensores, memórias e periféricos de propósito geral. Seu papel é permitir que um microcontrolador que disponha apenas de interface 1-Wire ou que deseje estender comunicação em longas distâncias possa acessar dispositivos I²C remotos sem a necessidade de um par de fios dedicado (SDA/SCL). Assim, toda a estrutura do I²C remota é encapsulada em comandos enviados por 1-Wire, reduzindo cabos, diminuindo ruído e simplificando o roteamento.</p>


<div class="wp-block-image">
<figure class="alignright size-full"><img loading="lazy" decoding="async" width="316" height="192" src="https://mcu.tec.br/wp-content/uploads/2025/11/image-25.png" alt="" class="wp-image-912" srcset="https://mcu.tec.br/wp-content/uploads/2025/11/image-25.png 316w, https://mcu.tec.br/wp-content/uploads/2025/11/image-25-300x182.png 300w, https://mcu.tec.br/wp-content/uploads/2025/11/image-25-240x145.png 240w" sizes="(max-width: 316px) 100vw, 316px" /></figure>
</div>


<p class="wp-block-paragraph">Para leigos, a ideia fundamental é a seguinte: o DS28E17 fica localizado próximo ao sensor I²C, enquanto o microcontrolador pode estar a metros de distância conectado por um único fio. Esse único fio transporta comandos digitais codificados. O DS28E17 os interpreta e gera localmente o protocolo I²C adequado, com temporizações corretas e níveis lógicos estáveis. O microcontrolador não precisa conhecer detalhes do sensor; basta enviar instruções de “escreva no registrador X” ou “leia o registrador Y”. Essa separação permite topologias mais flexíveis, especialmente em ambientes industriais ou de difícil cabeamento, onde I²C tradicional teria limitações de distância devido à capacitância do cabo.</p>



<p class="wp-block-paragraph">Do ponto de vista técnico, o DS28E17 mantém total conformidade com o protocolo I²C, permitindo velocidades de até <strong>400 kHz (Fast Mode)</strong> e oferecendo mecanismos confiáveis de temporização, controle de ACK/NACK, buffers internos e controle automático de clock stretching. No lado 1-Wire, oferece suporte a comandos de leitura e escrita otimizados, CRC embutido e mecanismos de endereçamento únicos por meio de seu ROM ID de 64 bits, garantindo que múltiplos dispositivos possam coexistir no mesmo fio sem conflitos.</p>



<p class="wp-block-paragraph">O benefício central, tanto para iniciantes quanto para engenheiros experientes, é que ele rompe a típica limitação de alguns metros do I²C convencional, pois o 1-Wire suporta distâncias significativamente maiores graças ao menor número de condutores, menor susceptibilidade à capacitância distribuída e ao uso de pull-up mais forte. Esse comportamento elétrico permite aplicações onde sensores ficam fisicamente distantes do microcontrolador — câmeras térmicas distribuídas, sensores de umidade em estufas agrícolas, sensores ambientais espaciais, entre outros. Tudo isso preservando a robustez e a confiabilidade elétrica, especialmente porque o DS28E17 pode operar com cabos longos sem sofrer com a degradação da integridade do sinal típica do SDA/SCL.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Arquitetura Interna e Funcionamento do DS28E17</strong></h2>



<p class="wp-block-paragraph">O DS28E17 funciona essencialmente como um tradutor digital entre dois mundos: o sinal altamente minimalista do 1-Wire e o protocolo completo do I²C. Para cumprir esse papel, o CI possui uma arquitetura interna composta por blocos funcionais bem definidos: o <strong>Núcleo 1-Wire</strong>, responsável pela recepção e validação dos comandos; o <strong>Motor de Tradução</strong>, que interpreta o pacote recebido e converte em operações I²C; e finalmente o <strong>Controlador I²C</strong>, capaz de executar transmissões completas com velocidade configurável, incluindo start, stop, ACK, NACK e clock stretching.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="668" height="385" src="https://mcu.tec.br/wp-content/uploads/2025/11/image-24.png" alt="" class="wp-image-911" srcset="https://mcu.tec.br/wp-content/uploads/2025/11/image-24.png 668w, https://mcu.tec.br/wp-content/uploads/2025/11/image-24-300x173.png 300w" sizes="(max-width: 668px) 100vw, 668px" /></figure>
</div>


<p class="wp-block-paragraph">O núcleo 1-Wire é a “porta de entrada” do dispositivo. Ele decodifica o protocolo, faz a verificação de integridade via CRC e identifica o DS28E17 por meio de seu ROM ID único de 64 bits. Isso permite que vários dispositivos coexistam no mesmo fio, e o microcontrolador selecione qual DS28E17 deseja comandar. Uma vez que o comando é validado, o pacote é repassado ao motor de tradução, que calcula a operação a ser realizada — por exemplo, escrever bytes em um periférico I²C, ou realizar uma leitura com número específico de bytes. A comunicação é totalmente síncrona: o microcontrolador envia o comando, o DS28E17 executa a operação localmente e devolve a resposta encapsulada em um frame 1-Wire.</p>



<p class="wp-block-paragraph">Já o controlador I²C é um bloco especializado, independente do microcontrolador. Ele gera o sinal SCL com alta precisão e administra as condições de start/stop conforme o padrão I²C. Ele ainda monitora ACK/NACK dos dispositivos conectados, armazenando os dados recebidos em seu buffer interno até que o microcontrolador solicite a leitura via 1-Wire. Um ponto importante para aplicações práticas é que o DS28E17 suporta velocidades de até 400 kHz, mas a eficiência final depende do tempo total de transmissão no 1-Wire — que é mais lento. Portanto, o ganho não está em velocidade, mas em <strong>distância e simplicidade de rede</strong>. Isso é essencial para projetos embutidos que precisam conectar sensores remotos, especialmente em campos como automação, monitoramento ambiental e dispositivos IoT distribuídos.</p>



<p class="wp-block-paragraph">Um detalhe pouco comentado, mas tecnicamente relevante, é a forma como o DS28E17 gerencia a capacitância distribuída no cabo. O 1-Wire tolera cabos longos porque o sinal é baseado em janelas temporais largas, enquanto o I²C é sensível a distorções provocadas pela capacitância. Ao “isolá-las” em blocos separados, o DS28E17 garante que o cabo longo afete apenas o 1-Wire, enquanto o I²C acontece localmente em uma curta distância — normalmente poucos centímetros. Assim, o microcontrolador ganha a habilidade de acessar sensores I²C como se estivessem próximos, mas fisicamente posicionados a metros de distância, com estabilidade e confiabilidade.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Aplicações Práticas e Benefícios no Design de Sistemas Embarcados</strong></h2>



<p class="wp-block-paragraph">O DS28E17 oferece vantagens significativas para projetos que precisam comunicar sensores remotos, reduzir cabeamento ou simplificar a topologia elétrica em ambientes hostis. Em um sistema embarcado tradicional, o barramento I²C apresenta limitações de distância, geralmente ficando preso a poucos centímetros ou, no máximo, dezenas de centímetros em condições ideais. Isso ocorre porque capacitância, indutância distribuída e interferências eletromagnéticas provocam degradação de sinal e distorções de forma de onda. Ao introduzir o DS28E17 como ponte, o microcontrolador passa a usar um único fio — o barramento One-Wire — que tolera melhor comprimentos de cabo maiores e é menos sensível a artefatos físicos, ideal para sensores distribuídos em ambientes industriais, agrícolas e automotivos.</p>



<p class="wp-block-paragraph">Em aplicações reais, isso permite integrar sensores I²C a longas distâncias sem modificar seu hardware original. Imagine um sensor de temperatura digital, um sensor de pressão ou um módulo de memória I²C instalado a metros de distância em um equipamento industrial. Em vez de tentar estender o I²C por cabos longos e sofrer com instabilidade, usa-se um único par de condutores para o 1-Wire e instala-se o DS28E17 próximo ao sensor. O resultado é uma comunicação robusta, com CRC e baixa suscetibilidade a distúrbios, mantendo alta integridade de dados. Esse tipo de solução é especialmente valioso em redes IoT distribuídas, onde há grande quantidade de sensores instalados de forma geograficamente dispersa.</p>



<p class="wp-block-paragraph">Outro benefício importante é a simplicidade de firmware. Em microcontroladores como os STM32F4, o desenvolvedor pode escrever rotinas simples de envio de comandos 1-Wire sem lidar diretamente com estados complexos do I²C. É o DS28E17 quem se encarrega de gerir start, stop, aquisição de ACK e leitura de múltiplos bytes. Isso reduz o tempo de desenvolvimento e as chances de falhas em firmware de baixo nível, tornando o sistema mais confiável. Em aplicações com restrição de energia, a redução de cabos e a padronização dos nós remotos também diminuem perdas e simplificam o layout físico.</p>



<p class="wp-block-paragraph">Além disso, a possibilidade de colocar múltiplos DS28E17 em paralelo no mesmo fio faz deste CI uma alternativa natural para redes com múltiplos sensores, permitindo endereçamento via ROM ID. Essa característica abre portas para arquiteturas hierárquicas de sensores, especialmente em sistemas de monitoramento ambiental, instrumentação científica, sensores estruturais em pontes e monitoramento distribuído em agroindústria. Cada módulo torna-se um nó inteligente, contendo seu próprio tradutor I²C local. Dessa forma, o barramento 1-Wire funciona como uma espinha dorsal simples e eficiente, capaz de interligar dezenas de sensores remotos sem degradação significativa no desempenho.</p>



<p class="wp-block-paragraph">A seguir apresento <strong>o Capítulo 4</strong>. Quando quiser prosseguir, peça <strong>“próximo capítulo”</strong>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Aplicações Práticas e Benefícios no Design de Sistemas Embarcados</strong></h2>



<p class="wp-block-paragraph">O DS28E17 oferece vantagens significativas para projetos que precisam comunicar sensores remotos, reduzir cabeamento ou simplificar a topologia elétrica em ambientes hostis. Em um sistema embarcado tradicional, o barramento I²C apresenta limitações de distância, geralmente ficando preso a poucos centímetros ou, no máximo, dezenas de centímetros em condições ideais. Isso ocorre porque capacitância, indutância distribuída e interferências eletromagnéticas provocam degradação de sinal e distorções de forma de onda. Ao introduzir o DS28E17 como ponte, o microcontrolador passa a usar um único fio — o barramento One-Wire — que tolera melhor comprimentos de cabo maiores e é menos sensível a artefatos físicos, ideal para sensores distribuídos em ambientes industriais, agrícolas e automotivos.</p>



<p class="wp-block-paragraph">Em aplicações reais, isso permite integrar sensores I²C a longas distâncias sem modificar seu hardware original. Imagine um sensor de temperatura digital, um sensor de pressão ou um módulo de memória I²C instalado a metros de distância em um equipamento industrial. Em vez de tentar estender o I²C por cabos longos e sofrer com instabilidade, usa-se um único par de condutores para o 1-Wire e instala-se o DS28E17 próximo ao sensor. O resultado é uma comunicação robusta, com CRC e baixa suscetibilidade a distúrbios, mantendo alta integridade de dados. Esse tipo de solução é especialmente valioso em redes IoT distribuídas, onde há grande quantidade de sensores instalados de forma geograficamente dispersa.</p>



<p class="wp-block-paragraph">Outro benefício importante é a simplicidade de firmware. Em microcontroladores como os STM32F4, o desenvolvedor pode escrever rotinas simples de envio de comandos 1-Wire sem lidar diretamente com estados complexos do I²C. É o DS28E17 quem se encarrega de gerir start, stop, aquisição de ACK e leitura de múltiplos bytes. Isso reduz o tempo de desenvolvimento e as chances de falhas em firmware de baixo nível, tornando o sistema mais confiável. Em aplicações com restrição de energia, a redução de cabos e a padronização dos nós remotos também diminuem perdas e simplificam o layout físico.</p>



<p class="wp-block-paragraph">Além disso, a possibilidade de colocar múltiplos DS28E17 em paralelo no mesmo fio faz deste CI uma alternativa natural para redes com múltiplos sensores, permitindo endereçamento via ROM ID. Essa característica abre portas para arquiteturas hierárquicas de sensores, especialmente em sistemas de monitoramento ambiental, instrumentação científica, sensores estruturais em pontes e monitoramento distribuído em agroindústria. Cada módulo torna-se um nó inteligente, contendo seu próprio tradutor I²C local. Dessa forma, o barramento 1-Wire funciona como uma espinha dorsal simples e eficiente, capaz de interligar dezenas de sensores remotos sem degradação significativa no desempenho.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Exemplos Práticos com Pseudocódigo em C para STM32F411</strong></h2>



<p class="wp-block-paragraph">Para demonstrar o uso do DS28E17 em um projeto real com STM32F411, é importante compreender que o microcontrolador não acessa diretamente o barramento I²C remoto. Em vez disso, ele envia comandos 1-Wire ao DS28E17, que os traduz em operações I²C locais. Neste capítulo, apresentamos pseudocódigos didáticos, com foco na lógica essencial, abstraindo detalhes de temporização específicos do 1-Wire para manter clareza.</p>



<p class="wp-block-paragraph">A primeira etapa é implementar uma função para enviar um comando 1-Wire ao DS28E17. No STM32F411, isso seria conectado a um GPIO configurado como open-drain com pull-up, emulando o 1-Wire por bit-banging ou usando um timer auxiliar. O pseudocódigo base envolve reset, seleção do ROM ID e envio do comando:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Pseudocódigo básico para enviar bytes ao DS28E17 via 1-Wire
void ONEWIRE_WriteBytes(uint8_t *data, uint16_t length)
{
    for (uint16_t i = 0; i &lt; length; i++) {
        ONEWIRE_WriteByte(data&#91;i&#93;); // Função básica de escrita de 1 byte no barramento
    }
}

void DS28E17_Select(uint8_t *rom_id)
{
    ONEWIRE_Reset();
    ONEWIRE_WriteByte(0x55);      // Match ROM command
    ONEWIRE_WriteBytes(rom_id, 8);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// Pseudocódigo básico para enviar bytes ao DS28E17 via 1-Wire</span></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ONEWIRE_WriteBytes</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">length</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">ONEWIRE_WriteByte</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93;)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Função básica de escrita de 1 byte no barramento</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">DS28E17_Select</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">rom_id</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ONEWIRE_Reset</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ONEWIRE_WriteByte</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">0x55</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">      </span><span style="color: #616E88">// Match ROM command</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ONEWIRE_WriteBytes</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom_id</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">A seguir, enviamos uma operação I²C de escrita simples — por exemplo, escrever um registrador em um sensor remoto. O DS28E17 possui o comando específico <strong>I2C Write Command (0x99)</strong> que recebe o endereço do escravo, os bytes de escrita e controla o STOP:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Escreve N bytes em um escravo I2C via DS28E17
bool DS28E17_I2C_Write(uint8_t *rom_id, uint8_t addr, uint8_t *data, uint8_t len)
{
    uint8_t frame&#91;16&#93; = {0};
    uint8_t index = 0;

    DS28E17_Select(rom_id);

    frame&#91;index++&#93; = 0x99;      // Comando de escrita I²C
    frame&#91;index++&#93; = addr &lt;&lt; 1; // Endereço I2C em modo write
    frame&#91;index++&#93; = len;       // Quantidade de bytes a escrever

    for (uint8_t i = 0; i &lt; len; i++)
        frame&#91;index++&#93; = data&#91;i&#93;;

    ONEWIRE_WriteBytes(frame, index);

    // Leitura de status (ACK result etc.)
    uint8_t status = ONEWIRE_ReadByte();
    return (status == 0x00); // Sucesso
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// Escreve N bytes em um escravo I2C via DS28E17</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">DS28E17_I2C_Write</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">rom_id</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">data</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">16</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">}</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">index</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">DS28E17_Select</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom_id</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">index</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x99</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">      </span><span style="color: #616E88">// Comando de escrita I²C</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">index</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Endereço I2C em modo write</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">index</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">       </span><span style="color: #616E88">// Quantidade de bytes a escrever</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">index</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">data</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ONEWIRE_WriteBytes</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">frame</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">index</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Leitura de status (ACK result etc.)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">status</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ONEWIRE_ReadByte</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">status</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">==</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x00</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Sucesso</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Para leitura, o comando correspondente é <strong>I2C Read Command (0x96)</strong>, que solicita uma quantidade de bytes do escravo I²C remoto. Nesse caso, o DS28E17 executa o START, envia o endereço de leitura e coleta os dados antes de devolvê-los pelo barramento 1-Wire:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Lê N bytes de um escravo I2C remoto
bool DS28E17_I2C_Read(uint8_t *rom_id, uint8_t addr, uint8_t *buffer, uint8_t len)
{
    uint8_t frame&#91;4&#93;;
    frame&#91;0&#93; = 0x96;           // Comando de leitura I2C
    frame&#91;1&#93; = (addr &lt;&lt; 1) | 1; // Endereço I2C em modo read
    frame&#91;2&#93; = len;            // Quantidade de bytes a ler

    DS28E17_Select(rom_id);
    ONEWIRE_WriteBytes(frame, 3);

    uint8_t status = ONEWIRE_ReadByte();
    if (status != 0x00)
        return false;

    for (uint8_t i = 0; i &lt; len; i++)
        buffer&#91;i&#93; = ONEWIRE_ReadByte();

    return true;
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// Lê N bytes de um escravo I2C remoto</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">DS28E17_I2C_Read</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">rom_id</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">buffer</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">&#93;</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x96</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">           </span><span style="color: #616E88">// Comando de leitura I2C</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">addr</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">|</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Endereço I2C em modo read</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">frame</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">            </span><span style="color: #616E88">// Quantidade de bytes a ler</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">DS28E17_Select</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom_id</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">ONEWIRE_WriteBytes</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">frame</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">status</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ONEWIRE_ReadByte</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">status</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x00</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">len</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">i</span><span style="color: #81A1C1">++</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">buffer</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #D8DEE9">i</span><span style="color: #D8DEE9FF">&#93; </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">ONEWIRE_ReadByte</span><span style="color: #D8DEE9FF">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">true;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Por fim, apresentamos o pseudocódigo para a operação combinada mais comum: <strong>escrever um registrador e ler o valor em seguida</strong>, típica em sensores IMU, pressão, temperatura e ADCs:</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#2e3440ff"><svg xmlns="http://www.w3.org/2000/svg" width="54" height="14" viewBox="0 0 54 14"><g fill="none" fill-rule="evenodd" transform="translate(1 1)"><circle cx="6" cy="6" r="6" fill="#FF5F56" stroke="#E0443E" stroke-width=".5"></circle><circle cx="26" cy="6" r="6" fill="#FFBD2E" stroke="#DEA123" stroke-width=".5"></circle><circle cx="46" cy="6" r="6" fill="#27C93F" stroke="#1AAB29" stroke-width=".5"></circle></g></svg></span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Leitura combinada (Write + Read), ex: ler registrador de sensor remoto
bool DS28E17_I2C_WriteRead(uint8_t *rom_id,
                           uint8_t addr,
                           uint8_t reg,
                           uint8_t *rx,
                           uint8_t rx_len)
{
    // Escreve o registrador
    if (!DS28E17_I2C_Write(rom_id, addr, &amp;reg, 1))
        return false;

    HAL_Delay(2); // Pequena espera opcional

    // Lê o conteúdo do registrador
    return DS28E17_I2C_Read(rom_id, addr, rx, rx_len);
}
</textarea></pre><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"></path></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// Leitura combinada (Write + Read), ex: ler registrador de sensor remoto</span></span>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">DS28E17_I2C_WriteRead</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">rom_id</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                           </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                           </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">reg</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                           </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">rx</span><span style="color: #ECEFF4">,</span></span>
<span class="line"><span style="color: #D8DEE9FF">                           </span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rx_len</span><span style="color: #D8DEE9FF">)</span></span>
<span class="line"><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Escreve o registrador</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">DS28E17_I2C_Write</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom_id</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> ®</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #D8DEE9FF">))</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">HAL_Delay</span><span style="color: #D8DEE9FF">(</span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Pequena espera opcional</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Lê o conteúdo do registrador</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">DS28E17_I2C_Read</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">rom_id</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rx</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">rx_len</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Em sistemas STM32F411 reais, o desenvolvedor acrescentaria temporizações precisas, checagens de CRC, tratamento de erros e integração com FreeRTOS ou superloop. No entanto, mesmo neste formato simplificado, a lógica é clara: o DS28E17 transforma cada comando 1-Wire em transações I²C completas, permitindo acessar sensores remotos com simplicidade e confiabilidade.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading"><strong>Conclusão e Recomendações para Projetos Reais</strong></h2>



<p class="wp-block-paragraph">O DS28E17 é uma solução extremamente eficiente para quem precisa estender a comunicação com dispositivos I²C a longas distâncias ou simplificar o cabeamento em sistemas embarcados. Sua principal contribuição está em isolar os efeitos elétricos negativos que afetam o barramento I²C — como capacitância excessiva e interferências — e convertê-los em uma interface 1-Wire de maior robustez, permitindo que sensores, memórias e atuadores remotos continuem acessíveis mesmo em topologias distribuídas. A simplicidade de uso, aliada à confiabilidade do CRC e ao ROM ID único, torna o dispositivo atraente tanto para engenheiros experientes quanto para iniciantes que precisam lidar com sensores afastados do microcontrolador.</p>



<p class="wp-block-paragraph">No contexto de microcontroladores como os STM32F411, o DS28E17 reduz significativamente a complexidade do firmware. O desenvolvedor não precisa lidar com as intricadas fases do protocolo I²C tradicional, pois o dispositivo executa localmente essas operações. Isso facilita a escrita de drivers, diminui o risco de falhas e acelera a prototipagem. Em projetos industriais, agrícolas ou IoT distribuída, essa abordagem simplifica tanto a parte elétrica quanto o software, permitindo arquiteturas mais limpas, com menos fios, maior imunidade a ruído e possibilidade de crescimento para dezenas de nós remotos num único barramento 1-Wire.</p>



<p class="wp-block-paragraph">Em aplicações reais, recomenda-se posicionar o DS28E17 o mais próximo possível do dispositivo I²C remoto, garantindo que o trecho crítico de comunicação permaneça curto e estável. Também vale a pena testar diferentes resistores de pull-up no 1-Wire para cabos longos, ajustar temporizações conforme o ambiente e sempre validar a integridade de dados com base no status retornado pelo DS28E17. Quando bem aplicado, esse CI deixa de ser apenas um componente de conversão e se torna um elemento-chave para criar redes de sensores robustas, expansíveis e de implementação econômica.</p>



<p class="wp-block-paragraph">Datasheet: <a href="https://www.analog.com/media/en/technical-documentation/data-sheets/ds28e18.pdf">https://www.analog.com/media/en/technical-documentation/data-sheets/ds28e18.pdf</a></p>



<p class="wp-block-paragraph"></p><p>The post <a href="https://mcu.tec.br/protoclos/ds28e17-como-converter-one-wire-em-i%c2%b2c-e-estender-sensores-a-longas-distancias/">DS28E17: Como Converter One-Wire em I²C e Estender Sensores a Longas Distâncias</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">910</post-id>	</item>
	</channel>
</rss>
