<?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>Sensores - MCU &amp; FPGA</title>
	<atom:link href="https://mcu.tec.br/categorias/sensores/feed/" rel="self" type="application/rss+xml" />
	<link>https://mcu.tec.br</link>
	<description>Microcontroladores &#38; FPGA</description>
	<lastBuildDate>Sun, 22 Feb 2026 14:26:50 +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>Sensores - MCU &amp; FPGA</title>
	<link>https://mcu.tec.br</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>BNO055: Guia Completo de Orientação Absoluta, I2C, Calibração e Driver Robusto em C</title>
		<link>https://mcu.tec.br/sensores/bno055-guia-completo-de-orientacao-absoluta-i2c-calibracao-e-driver-robusto-em-c/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=bno055-guia-completo-de-orientacao-absoluta-i2c-calibracao-e-driver-robusto-em-c</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Sun, 01 Mar 2026 16:07:28 +0000</pubDate>
				<category><![CDATA[Sensores]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=1366</guid>

					<description><![CDATA[<p>Aprenda em detalhes como utilizar o sensor BNO055 para orientação absoluta com fusão sensorial interna. Entenda quaternions, ângulos de Euler, calibração, problemas reais no protocolo I2C, clock stretching, compatibilidade com STM32, ESP32, Raspberry Pi e RP2040. Veja exemplos completos de driver em C, estratégias de robustez e boas práticas de engenharia para aplicações profissionais em robótica, navegação e sistemas embarcados.</p>
<p>The post <a href="https://mcu.tec.br/sensores/bno055-guia-completo-de-orientacao-absoluta-i2c-calibracao-e-driver-robusto-em-c/">BNO055: Guia Completo de Orientação Absoluta, I2C, Calibração e Driver Robusto em C</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<div class="root-eb-toc-fpags wp-block-essential-blocks-table-of-contents"><div class="eb-parent-wrapper eb-parent-eb-toc-fpags "><div class="eb-toc-container eb-toc-fpags  eb-toc-is-not-sticky eb-toc-not-collapsible eb-toc-initially-not-collapsed eb-toc-scrollToTop style-1 list-style-none" data-scroll-top="false" data-scroll-top-icon="fas fa-angle-up" data-collapsible="false" data-sticky-hide-mobile="false" data-sticky="false" data-scroll-target="scroll_to_toc" data-copy-link="false" data-editor-type="" data-hide-desktop="false" data-hide-tab="false" data-hide-mobile="false" data-itemcollapsed="false" data-highlight-scroll="false"><div class="eb-toc-header"><h2 class="eb-toc-title">Table of Contents</h2></div><div class="eb-toc-wrapper " data-headers="[{&quot;level&quot;:2,&quot;content&quot;:&quot;Introdu\u00e7\u00e3o ao BNO055 e Conceito de Orienta\u00e7\u00e3o Absoluta&quot;,&quot;text&quot;:&quot;Introdu\u00e7\u00e3o ao BNO055 e Conceito de Orienta\u00e7\u00e3o Absoluta&quot;,&quot;link&quot;:&quot;eb-table-content-0&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;2. Arquitetura Interna, Modos de Opera\u00e7\u00e3o e Sequ\u00eancia Correta de Inicializa\u00e7\u00e3o&quot;,&quot;text&quot;:&quot;2. Arquitetura Interna, Modos de Opera\u00e7\u00e3o e Sequ\u00eancia Correta de Inicializa\u00e7\u00e3o&quot;,&quot;link&quot;:&quot;eb-table-content-1&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.1 Organiza\u00e7\u00e3o de Registradores&quot;,&quot;text&quot;:&quot;2.1 Organiza\u00e7\u00e3o de Registradores&quot;,&quot;link&quot;:&quot;eb-table-content-2&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.2 Modos de Opera\u00e7\u00e3o&quot;,&quot;text&quot;:&quot;2.2 Modos de Opera\u00e7\u00e3o&quot;,&quot;link&quot;:&quot;eb-table-content-3&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.3 Sequ\u00eancia Correta de Inicializa\u00e7\u00e3o&quot;,&quot;text&quot;:&quot;2.3 Sequ\u00eancia Correta de Inicializa\u00e7\u00e3o&quot;,&quot;link&quot;:&quot;eb-table-content-4&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.4 Exemplo de Inicializa\u00e7\u00e3o em C (Bare-Metal)&quot;,&quot;text&quot;:&quot;2.4 Exemplo de Inicializa\u00e7\u00e3o em C (Bare-Metal)&quot;,&quot;link&quot;:&quot;eb-table-content-5&quot;},{&quot;level&quot;:4,&quot;content&quot;:&quot;Verifica\u00e7\u00e3o do CHIP_ID&quot;,&quot;text&quot;:&quot;Verifica\u00e7\u00e3o do CHIP_ID&quot;,&quot;link&quot;:&quot;eb-table-content-6&quot;},{&quot;level&quot;:4,&quot;content&quot;:&quot;Entrar em modo CONFIG&quot;,&quot;text&quot;:&quot;Entrar em modo CONFIG&quot;,&quot;link&quot;:&quot;entrar-em-modo-config&quot;},{&quot;level&quot;:4,&quot;content&quot;:&quot;Reset&quot;,&quot;text&quot;:&quot;Reset&quot;,&quot;link&quot;:&quot;reset&quot;},{&quot;level&quot;:4,&quot;content&quot;:&quot;Selecionar modo NDOF&quot;,&quot;text&quot;:&quot;Selecionar modo NDOF&quot;,&quot;link&quot;:&quot;selecionar-modo-ndof&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2.5 Convers\u00e3o de Dados&quot;,&quot;text&quot;:&quot;2.5 Convers\u00e3o de Dados&quot;,&quot;link&quot;:&quot;eb-table-content-10&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;3. Fus\u00e3o Sensorial Interna, Quaternions, \u00c2ngulos de Euler e Fundamentos Trigonom\u00e9tricos&quot;,&quot;text&quot;:&quot;3. Fus\u00e3o Sensorial Interna, Quaternions, \u00c2ngulos de Euler e Fundamentos Trigonom\u00e9tricos&quot;,&quot;link&quot;:&quot;eb-table-content-11&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;3.1 Papel de Cada Sensor na Fus\u00e3o&quot;,&quot;text&quot;:&quot;3.1 Papel de Cada Sensor na Fus\u00e3o&quot;,&quot;link&quot;:&quot;eb-table-content-12&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;3.2 \u00c2ngulos de Euler&quot;,&quot;text&quot;:&quot;3.2 \u00c2ngulos de Euler&quot;,&quot;link&quot;:&quot;eb-table-content-13&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Interpreta\u00e7\u00e3o Trigonom\u00e9trica&quot;,&quot;text&quot;:&quot;Interpreta\u00e7\u00e3o Trigonom\u00e9trica&quot;,&quot;link&quot;:&quot;eb-table-content-14&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;3.3 Quaternions&quot;,&quot;text&quot;:&quot;3.3 Quaternions&quot;,&quot;link&quot;:&quot;33-quaternions&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Convers\u00e3o Quaternion \u2192 Euler&quot;,&quot;text&quot;:&quot;Convers\u00e3o Quaternion \u2192 Euler&quot;,&quot;link&quot;:&quot;eb-table-content-16&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;3.4 Vetores Fornecidos pelo BNO055&quot;,&quot;text&quot;:&quot;3.4 Vetores Fornecidos pelo BNO055&quot;,&quot;link&quot;:&quot;34-vetores-fornecidos-pelo-bno055&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;3.5 Processo de Calibra\u00e7\u00e3o&quot;,&quot;text&quot;:&quot;3.5 Processo de Calibra\u00e7\u00e3o&quot;,&quot;link&quot;:&quot;eb-table-content-18&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4. Problemas no Barramento I2C: Por que o BNO055 \u201cquebra\u201d o protocolo e quais microcontroladores sofrem mais&quot;,&quot;text&quot;:&quot;4. Problemas no Barramento I2C: Por que o BNO055 \u201cquebra\u201d o protocolo e quais microcontroladores sofrem mais&quot;,&quot;link&quot;:&quot;4-problemas-no-barramento-i2c-por-que-o-bno055-quebra-o-protocolo-e-quais-microcontroladores-sofrem-mais&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;4.1 Relembrando o Protocolo I2C&quot;,&quot;text&quot;:&quot;4.1 Relembrando o Protocolo I2C&quot;,&quot;link&quot;:&quot;41-relembrando-o-protocolo-i2c&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4.2 O Problema Real do BNO055&quot;,&quot;text&quot;:&quot;4.2 O Problema Real do BNO055&quot;,&quot;link&quot;:&quot;42-o-problema-real-do-bno055&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4.3 Microcontroladores que costumam apresentar problemas&quot;,&quot;text&quot;:&quot;4.3 Microcontroladores que costumam apresentar problemas&quot;,&quot;link&quot;:&quot;43-microcontroladores-que-costumam-apresentar-problemas&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4.4 Microcontroladores que funcionam bem&quot;,&quot;text&quot;:&quot;4.4 Microcontroladores que funcionam bem&quot;,&quot;link&quot;:&quot;44-microcontroladores-que-funcionam-bem&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4.5 Por que o BNO055 faz clock stretching longo?&quot;,&quot;text&quot;:&quot;4.5 Por que o BNO055 faz clock stretching longo?&quot;,&quot;link&quot;:&quot;45-por-que-o-bno055-faz-clock-stretching-longo&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4.6 Exemplo de Erro T\u00edpico&quot;,&quot;text&quot;:&quot;4.6 Exemplo de Erro T\u00edpico&quot;,&quot;link&quot;:&quot;eb-table-content-25&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4.7 Estrat\u00e9gias T\u00e9cnicas para Evitar Problemas&quot;,&quot;text&quot;:&quot;4.7 Estrat\u00e9gias T\u00e9cnicas para Evitar Problemas&quot;,&quot;link&quot;:&quot;eb-table-content-26&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Recupera\u00e7\u00e3o de Barramento (Exemplo Gen\u00e9rico)&quot;,&quot;text&quot;:&quot;Recupera\u00e7\u00e3o de Barramento (Exemplo Gen\u00e9rico)&quot;,&quot;link&quot;:&quot;eb-table-content-27&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4.8 Alternativa: Usar UART&quot;,&quot;text&quot;:&quot;4.8 Alternativa: Usar UART&quot;,&quot;link&quot;:&quot;48-alternativa-usar-uart&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4.9 An\u00e1lise Cr\u00edtica&quot;,&quot;text&quot;:&quot;4.9 An\u00e1lise Cr\u00edtica&quot;,&quot;link&quot;:&quot;eb-table-content-29&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5. Driver Robusto em C para o BNO055 com Tratamento de Timeout e Recupera\u00e7\u00e3o de Barramento&quot;,&quot;text&quot;:&quot;5. Driver Robusto em C para o BNO055 com Tratamento de Timeout e Recupera\u00e7\u00e3o de Barramento&quot;,&quot;link&quot;:&quot;eb-table-content-30&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;5.1 Endere\u00e7o I2C&quot;,&quot;text&quot;:&quot;5.1 Endere\u00e7o I2C&quot;,&quot;link&quot;:&quot;eb-table-content-31&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5.2 Escrita com Retry&quot;,&quot;text&quot;:&quot;5.2 Escrita com Retry&quot;,&quot;link&quot;:&quot;52-escrita-com-retry&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5.3 Leitura com Retry&quot;,&quot;text&quot;:&quot;5.3 Leitura com Retry&quot;,&quot;link&quot;:&quot;53-leitura-com-retry&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5.4 Inicializa\u00e7\u00e3o Segura Completa&quot;,&quot;text&quot;:&quot;5.4 Inicializa\u00e7\u00e3o Segura Completa&quot;,&quot;link&quot;:&quot;eb-table-content-34&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5.5 Leitura de Quaternion&quot;,&quot;text&quot;:&quot;5.5 Leitura de Quaternion&quot;,&quot;link&quot;:&quot;55-leitura-de-quaternion&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5.6 Convers\u00e3o para \u00c2ngulos&quot;,&quot;text&quot;:&quot;5.6 Convers\u00e3o para \u00c2ngulos&quot;,&quot;link&quot;:&quot;eb-table-content-36&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5.7 Estrutura de Aplica\u00e7\u00e3o Principal&quot;,&quot;text&quot;:&quot;5.7 Estrutura de Aplica\u00e7\u00e3o Principal&quot;,&quot;link&quot;:&quot;eb-table-content-37&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5.8 Considera\u00e7\u00f5es Profissionais Importantes&quot;,&quot;text&quot;:&quot;5.8 Considera\u00e7\u00f5es Profissionais Importantes&quot;,&quot;link&quot;:&quot;eb-table-content-38&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;6. Calibra\u00e7\u00e3o, Salvamento de Offsets e Uso de Acelera\u00e7\u00e3o Linear para Estimar Movimento&quot;,&quot;text&quot;:&quot;6. Calibra\u00e7\u00e3o, Salvamento de Offsets e Uso de Acelera\u00e7\u00e3o Linear para Estimar Movimento&quot;,&quot;link&quot;:&quot;eb-table-content-39&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.1 Lendo o status de calibra\u00e7\u00e3o (CALIB_STAT)&quot;,&quot;text&quot;:&quot;6.1 Lendo o status de calibra\u00e7\u00e3o (CALIB_STAT)&quot;,&quot;link&quot;:&quot;eb-table-content-40&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.2 Por que salvar calibra\u00e7\u00e3o vale ouro em produto real&quot;,&quot;text&quot;:&quot;6.2 Por que salvar calibra\u00e7\u00e3o vale ouro em produto real&quot;,&quot;link&quot;:&quot;eb-table-content-41&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.3 Rotina em C para ler e restaurar offsets&quot;,&quot;text&quot;:&quot;6.3 Rotina em C para ler e restaurar offsets&quot;,&quot;link&quot;:&quot;63-rotina-em-c-para-ler-e-restaurar-offsets&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.4 Acelera\u00e7\u00e3o linear e \u201cmovimento\u201d: o que d\u00e1 para fazer e o que n\u00e3o d\u00e1&quot;,&quot;text&quot;:&quot;6.4 Acelera\u00e7\u00e3o linear e \u201cmovimento\u201d: o que d\u00e1 para fazer e o que n\u00e3o d\u00e1&quot;,&quot;link&quot;:&quot;eb-table-content-43&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.5 Ligando isso ao problema do I2C em produto real&quot;,&quot;text&quot;:&quot;6.5 Ligando isso ao problema do I2C em produto real&quot;,&quot;link&quot;:&quot;65-ligando-isso-ao-problema-do-i2c-em-produto-real&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;6. Calibra\u00e7\u00e3o, Salvamento de Offsets e Uso de Acelera\u00e7\u00e3o Linear para Estimar Movimento&quot;,&quot;text&quot;:&quot;6. Calibra\u00e7\u00e3o, Salvamento de Offsets e Uso de Acelera\u00e7\u00e3o Linear para Estimar Movimento&quot;,&quot;link&quot;:&quot;eb-table-content-45&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.1 Lendo o status de calibra\u00e7\u00e3o (CALIB_STAT)&quot;,&quot;text&quot;:&quot;6.1 Lendo o status de calibra\u00e7\u00e3o (CALIB_STAT)&quot;,&quot;link&quot;:&quot;eb-table-content-46&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.2 Por que salvar calibra\u00e7\u00e3o vale ouro em produto real&quot;,&quot;text&quot;:&quot;6.2 Por que salvar calibra\u00e7\u00e3o vale ouro em produto real&quot;,&quot;link&quot;:&quot;eb-table-content-47&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.3 Rotina em C para ler e restaurar offsets&quot;,&quot;text&quot;:&quot;6.3 Rotina em C para ler e restaurar offsets&quot;,&quot;link&quot;:&quot;63-rotina-em-c-para-ler-e-restaurar-offsets&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.4 Acelera\u00e7\u00e3o linear e \u201cmovimento\u201d: o que d\u00e1 para fazer e o que n\u00e3o d\u00e1&quot;,&quot;text&quot;:&quot;6.4 Acelera\u00e7\u00e3o linear e \u201cmovimento\u201d: o que d\u00e1 para fazer e o que n\u00e3o d\u00e1&quot;,&quot;link&quot;:&quot;eb-table-content-49&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;6.5 Ligando isso ao problema do I2C em produto real&quot;,&quot;text&quot;:&quot;6.5 Ligando isso ao problema do I2C em produto real&quot;,&quot;link&quot;:&quot;65-ligando-isso-ao-problema-do-i2c-em-produto-real&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;7. Compatibilidade Real com Microcontroladores, Clock Stretching e Boas Pr\u00e1ticas de Engenharia&quot;,&quot;text&quot;:&quot;7. Compatibilidade Real com Microcontroladores, Clock Stretching e Boas Pr\u00e1ticas de Engenharia&quot;,&quot;link&quot;:&quot;eb-table-content-51&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.1 O caso cl\u00e1ssico: Raspberry Pi&quot;,&quot;text&quot;:&quot;7.1 O caso cl\u00e1ssico: Raspberry Pi&quot;,&quot;link&quot;:&quot;eb-table-content-52&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.2 ESP8266 e Implementa\u00e7\u00f5es por Software&quot;,&quot;text&quot;:&quot;7.2 ESP8266 e Implementa\u00e7\u00f5es por Software&quot;,&quot;link&quot;:&quot;eb-table-content-53&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.3 ESP32&quot;,&quot;text&quot;:&quot;7.3 ESP32&quot;,&quot;link&quot;:&quot;73-esp32&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.4 STM32&quot;,&quot;text&quot;:&quot;7.4 STM32&quot;,&quot;link&quot;:&quot;74-stm32&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.5 RP2040&quot;,&quot;text&quot;:&quot;7.5 RP2040&quot;,&quot;link&quot;:&quot;75-rp2040&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;7.6 nRF52&quot;,&quot;text&quot;:&quot;7.6 nRF52&quot;,&quot;link&quot;:&quot;76-nrf52&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;7.7 Quest\u00e3o El\u00e9trica: Pull-ups e Integridade de Sinal&quot;,&quot;text&quot;:&quot;7.7 Quest\u00e3o El\u00e9trica: Pull-ups e Integridade de Sinal&quot;,&quot;link&quot;:&quot;eb-table-content-58&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;7.8 Estrat\u00e9gia Profissional Recomendada&quot;,&quot;text&quot;:&quot;7.8 Estrat\u00e9gia Profissional Recomendada&quot;,&quot;link&quot;:&quot;eb-table-content-59&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;7.9 Compara\u00e7\u00e3o com Sensores que Exigem Fus\u00e3o Externa&quot;,&quot;text&quot;:&quot;7.9 Compara\u00e7\u00e3o com Sensores que Exigem Fus\u00e3o Externa&quot;,&quot;link&quot;:&quot;eb-table-content-60&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Conclus\u00e3o T\u00e9cnica&quot;,&quot;text&quot;:&quot;Conclus\u00e3o T\u00e9cnica&quot;,&quot;link&quot;:&quot;eb-table-content-61&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;8. Refer\u00eancias T\u00e9cnicas&quot;,&quot;text&quot;:&quot;8. Refer\u00eancias T\u00e9cnicas&quot;,&quot;link&quot;:&quot;eb-table-content-62&quot;}]" data-visible="[true,true,true,true,true,true]" data-delete-headers="[{&quot;label&quot;:&quot;Introdu\u00e7\u00e3o ao BNO055 e Conceito de Orienta\u00e7\u00e3o Absoluta&quot;,&quot;value&quot;:&quot;introdu\u00e7\u00e3o-ao-bno055-e-conceito-de-orienta\u00e7\u00e3o-absoluta&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2. Arquitetura Interna, Modos de Opera\u00e7\u00e3o e Sequ\u00eancia Correta de Inicializa\u00e7\u00e3o&quot;,&quot;value&quot;:&quot;2-arquitetura-interna-modos-de-opera\u00e7\u00e3o-e-sequ\u00eancia-correta-de-inicializa\u00e7\u00e3o&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.1 Organiza\u00e7\u00e3o de Registradores&quot;,&quot;value&quot;:&quot;21-organiza\u00e7\u00e3o-de-registradores&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.2 Modos de Opera\u00e7\u00e3o&quot;,&quot;value&quot;:&quot;22-modos-de-opera\u00e7\u00e3o&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.3 Sequ\u00eancia Correta de Inicializa\u00e7\u00e3o&quot;,&quot;value&quot;:&quot;23-sequ\u00eancia-correta-de-inicializa\u00e7\u00e3o&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.4 Exemplo de Inicializa\u00e7\u00e3o em C (Bare-Metal)&quot;,&quot;value&quot;:&quot;24-exemplo-de-inicializa\u00e7\u00e3o-em-c-bare-metal&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Verifica\u00e7\u00e3o do CHIP_ID&quot;,&quot;value&quot;:&quot;verifica\u00e7\u00e3o-do-chip_id&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Entrar em modo CONFIG&quot;,&quot;value&quot;:&quot;entrar-em-modo-config&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Reset&quot;,&quot;value&quot;:&quot;reset&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Selecionar modo NDOF&quot;,&quot;value&quot;:&quot;selecionar-modo-ndof&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2.5 Convers\u00e3o de Dados&quot;,&quot;value&quot;:&quot;25-convers\u00e3o-de-dados&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3. Fus\u00e3o Sensorial Interna, Quaternions, \u00c2ngulos de Euler e Fundamentos Trigonom\u00e9tricos&quot;,&quot;value&quot;:&quot;3-fus\u00e3o-sensorial-interna-quaternions-\u00e2ngulos-de-euler-e-fundamentos-trigonom\u00e9tricos&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.1 Papel de Cada Sensor na Fus\u00e3o&quot;,&quot;value&quot;:&quot;31-papel-de-cada-sensor-na-fus\u00e3o&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.2 \u00c2ngulos de Euler&quot;,&quot;value&quot;:&quot;32-\u00e2ngulos-de-euler&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Interpreta\u00e7\u00e3o Trigonom\u00e9trica&quot;,&quot;value&quot;:&quot;interpreta\u00e7\u00e3o-trigonom\u00e9trica&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.3 Quaternions&quot;,&quot;value&quot;:&quot;33-quaternions&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Convers\u00e3o Quaternion \u2192 Euler&quot;,&quot;value&quot;:&quot;convers\u00e3o-quaternion-\u2192-euler&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.4 Vetores Fornecidos pelo BNO055&quot;,&quot;value&quot;:&quot;34-vetores-fornecidos-pelo-bno055&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3.5 Processo de Calibra\u00e7\u00e3o&quot;,&quot;value&quot;:&quot;35-processo-de-calibra\u00e7\u00e3o&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4. Problemas no Barramento I2C: Por que o BNO055 \u201cquebra\u201d o protocolo e quais microcontroladores sofrem mais&quot;,&quot;value&quot;:&quot;4-problemas-no-barramento-i2c-por-que-o-bno055-quebra-o-protocolo-e-quais-microcontroladores-sofrem-mais&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.1 Relembrando o Protocolo I2C&quot;,&quot;value&quot;:&quot;41-relembrando-o-protocolo-i2c&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.2 O Problema Real do BNO055&quot;,&quot;value&quot;:&quot;42-o-problema-real-do-bno055&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.3 Microcontroladores que costumam apresentar problemas&quot;,&quot;value&quot;:&quot;43-microcontroladores-que-costumam-apresentar-problemas&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.4 Microcontroladores que funcionam bem&quot;,&quot;value&quot;:&quot;44-microcontroladores-que-funcionam-bem&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.5 Por que o BNO055 faz clock stretching longo?&quot;,&quot;value&quot;:&quot;45-por-que-o-bno055-faz-clock-stretching-longo&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.6 Exemplo de Erro T\u00edpico&quot;,&quot;value&quot;:&quot;46-exemplo-de-erro-t\u00edpico&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.7 Estrat\u00e9gias T\u00e9cnicas para Evitar Problemas&quot;,&quot;value&quot;:&quot;47-estrat\u00e9gias-t\u00e9cnicas-para-evitar-problemas&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Recupera\u00e7\u00e3o de Barramento (Exemplo Gen\u00e9rico)&quot;,&quot;value&quot;:&quot;recupera\u00e7\u00e3o-de-barramento-exemplo-gen\u00e9rico&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.8 Alternativa: Usar UART&quot;,&quot;value&quot;:&quot;48-alternativa-usar-uart&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4.9 An\u00e1lise Cr\u00edtica&quot;,&quot;value&quot;:&quot;49-an\u00e1lise-cr\u00edtica&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5. Driver Robusto em C para o BNO055 com Tratamento de Timeout e Recupera\u00e7\u00e3o de Barramento&quot;,&quot;value&quot;:&quot;5-driver-robusto-em-c-para-o-bno055-com-tratamento-de-timeout-e-recupera\u00e7\u00e3o-de-barramento&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.1 Endere\u00e7o I2C&quot;,&quot;value&quot;:&quot;51-endere\u00e7o-i2c&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.2 Escrita com Retry&quot;,&quot;value&quot;:&quot;52-escrita-com-retry&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.3 Leitura com Retry&quot;,&quot;value&quot;:&quot;53-leitura-com-retry&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.4 Inicializa\u00e7\u00e3o Segura Completa&quot;,&quot;value&quot;:&quot;54-inicializa\u00e7\u00e3o-segura-completa&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.5 Leitura de Quaternion&quot;,&quot;value&quot;:&quot;55-leitura-de-quaternion&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.6 Convers\u00e3o para \u00c2ngulos&quot;,&quot;value&quot;:&quot;56-convers\u00e3o-para-\u00e2ngulos&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.7 Estrutura de Aplica\u00e7\u00e3o Principal&quot;,&quot;value&quot;:&quot;57-estrutura-de-aplica\u00e7\u00e3o-principal&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5.8 Considera\u00e7\u00f5es Profissionais Importantes&quot;,&quot;value&quot;:&quot;58-considera\u00e7\u00f5es-profissionais-importantes&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6. Calibra\u00e7\u00e3o, Salvamento de Offsets e Uso de Acelera\u00e7\u00e3o Linear para Estimar Movimento&quot;,&quot;value&quot;:&quot;6-calibra\u00e7\u00e3o-salvamento-de-offsets-e-uso-de-acelera\u00e7\u00e3o-linear-para-estimar-movimento&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.1 Lendo o status de calibra\u00e7\u00e3o (CALIB_STAT)&quot;,&quot;value&quot;:&quot;61-lendo-o-status-de-calibra\u00e7\u00e3o-calib_stat&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.2 Por que salvar calibra\u00e7\u00e3o vale ouro em produto real&quot;,&quot;value&quot;:&quot;62-por-que-salvar-calibra\u00e7\u00e3o-vale-ouro-em-produto-real&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.3 Rotina em C para ler e restaurar offsets&quot;,&quot;value&quot;:&quot;63-rotina-em-c-para-ler-e-restaurar-offsets&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.4 Acelera\u00e7\u00e3o linear e \u201cmovimento\u201d: o que d\u00e1 para fazer e o que n\u00e3o d\u00e1&quot;,&quot;value&quot;:&quot;64-acelera\u00e7\u00e3o-linear-e-movimento-o-que-d\u00e1-para-fazer-e-o-que-n\u00e3o-d\u00e1&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.5 Ligando isso ao problema do I2C em produto real&quot;,&quot;value&quot;:&quot;65-ligando-isso-ao-problema-do-i2c-em-produto-real&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6. Calibra\u00e7\u00e3o, Salvamento de Offsets e Uso de Acelera\u00e7\u00e3o Linear para Estimar Movimento&quot;,&quot;value&quot;:&quot;6-calibra\u00e7\u00e3o-salvamento-de-offsets-e-uso-de-acelera\u00e7\u00e3o-linear-para-estimar-movimento&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.1 Lendo o status de calibra\u00e7\u00e3o (CALIB_STAT)&quot;,&quot;value&quot;:&quot;61-lendo-o-status-de-calibra\u00e7\u00e3o-calib_stat&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.2 Por que salvar calibra\u00e7\u00e3o vale ouro em produto real&quot;,&quot;value&quot;:&quot;62-por-que-salvar-calibra\u00e7\u00e3o-vale-ouro-em-produto-real&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.3 Rotina em C para ler e restaurar offsets&quot;,&quot;value&quot;:&quot;63-rotina-em-c-para-ler-e-restaurar-offsets&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.4 Acelera\u00e7\u00e3o linear e \u201cmovimento\u201d: o que d\u00e1 para fazer e o que n\u00e3o d\u00e1&quot;,&quot;value&quot;:&quot;64-acelera\u00e7\u00e3o-linear-e-movimento-o-que-d\u00e1-para-fazer-e-o-que-n\u00e3o-d\u00e1&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6.5 Ligando isso ao problema do I2C em produto real&quot;,&quot;value&quot;:&quot;65-ligando-isso-ao-problema-do-i2c-em-produto-real&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7. Compatibilidade Real com Microcontroladores, Clock Stretching e Boas Pr\u00e1ticas de Engenharia&quot;,&quot;value&quot;:&quot;7-compatibilidade-real-com-microcontroladores-clock-stretching-e-boas-pr\u00e1ticas-de-engenharia&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.1 O caso cl\u00e1ssico: Raspberry Pi&quot;,&quot;value&quot;:&quot;71-o-caso-cl\u00e1ssico-raspberry-pi&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.2 ESP8266 e Implementa\u00e7\u00f5es por Software&quot;,&quot;value&quot;:&quot;72-esp8266-e-implementa\u00e7\u00f5es-por-software&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.3 ESP32&quot;,&quot;value&quot;:&quot;73-esp32&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.4 STM32&quot;,&quot;value&quot;:&quot;74-stm32&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.5 RP2040&quot;,&quot;value&quot;:&quot;75-rp2040&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.6 nRF52&quot;,&quot;value&quot;:&quot;76-nrf52&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.7 Quest\u00e3o El\u00e9trica: Pull-ups e Integridade de Sinal&quot;,&quot;value&quot;:&quot;77-quest\u00e3o-el\u00e9trica-pull-ups-e-integridade-de-sinal&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.8 Estrat\u00e9gia Profissional Recomendada&quot;,&quot;value&quot;:&quot;78-estrat\u00e9gia-profissional-recomendada&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7.9 Compara\u00e7\u00e3o com Sensores que Exigem Fus\u00e3o Externa&quot;,&quot;value&quot;:&quot;79-compara\u00e7\u00e3o-com-sensores-que-exigem-fus\u00e3o-externa&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Conclus\u00e3o T\u00e9cnica&quot;,&quot;value&quot;:&quot;conclus\u00e3o-t\u00e9cnica&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;8. Refer\u00eancias T\u00e9cnicas&quot;,&quot;value&quot;:&quot;8-refer\u00eancias-t\u00e9cnicas&quot;,&quot;isDelete&quot;:false}]" data-smooth="true" data-top-offset=""><div class="eb-toc__list-wrap"><ul class="eb-toc__list"><li><a href="#eb-table-content-0">Introdução ao BNO055 e Conceito de Orientação Absoluta</a><li><a href="#eb-table-content-1">2. Arquitetura Interna, Modos de Operação e Sequência Correta de Inicialização</a><ul class="eb-toc__list"><li><a href="#eb-table-content-2">2.1 Organização de Registradores</a><li><a href="#eb-table-content-3">2.2 Modos de Operação</a><li><a href="#eb-table-content-4">2.3 Sequência Correta de Inicialização</a><li><a href="#eb-table-content-5">2.4 Exemplo de Inicialização em C (Bare-Metal)</a><ul class="eb-toc__list"><li><a href="#eb-table-content-6">Verificação do CHIP_ID</a><li><a href="#entrar-em-modo-config">Entrar em modo CONFIG</a><li><a href="#reset">Reset</a><li><a href="#selecionar-modo-ndof">Selecionar modo NDOF</a></li></ul><li><a href="#eb-table-content-10">2.5 Conversão de Dados</a></li></ul><li><a href="#eb-table-content-11">3. Fusão Sensorial Interna, Quaternions, Ângulos de Euler e Fundamentos Trigonométricos</a><ul class="eb-toc__list"><li><a href="#eb-table-content-12">3.1 Papel de Cada Sensor na Fusão</a></li></ul><li><a href="#eb-table-content-13">3.2 Ângulos de Euler</a><ul class="eb-toc__list"><li><a href="#eb-table-content-14">Interpretação Trigonométrica</a></li></ul><li><a href="#33-quaternions">3.3 Quaternions</a><ul class="eb-toc__list"><li><a href="#eb-table-content-16">Conversão Quaternion → Euler</a></li></ul><li><a href="#34-vetores-fornecidos-pelo-bno055">3.4 Vetores Fornecidos pelo BNO055</a><li><a href="#eb-table-content-18">3.5 Processo de Calibração</a><li><a href="#4-problemas-no-barramento-i2c-por-que-o-bno055-quebra-o-protocolo-e-quais-microcontroladores-sofrem-mais">4. Problemas no Barramento I2C: Por que o BNO055 “quebra” o protocolo e quais microcontroladores sofrem mais</a><ul class="eb-toc__list"><li><a href="#41-relembrando-o-protocolo-i2c">4.1 Relembrando o Protocolo I2C</a></li></ul><li><a href="#42-o-problema-real-do-bno055">4.2 O Problema Real do BNO055</a><li><a href="#43-microcontroladores-que-costumam-apresentar-problemas">4.3 Microcontroladores que costumam apresentar problemas</a><li><a href="#44-microcontroladores-que-funcionam-bem">4.4 Microcontroladores que funcionam bem</a><li><a href="#45-por-que-o-bno055-faz-clock-stretching-longo">4.5 Por que o BNO055 faz clock stretching longo?</a><li><a href="#eb-table-content-25">4.6 Exemplo de Erro Típico</a><li><a href="#eb-table-content-26">4.7 Estratégias Técnicas para Evitar Problemas</a><ul class="eb-toc__list"><li><a href="#eb-table-content-27">Recuperação de Barramento (Exemplo Genérico)</a></li></ul><li><a href="#48-alternativa-usar-uart">4.8 Alternativa: Usar UART</a><li><a href="#eb-table-content-29">4.9 Análise Crítica</a><li><a href="#eb-table-content-30">5. Driver Robusto em C para o BNO055 com Tratamento de Timeout e Recuperação de Barramento</a><ul class="eb-toc__list"><li><a href="#eb-table-content-31">5.1 Endereço I2C</a></li></ul><li><a href="#52-escrita-com-retry">5.2 Escrita com Retry</a><li><a href="#53-leitura-com-retry">5.3 Leitura com Retry</a><li><a href="#eb-table-content-34">5.4 Inicialização Segura Completa</a><li><a href="#55-leitura-de-quaternion">5.5 Leitura de Quaternion</a><li><a href="#eb-table-content-36">5.6 Conversão para Ângulos</a><li><a href="#eb-table-content-37">5.7 Estrutura de Aplicação Principal</a><li><a href="#eb-table-content-38">5.8 Considerações Profissionais Importantes</a><li><a href="#eb-table-content-39">6. Calibração, Salvamento de Offsets e Uso de Aceleração Linear para Estimar Movimento</a><ul class="eb-toc__list"><li><a href="#eb-table-content-40">6.1 Lendo o status de calibração (CALIB_STAT)</a><li><a href="#eb-table-content-41">6.2 Por que salvar calibração vale ouro em produto real</a><li><a href="#63-rotina-em-c-para-ler-e-restaurar-offsets">6.3 Rotina em C para ler e restaurar offsets</a><li><a href="#eb-table-content-43">6.4 Aceleração linear e “movimento”: o que dá para fazer e o que não dá</a><li><a href="#65-ligando-isso-ao-problema-do-i2c-em-produto-real">6.5 Ligando isso ao problema do I2C em produto real</a></li></ul><li><a href="#eb-table-content-45">6. Calibração, Salvamento de Offsets e Uso de Aceleração Linear para Estimar Movimento</a><ul class="eb-toc__list"><li><a href="#eb-table-content-46">6.1 Lendo o status de calibração (CALIB_STAT)</a><li><a href="#eb-table-content-47">6.2 Por que salvar calibração vale ouro em produto real</a><li><a href="#63-rotina-em-c-para-ler-e-restaurar-offsets">6.3 Rotina em C para ler e restaurar offsets</a><li><a href="#eb-table-content-49">6.4 Aceleração linear e “movimento”: o que dá para fazer e o que não dá</a><li><a href="#65-ligando-isso-ao-problema-do-i2c-em-produto-real">6.5 Ligando isso ao problema do I2C em produto real</a></li></ul><li><a href="#eb-table-content-51">7. Compatibilidade Real com Microcontroladores, Clock Stretching e Boas Práticas de Engenharia</a><ul class="eb-toc__list"><li><a href="#eb-table-content-52">7.1 O caso clássico: Raspberry Pi</a><li><a href="#eb-table-content-53">7.2 ESP8266 e Implementações por Software</a><li><a href="#73-esp32">7.3 ESP32</a><li><a href="#74-stm32">7.4 STM32</a><li><a href="#75-rp2040">7.5 RP2040</a><li><a href="#76-nrf52">7.6 nRF52</a></li></ul><li><a href="#eb-table-content-58">7.7 Questão Elétrica: Pull-ups e Integridade de Sinal</a><li><a href="#eb-table-content-59">7.8 Estratégia Profissional Recomendada</a><li><a href="#eb-table-content-60">7.9 Comparação com Sensores que Exigem Fusão Externa</a><li><a href="#eb-table-content-61">Conclusão Técnica</a><li><a href="#eb-table-content-62">8. Referências Técnicas</a></ul></div></div></div></div></div>


<h2 class="wp-block-heading">Introdução ao BNO055 e Conceito de Orientação Absoluta</h2>



<p class="wp-block-paragraph">O <strong>BNO055</strong>, fabricado pela Bosch Sensortec e amplamente difundido pela Adafruit Industries em sua placa breakout, é um sensor de orientação absoluta que integra acelerômetro, giroscópio e magnetômetro triaxiais, além de um microcontrolador interno dedicado à fusão sensorial. Diferentemente de sensores como MPU6050 ou MPU9250, nos quais a fusão deve ser implementada no microcontrolador hospedeiro, o BNO055 executa internamente o algoritmo proprietário da Bosch (BSX3.0), entregando diretamente quaternions, ângulos de Euler ou vetores de orientação já compensados.</p>



<p class="wp-block-paragraph">Segundo o datasheet oficial da Bosch (BST_BNO055_DS000_12.pdf), o dispositivo opera com dois domínios de alimentação: VDD (núcleo) e VDDIO (interface digital), normalmente 3,3 V na placa da Adafruit. Ele pode se comunicar via I2C ou UART, sendo o modo I2C o mais utilizado em sistemas embarcados. O sensor também implementa múltiplos modos de operação, incluindo apenas acelerômetro, apenas giroscópio, apenas magnetômetro ou fusão completa (NDOF – Nine Degrees of Freedom).</p>



<p class="wp-block-paragraph">O conceito de “orientação absoluta” significa que o sensor fornece a orientação do objeto em relação ao campo gravitacional da Terra e ao campo magnético terrestre, não apenas variações incrementais. O acelerômetro mede a aceleração linear e a gravidade, o giroscópio mede velocidade angular e o magnetômetro mede o campo magnético. A fusão combina essas três grandezas para eliminar deriva do giroscópio e ruído do acelerômetro.</p>



<p class="wp-block-paragraph">Internamente, o BNO055 possui registradores organizados em páginas (Page 0 e Page 1), sendo a Page 0 voltada para dados e controle geral, e a Page 1 para configurações avançadas dos sensores individuais. Isso já antecipa um cuidado importante no firmware: toda escrita em registrador deve considerar o registrador PAGE_ID (0x07), sob risco de configurar o sensor errado.</p>



<p class="wp-block-paragraph">Nesta primeira seção apresentamos o contexto arquitetural e conceitual do BNO055. Na próxima seção, detalharemos a arquitetura interna do sensor, seus modos de operação e o fluxo correto de inicialização segundo o datasheet e a implementação oficial da biblioteca da Adafruit.</p><p>The post <a href="https://mcu.tec.br/sensores/bno055-guia-completo-de-orientacao-absoluta-i2c-calibracao-e-driver-robusto-em-c/">BNO055: Guia Completo de Orientação Absoluta, I2C, Calibração e Driver Robusto em C</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1366</post-id>	</item>
		<item>
		<title>MPU6050 em projetos reais: do “dado cru” ao ângulo (e preparando terreno para o DMP)</title>
		<link>https://mcu.tec.br/sensores/mpu6050-em-projetos-reais-do-dado-cru-ao-angulo-e-preparando-terreno-para-o-dmp/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mpu6050-em-projetos-reais-do-dado-cru-ao-angulo-e-preparando-terreno-para-o-dmp</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Sat, 28 Feb 2026 10:06:45 +0000</pubDate>
				<category><![CDATA[Sensores]]></category>
		<category><![CDATA[aceleração linear IMU]]></category>
		<category><![CDATA[acelerômetro MPU6050]]></category>
		<category><![CDATA[cálculo de inclinação com atan2]]></category>
		<category><![CDATA[calibração giroscópio MPU6050]]></category>
		<category><![CDATA[DMP Motion Processor]]></category>
		<category><![CDATA[FIFO MPU6050]]></category>
		<category><![CDATA[filtro complementar IMU]]></category>
		<category><![CDATA[FreeRTOS MPU6050]]></category>
		<category><![CDATA[giroscópio MPU6050]]></category>
		<category><![CDATA[IMU 6 eixos]]></category>
		<category><![CDATA[integração de movimento com IMU]]></category>
		<category><![CDATA[integração giroscópio C]]></category>
		<category><![CDATA[MPU6050]]></category>
		<category><![CDATA[MPU6050 DMP]]></category>
		<category><![CDATA[orientação 3D microcontrolador]]></category>
		<category><![CDATA[programação MPU6050 em C]]></category>
		<category><![CDATA[quaternion MPU6050]]></category>
		<category><![CDATA[remover gravidade acelerômetro]]></category>
		<category><![CDATA[sensores inerciais embarcados]]></category>
		<category><![CDATA[superloop IMU]]></category>
		<category><![CDATA[yaw pitch roll MPU6050]]></category>
		<category><![CDATA[ZUPT IMU]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=1359</guid>

					<description><![CDATA[<p>Aprenda como usar o MPU6050 de forma profissional em projetos embarcados utilizando giroscópio, acelerômetro e o DMP interno. Este guia técnico explica passo a passo como configurar registradores, converter dados brutos para unidades físicas, calcular inclinação com trigonometria, integrar velocidade angular, aplicar filtro complementar e utilizar quaternions via FIFO do DMP para obter yaw, pitch e roll estáveis. Também demonstra como remover a gravidade para extrair aceleração linear real e integrar movimento com técnicas como ZUPT. Conteúdo completo com exemplos em linguagem C, arquitetura para superloop e FreeRTOS e boas práticas de depuração.</p>
<p>The post <a href="https://mcu.tec.br/sensores/mpu6050-em-projetos-reais-do-dado-cru-ao-angulo-e-preparando-terreno-para-o-dmp/">MPU6050 em projetos reais: do “dado cru” ao ângulo (e preparando terreno para o DMP)</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<div class="root-eb-toc-qidhp wp-block-essential-blocks-table-of-contents"><div class="eb-parent-wrapper eb-parent-eb-toc-qidhp "><div class="eb-toc-container eb-toc-qidhp  eb-toc-is-not-sticky eb-toc-not-collapsible eb-toc-initially-not-collapsed eb-toc-scrollToTop style-1 list-style-none" data-scroll-top="false" data-scroll-top-icon="fas fa-angle-up" data-collapsible="false" data-sticky-hide-mobile="false" data-sticky="false" data-scroll-target="scroll_to_toc" data-copy-link="false" data-editor-type="" data-hide-desktop="false" data-hide-tab="false" data-hide-mobile="false" data-itemcollapsed="false" data-highlight-scroll="false"><div class="eb-toc-header"><h2 class="eb-toc-title">Table of Contents</h2></div><div class="eb-toc-wrapper " data-headers="[{&quot;level&quot;:2,&quot;content&quot;:&quot;Leitura bruta e convers\u00e3o para unidades f\u00edsicas (C, I\u00b2C gen\u00e9rico)&quot;,&quot;text&quot;:&quot;Leitura bruta e convers\u00e3o para unidades f\u00edsicas (C, I\u00b2C gen\u00e9rico)&quot;,&quot;link&quot;:&quot;eb-table-content-0&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;C\u00f3digo (driver m\u00ednimo) \u2014 com callbacks de I\u00b2C&quot;,&quot;text&quot;:&quot;C\u00f3digo (driver m\u00ednimo) \u2014 com callbacks de I\u00b2C&quot;,&quot;link&quot;:&quot;eb-table-content-1&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;O que esse c\u00f3digo est\u00e1 fazendo (de verdade)&quot;,&quot;text&quot;:&quot;O que esse c\u00f3digo est\u00e1 fazendo (de verdade)&quot;,&quot;link&quot;:&quot;eb-table-content-2&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Observa\u00e7\u00e3o importante de bancada (qualidade de m\u00f3dulos no mercado)&quot;,&quot;text&quot;:&quot;Observa\u00e7\u00e3o importante de bancada (qualidade de m\u00f3dulos no mercado)&quot;,&quot;link&quot;:&quot;eb-table-content-3&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Inclina\u00e7\u00e3o por aceler\u00f4metro: pitch e roll com trigonometria (vetor gravidade + atan2)&quot;,&quot;text&quot;:&quot;Inclina\u00e7\u00e3o por aceler\u00f4metro: pitch e roll com trigonometria (vetor gravidade + atan2)&quot;,&quot;link&quot;:&quot;eb-table-content-4&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Modelo geom\u00e9trico (sem inventar \u201cm\u00e1gica\u201d)&quot;,&quot;text&quot;:&quot;Modelo geom\u00e9trico (sem inventar \u201cm\u00e1gica\u201d)&quot;,&quot;link&quot;:&quot;eb-table-content-5&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;C\u00f3digo em C: calcula pitch\/roll a partir dos dados convertidos&quot;,&quot;text&quot;:&quot;C\u00f3digo em C: calcula pitch\/roll a partir dos dados convertidos&quot;,&quot;link&quot;:&quot;eb-table-content-6&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Por que isso funciona (ligando matem\u00e1tica ao \u201cmundo f\u00edsico\u201d)&quot;,&quot;text&quot;:&quot;Por que isso funciona (ligando matem\u00e1tica ao \u201cmundo f\u00edsico\u201d)&quot;,&quot;link&quot;:&quot;eb-table-content-7&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Exemplo de uso (amarrando com a se\u00e7\u00e3o anterior)&quot;,&quot;text&quot;:&quot;Exemplo de uso (amarrando com a se\u00e7\u00e3o anterior)&quot;,&quot;link&quot;:&quot;eb-table-content-8&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Girosc\u00f3pio na pr\u00e1tica: taxa de rota\u00e7\u00e3o, integra\u00e7\u00e3o no tempo e \u00e2ngulo est\u00e1vel com fus\u00e3o (filtro complementar)&quot;,&quot;text&quot;:&quot;Girosc\u00f3pio na pr\u00e1tica: taxa de rota\u00e7\u00e3o, integra\u00e7\u00e3o no tempo e \u00e2ngulo est\u00e1vel com fus\u00e3o (filtro complementar)&quot;,&quot;link&quot;:&quot;eb-table-content-9&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;1) Calibrando o bias do girosc\u00f3pio (do jeito que funciona em bancada)&quot;,&quot;text&quot;:&quot;1) Calibrando o bias do girosc\u00f3pio (do jeito que funciona em bancada)&quot;,&quot;link&quot;:&quot;eb-table-content-10&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2) Integra\u00e7\u00e3o do girosc\u00f3pio para obter \u00e2ngulo (roll\/pitch) e por que deriva&quot;,&quot;text&quot;:&quot;2) Integra\u00e7\u00e3o do girosc\u00f3pio para obter \u00e2ngulo (roll\/pitch) e por que deriva&quot;,&quot;link&quot;:&quot;eb-table-content-11&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;3) Filtro complementar: girosc\u00f3pio r\u00e1pido + aceler\u00f4metro est\u00e1vel (pitch\/roll)&quot;,&quot;text&quot;:&quot;3) Filtro complementar: girosc\u00f3pio r\u00e1pido + aceler\u00f4metro est\u00e1vel (pitch\/roll)&quot;,&quot;link&quot;:&quot;eb-table-content-12&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;4) Medindo o dt direito (onde muita gente erra)&quot;,&quot;text&quot;:&quot;4) Medindo o dt direito (onde muita gente erra)&quot;,&quot;link&quot;:&quot;4-medindo-o-dt-direito-onde-muita-gente-erra&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Girosc\u00f3pio na pr\u00e1tica: taxa de rota\u00e7\u00e3o, integra\u00e7\u00e3o no tempo e \u00e2ngulo est\u00e1vel com fus\u00e3o (filtro complementar)&quot;,&quot;text&quot;:&quot;Girosc\u00f3pio na pr\u00e1tica: taxa de rota\u00e7\u00e3o, integra\u00e7\u00e3o no tempo e \u00e2ngulo est\u00e1vel com fus\u00e3o (filtro complementar)&quot;,&quot;link&quot;:&quot;eb-table-content-14&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;1) Calibrando o bias do girosc\u00f3pio (do jeito que funciona em bancada)&quot;,&quot;text&quot;:&quot;1) Calibrando o bias do girosc\u00f3pio (do jeito que funciona em bancada)&quot;,&quot;link&quot;:&quot;eb-table-content-15&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2) Integra\u00e7\u00e3o do girosc\u00f3pio para obter \u00e2ngulo (roll\/pitch) e por que deriva&quot;,&quot;text&quot;:&quot;2) Integra\u00e7\u00e3o do girosc\u00f3pio para obter \u00e2ngulo (roll\/pitch) e por que deriva&quot;,&quot;link&quot;:&quot;eb-table-content-16&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;3) Filtro complementar: girosc\u00f3pio r\u00e1pido + aceler\u00f4metro est\u00e1vel (pitch\/roll)&quot;,&quot;text&quot;:&quot;3) Filtro complementar: girosc\u00f3pio r\u00e1pido + aceler\u00f4metro est\u00e1vel (pitch\/roll)&quot;,&quot;link&quot;:&quot;eb-table-content-17&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;4) Medindo o dt direito (onde muita gente erra)&quot;,&quot;text&quot;:&quot;4) Medindo o dt direito (onde muita gente erra)&quot;,&quot;link&quot;:&quot;4-medindo-o-dt-direito-onde-muita-gente-erra&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Acelera\u00e7\u00e3o \u201cdo objeto\u201d e movimento: separando gravidade da acelera\u00e7\u00e3o linear (e por que integrar vira deriva)&quot;,&quot;text&quot;:&quot;Acelera\u00e7\u00e3o \u201cdo objeto\u201d e movimento: separando gravidade da acelera\u00e7\u00e3o linear (e por que integrar vira deriva)&quot;,&quot;link&quot;:&quot;eb-table-content-19&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Estimando o vetor gravidade no referencial do sensor a partir de roll\/pitch&quot;,&quot;text&quot;:&quot;Estimando o vetor gravidade no referencial do sensor a partir de roll\/pitch&quot;,&quot;link&quot;:&quot;estimando-o-vetor-gravidade-no-referencial-do-sensor-a-partir-de-rollpitch&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;C\u00f3digo em C: gravidade estimada e acelera\u00e7\u00e3o linear (em g e em m\/s\u00b2)&quot;,&quot;text&quot;:&quot;C\u00f3digo em C: gravidade estimada e acelera\u00e7\u00e3o linear (em g e em m\/s\u00b2)&quot;,&quot;link&quot;:&quot;eb-table-content-21&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Movimento: integrar acelera\u00e7\u00e3o linear para velocidade e posi\u00e7\u00e3o (e o \u201celefante na sala\u201d)&quot;,&quot;text&quot;:&quot;Movimento: integrar acelera\u00e7\u00e3o linear para velocidade e posi\u00e7\u00e3o (e o \u201celefante na sala\u201d)&quot;,&quot;link&quot;:&quot;eb-table-content-22&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Exemplo de loop completo (amarrando tudo)&quot;,&quot;text&quot;:&quot;Exemplo de loop completo (amarrando tudo)&quot;,&quot;link&quot;:&quot;exemplo-de-loop-completo-amarrando-tudo&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Usando o DMP interno do MPU6050: FIFO, interrup\u00e7\u00e3o, quaternions e yaw\/pitch\/roll com mais estabilidade&quot;,&quot;text&quot;:&quot;Usando o DMP interno do MPU6050: FIFO, interrup\u00e7\u00e3o, quaternions e yaw\/pitch\/roll com mais estabilidade&quot;,&quot;link&quot;:&quot;eb-table-content-24&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;1) O que o DMP entrega e por que o quaternion \u00e9 melhor que Euler direto&quot;,&quot;text&quot;:&quot;1) O que o DMP entrega e por que o quaternion \u00e9 melhor que Euler direto&quot;,&quot;link&quot;:&quot;eb-table-content-25&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2) Inicializa\u00e7\u00e3o t\u00edpica do DMP (o que precisa acontecer)&quot;,&quot;text&quot;:&quot;2) Inicializa\u00e7\u00e3o t\u00edpica do DMP (o que precisa acontecer)&quot;,&quot;link&quot;:&quot;eb-table-content-26&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;3) Leitura do FIFO: como extrair pacote, lidar com overflow e converter para \u00e2ngulos&quot;,&quot;text&quot;:&quot;3) Leitura do FIFO: como extrair pacote, lidar com overflow e converter para \u00e2ngulos&quot;,&quot;link&quot;:&quot;eb-table-content-27&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;4) Como isso conversa com \u201cacelera\u00e7\u00e3o do objeto\u201d e movimento&quot;,&quot;text&quot;:&quot;4) Como isso conversa com \u201cacelera\u00e7\u00e3o do objeto\u201d e movimento&quot;,&quot;link&quot;:&quot;eb-table-content-28&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Acelera\u00e7\u00e3o linear usando quaternion do DMP: remo\u00e7\u00e3o de gravidade \u201c3D correta\u201d e movimento (com limites honestos)&quot;,&quot;text&quot;:&quot;Acelera\u00e7\u00e3o linear usando quaternion do DMP: remo\u00e7\u00e3o de gravidade \u201c3D correta\u201d e movimento (com limites honestos)&quot;,&quot;link&quot;:&quot;eb-table-content-29&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;1) Gravidade a partir do quaternion (igual ao que as libs fazem, mas sem esconder o c\u00e1lculo)&quot;,&quot;text&quot;:&quot;1) Gravidade a partir do quaternion (igual ao que as libs fazem, mas sem esconder o c\u00e1lculo)&quot;,&quot;link&quot;:&quot;eb-table-content-30&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;2) Integrando para \u201cmovimento\u201d sem se enganar&quot;,&quot;text&quot;:&quot;2) Integrando para \u201cmovimento\u201d sem se enganar&quot;,&quot;link&quot;:&quot;2-integrando-para-movimento-sem-se-enganar&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Boas pr\u00e1ticas para MPU6050 + DMP (o que evita dor de cabe\u00e7a de verdade)&quot;,&quot;text&quot;:&quot;Boas pr\u00e1ticas para MPU6050 + DMP (o que evita dor de cabe\u00e7a de verdade)&quot;,&quot;link&quot;:&quot;eb-table-content-32&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Guia de depura\u00e7\u00e3o e arquitetura de firmware para MPU6050 + DMP (superloop ou FreeRTOS sem perder pacotes)&quot;,&quot;text&quot;:&quot;Guia de depura\u00e7\u00e3o e arquitetura de firmware para MPU6050 + DMP (superloop ou FreeRTOS sem perder pacotes)&quot;,&quot;link&quot;:&quot;eb-table-content-33&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Superloop robusto com INT: ler FIFO apenas quando chegar dado novo&quot;,&quot;text&quot;:&quot;Superloop robusto com INT: ler FIFO apenas quando chegar dado novo&quot;,&quot;link&quot;:&quot;superloop-robusto-com-int-ler-fifo-apenas-quando-chegar-dado-novo&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Em FreeRTOS: ISR d\u00e1 um \u201csinal\u201d, tarefa l\u00ea FIFO e processa&quot;,&quot;text&quot;:&quot;Em FreeRTOS: ISR d\u00e1 um \u201csinal\u201d, tarefa l\u00ea FIFO e processa&quot;,&quot;link&quot;:&quot;eb-table-content-35&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Como identificar r\u00e1pido a causa quando \u201cest\u00e1 ruim\u201d&quot;,&quot;text&quot;:&quot;Como identificar r\u00e1pido a causa quando \u201cest\u00e1 ruim\u201d&quot;,&quot;link&quot;:&quot;eb-table-content-36&quot;},{&quot;level&quot;:3,&quot;content&quot;:&quot;Fechando o ciclo com o que voc\u00ea pediu: por que o DMP melhora \u201cresultados\u201d&quot;,&quot;text&quot;:&quot;Fechando o ciclo com o que voc\u00ea pediu: por que o DMP melhora \u201cresultados\u201d&quot;,&quot;link&quot;:&quot;eb-table-content-37&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Refer\u00eancias&quot;,&quot;text&quot;:&quot;Refer\u00eancias&quot;,&quot;link&quot;:&quot;eb-table-content-38&quot;}]" data-visible="[true,true,true,true,true,true]" data-delete-headers="[{&quot;label&quot;:&quot;Leitura bruta e convers\u00e3o para unidades f\u00edsicas (C, I\u00b2C gen\u00e9rico)&quot;,&quot;value&quot;:&quot;leitura-bruta-e-convers\u00e3o-para-unidades-f\u00edsicas-c-i\u00b2c-gen\u00e9rico&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;C\u00f3digo (driver m\u00ednimo) \u2014 com callbacks de I\u00b2C&quot;,&quot;value&quot;:&quot;c\u00f3digo-driver-m\u00ednimo-com-callbacks-de-i\u00b2c&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;O que esse c\u00f3digo est\u00e1 fazendo (de verdade)&quot;,&quot;value&quot;:&quot;o-que-esse-c\u00f3digo-est\u00e1-fazendo-de-verdade&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Observa\u00e7\u00e3o importante de bancada (qualidade de m\u00f3dulos no mercado)&quot;,&quot;value&quot;:&quot;observa\u00e7\u00e3o-importante-de-bancada-qualidade-de-m\u00f3dulos-no-mercado&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Inclina\u00e7\u00e3o por aceler\u00f4metro: pitch e roll com trigonometria (vetor gravidade + atan2)&quot;,&quot;value&quot;:&quot;inclina\u00e7\u00e3o-por-aceler\u00f4metro-pitch-e-roll-com-trigonometria-vetor-gravidade-atan2&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Modelo geom\u00e9trico (sem inventar \u201cm\u00e1gica\u201d)&quot;,&quot;value&quot;:&quot;modelo-geom\u00e9trico-sem-inventar-m\u00e1gica&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;C\u00f3digo em C: calcula pitch\/roll a partir dos dados convertidos&quot;,&quot;value&quot;:&quot;c\u00f3digo-em-c-calcula-pitchroll-a-partir-dos-dados-convertidos&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Por que isso funciona (ligando matem\u00e1tica ao \u201cmundo f\u00edsico\u201d)&quot;,&quot;value&quot;:&quot;por-que-isso-funciona-ligando-matem\u00e1tica-ao-mundo-f\u00edsico&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Exemplo de uso (amarrando com a se\u00e7\u00e3o anterior)&quot;,&quot;value&quot;:&quot;exemplo-de-uso-amarrando-com-a-se\u00e7\u00e3o-anterior&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Girosc\u00f3pio na pr\u00e1tica: taxa de rota\u00e7\u00e3o, integra\u00e7\u00e3o no tempo e \u00e2ngulo est\u00e1vel com fus\u00e3o (filtro complementar)&quot;,&quot;value&quot;:&quot;girosc\u00f3pio-na-pr\u00e1tica-taxa-de-rota\u00e7\u00e3o-integra\u00e7\u00e3o-no-tempo-e-\u00e2ngulo-est\u00e1vel-com-fus\u00e3o-filtro-complementar&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;1) Calibrando o bias do girosc\u00f3pio (do jeito que funciona em bancada)&quot;,&quot;value&quot;:&quot;1-calibrando-o-bias-do-girosc\u00f3pio-do-jeito-que-funciona-em-bancada&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2) Integra\u00e7\u00e3o do girosc\u00f3pio para obter \u00e2ngulo (roll\/pitch) e por que deriva&quot;,&quot;value&quot;:&quot;2-integra\u00e7\u00e3o-do-girosc\u00f3pio-para-obter-\u00e2ngulo-rollpitch-e-por-que-deriva&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3) Filtro complementar: girosc\u00f3pio r\u00e1pido + aceler\u00f4metro est\u00e1vel (pitch\/roll)&quot;,&quot;value&quot;:&quot;3-filtro-complementar-girosc\u00f3pio-r\u00e1pido-aceler\u00f4metro-est\u00e1vel-pitchroll&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4) Medindo o dt direito (onde muita gente erra)&quot;,&quot;value&quot;:&quot;4-medindo-o-dt-direito-onde-muita-gente-erra&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Girosc\u00f3pio na pr\u00e1tica: taxa de rota\u00e7\u00e3o, integra\u00e7\u00e3o no tempo e \u00e2ngulo est\u00e1vel com fus\u00e3o (filtro complementar)&quot;,&quot;value&quot;:&quot;girosc\u00f3pio-na-pr\u00e1tica-taxa-de-rota\u00e7\u00e3o-integra\u00e7\u00e3o-no-tempo-e-\u00e2ngulo-est\u00e1vel-com-fus\u00e3o-filtro-complementar&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;1) Calibrando o bias do girosc\u00f3pio (do jeito que funciona em bancada)&quot;,&quot;value&quot;:&quot;1-calibrando-o-bias-do-girosc\u00f3pio-do-jeito-que-funciona-em-bancada&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2) Integra\u00e7\u00e3o do girosc\u00f3pio para obter \u00e2ngulo (roll\/pitch) e por que deriva&quot;,&quot;value&quot;:&quot;2-integra\u00e7\u00e3o-do-girosc\u00f3pio-para-obter-\u00e2ngulo-rollpitch-e-por-que-deriva&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3) Filtro complementar: girosc\u00f3pio r\u00e1pido + aceler\u00f4metro est\u00e1vel (pitch\/roll)&quot;,&quot;value&quot;:&quot;3-filtro-complementar-girosc\u00f3pio-r\u00e1pido-aceler\u00f4metro-est\u00e1vel-pitchroll&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4) Medindo o dt direito (onde muita gente erra)&quot;,&quot;value&quot;:&quot;4-medindo-o-dt-direito-onde-muita-gente-erra&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Acelera\u00e7\u00e3o \u201cdo objeto\u201d e movimento: separando gravidade da acelera\u00e7\u00e3o linear (e por que integrar vira deriva)&quot;,&quot;value&quot;:&quot;acelera\u00e7\u00e3o-do-objeto-e-movimento-separando-gravidade-da-acelera\u00e7\u00e3o-linear-e-por-que-integrar-vira-deriva&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Estimando o vetor gravidade no referencial do sensor a partir de roll\/pitch&quot;,&quot;value&quot;:&quot;estimando-o-vetor-gravidade-no-referencial-do-sensor-a-partir-de-rollpitch&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;C\u00f3digo em C: gravidade estimada e acelera\u00e7\u00e3o linear (em g e em m\/s\u00b2)&quot;,&quot;value&quot;:&quot;c\u00f3digo-em-c-gravidade-estimada-e-acelera\u00e7\u00e3o-linear-em-g-e-em-ms\u00b2&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Movimento: integrar acelera\u00e7\u00e3o linear para velocidade e posi\u00e7\u00e3o (e o \u201celefante na sala\u201d)&quot;,&quot;value&quot;:&quot;movimento-integrar-acelera\u00e7\u00e3o-linear-para-velocidade-e-posi\u00e7\u00e3o-e-o-elefante-na-sala&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Exemplo de loop completo (amarrando tudo)&quot;,&quot;value&quot;:&quot;exemplo-de-loop-completo-amarrando-tudo&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Usando o DMP interno do MPU6050: FIFO, interrup\u00e7\u00e3o, quaternions e yaw\/pitch\/roll com mais estabilidade&quot;,&quot;value&quot;:&quot;usando-o-dmp-interno-do-mpu6050-fifo-interrup\u00e7\u00e3o-quaternions-e-yawpitchroll-com-mais-estabilidade&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;1) O que o DMP entrega e por que o quaternion \u00e9 melhor que Euler direto&quot;,&quot;value&quot;:&quot;1-o-que-o-dmp-entrega-e-por-que-o-quaternion-\u00e9-melhor-que-euler-direto&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2) Inicializa\u00e7\u00e3o t\u00edpica do DMP (o que precisa acontecer)&quot;,&quot;value&quot;:&quot;2-inicializa\u00e7\u00e3o-t\u00edpica-do-dmp-o-que-precisa-acontecer&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3) Leitura do FIFO: como extrair pacote, lidar com overflow e converter para \u00e2ngulos&quot;,&quot;value&quot;:&quot;3-leitura-do-fifo-como-extrair-pacote-lidar-com-overflow-e-converter-para-\u00e2ngulos&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4) Como isso conversa com \u201cacelera\u00e7\u00e3o do objeto\u201d e movimento&quot;,&quot;value&quot;:&quot;4-como-isso-conversa-com-acelera\u00e7\u00e3o-do-objeto-e-movimento&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Acelera\u00e7\u00e3o linear usando quaternion do DMP: remo\u00e7\u00e3o de gravidade \u201c3D correta\u201d e movimento (com limites honestos)&quot;,&quot;value&quot;:&quot;acelera\u00e7\u00e3o-linear-usando-quaternion-do-dmp-remo\u00e7\u00e3o-de-gravidade-3d-correta-e-movimento-com-limites-honestos&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;1) Gravidade a partir do quaternion (igual ao que as libs fazem, mas sem esconder o c\u00e1lculo)&quot;,&quot;value&quot;:&quot;1-gravidade-a-partir-do-quaternion-igual-ao-que-as-libs-fazem-mas-sem-esconder-o-c\u00e1lculo&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2) Integrando para \u201cmovimento\u201d sem se enganar&quot;,&quot;value&quot;:&quot;2-integrando-para-movimento-sem-se-enganar&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Boas pr\u00e1ticas para MPU6050 + DMP (o que evita dor de cabe\u00e7a de verdade)&quot;,&quot;value&quot;:&quot;boas-pr\u00e1ticas-para-mpu6050-dmp-o-que-evita-dor-de-cabe\u00e7a-de-verdade&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Guia de depura\u00e7\u00e3o e arquitetura de firmware para MPU6050 + DMP (superloop ou FreeRTOS sem perder pacotes)&quot;,&quot;value&quot;:&quot;guia-de-depura\u00e7\u00e3o-e-arquitetura-de-firmware-para-mpu6050-dmp-superloop-ou-freertos-sem-perder-pacotes&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Superloop robusto com INT: ler FIFO apenas quando chegar dado novo&quot;,&quot;value&quot;:&quot;superloop-robusto-com-int-ler-fifo-apenas-quando-chegar-dado-novo&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Em FreeRTOS: ISR d\u00e1 um \u201csinal\u201d, tarefa l\u00ea FIFO e processa&quot;,&quot;value&quot;:&quot;em-freertos-isr-d\u00e1-um-sinal-tarefa-l\u00ea-fifo-e-processa&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Como identificar r\u00e1pido a causa quando \u201cest\u00e1 ruim\u201d&quot;,&quot;value&quot;:&quot;como-identificar-r\u00e1pido-a-causa-quando-est\u00e1-ruim&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Fechando o ciclo com o que voc\u00ea pediu: por que o DMP melhora \u201cresultados\u201d&quot;,&quot;value&quot;:&quot;fechando-o-ciclo-com-o-que-voc\u00ea-pediu-por-que-o-dmp-melhora-resultados&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Refer\u00eancias&quot;,&quot;value&quot;:&quot;refer\u00eancias&quot;,&quot;isDelete&quot;:false}]" data-smooth="true" data-top-offset=""><div class="eb-toc__list-wrap"><ul class="eb-toc__list"><li><a href="#eb-table-content-0">Leitura bruta e conversão para unidades físicas (C, I²C genérico)</a><ul class="eb-toc__list"><li><a href="#eb-table-content-1">Código (driver mínimo) — com callbacks de I²C</a><li><a href="#eb-table-content-2">O que esse código está fazendo (de verdade)</a><li><a href="#eb-table-content-3">Observação importante de bancada (qualidade de módulos no mercado)</a></li></ul><li><a href="#eb-table-content-4">Inclinação por acelerômetro: pitch e roll com trigonometria (vetor gravidade + atan2)</a><ul class="eb-toc__list"><li><a href="#eb-table-content-5">Modelo geométrico (sem inventar “mágica”)</a><li><a href="#eb-table-content-6">Código em C: calcula pitch/roll a partir dos dados convertidos</a><li><a href="#eb-table-content-7">Por que isso funciona (ligando matemática ao “mundo físico”)</a><li><a href="#eb-table-content-8">Exemplo de uso (amarrando com a seção anterior)</a></li></ul><li><a href="#eb-table-content-9">Giroscópio na prática: taxa de rotação, integração no tempo e ângulo estável com fusão (filtro complementar)</a><ul class="eb-toc__list"><li><a href="#eb-table-content-10">1) Calibrando o bias do giroscópio (do jeito que funciona em bancada)</a><li><a href="#eb-table-content-11">2) Integração do giroscópio para obter ângulo (roll/pitch) e por que deriva</a><li><a href="#eb-table-content-12">3) Filtro complementar: giroscópio rápido + acelerômetro estável (pitch/roll)</a><li><a href="#4-medindo-o-dt-direito-onde-muita-gente-erra">4) Medindo o dt direito (onde muita gente erra)</a></li></ul><li><a href="#eb-table-content-14">Giroscópio na prática: taxa de rotação, integração no tempo e ângulo estável com fusão (filtro complementar)</a><ul class="eb-toc__list"><li><a href="#eb-table-content-15">1) Calibrando o bias do giroscópio (do jeito que funciona em bancada)</a><li><a href="#eb-table-content-16">2) Integração do giroscópio para obter ângulo (roll/pitch) e por que deriva</a><li><a href="#eb-table-content-17">3) Filtro complementar: giroscópio rápido + acelerômetro estável (pitch/roll)</a><li><a href="#4-medindo-o-dt-direito-onde-muita-gente-erra">4) Medindo o dt direito (onde muita gente erra)</a></li></ul><li><a href="#eb-table-content-19">Aceleração “do objeto” e movimento: separando gravidade da aceleração linear (e por que integrar vira deriva)</a><ul class="eb-toc__list"><li><a href="#estimando-o-vetor-gravidade-no-referencial-do-sensor-a-partir-de-rollpitch">Estimando o vetor gravidade no referencial do sensor a partir de roll/pitch</a><li><a href="#eb-table-content-21">Código em C: gravidade estimada e aceleração linear (em g e em m/s²)</a><li><a href="#eb-table-content-22">Movimento: integrar aceleração linear para velocidade e posição (e o “elefante na sala”)</a><li><a href="#exemplo-de-loop-completo-amarrando-tudo">Exemplo de loop completo (amarrando tudo)</a></li></ul><li><a href="#eb-table-content-24">Usando o DMP interno do MPU6050: FIFO, interrupção, quaternions e yaw/pitch/roll com mais estabilidade</a><ul class="eb-toc__list"><li><a href="#eb-table-content-25">1) O que o DMP entrega e por que o quaternion é melhor que Euler direto</a><li><a href="#eb-table-content-26">2) Inicialização típica do DMP (o que precisa acontecer)</a><li><a href="#eb-table-content-27">3) Leitura do FIFO: como extrair pacote, lidar com overflow e converter para ângulos</a><li><a href="#eb-table-content-28">4) Como isso conversa com “aceleração do objeto” e movimento</a></li></ul><li><a href="#eb-table-content-29">Aceleração linear usando quaternion do DMP: remoção de gravidade “3D correta” e movimento (com limites honestos)</a><ul class="eb-toc__list"><li><a href="#eb-table-content-30">1) Gravidade a partir do quaternion (igual ao que as libs fazem, mas sem esconder o cálculo)</a><li><a href="#2-integrando-para-movimento-sem-se-enganar">2) Integrando para “movimento” sem se enganar</a></li></ul><li><a href="#eb-table-content-32">Boas práticas para MPU6050 + DMP (o que evita dor de cabeça de verdade)</a><li><a href="#eb-table-content-33">Guia de depuração e arquitetura de firmware para MPU6050 + DMP (superloop ou FreeRTOS sem perder pacotes)</a><ul class="eb-toc__list"><li><a href="#superloop-robusto-com-int-ler-fifo-apenas-quando-chegar-dado-novo">Superloop robusto com INT: ler FIFO apenas quando chegar dado novo</a><li><a href="#eb-table-content-35">Em FreeRTOS: ISR dá um “sinal”, tarefa lê FIFO e processa</a><li><a href="#eb-table-content-36">Como identificar rápido a causa quando “está ruim”</a><li><a href="#eb-table-content-37">Fechando o ciclo com o que você pediu: por que o DMP melhora “resultados”</a></li></ul><li><a href="#eb-table-content-38">Referências</a></ul></div></div></div></div></div>


<p class="wp-block-paragraph">O MPU6050 é uma IMU (Unidade de Medição Inercial) de 6 eixos que integra acelerômetro (3 eixos) e giroscópio (3 eixos) e expõe tudo via I²C. A forma mais confiável de “começar certo” é dominar primeiro a leitura bruta e as conversões (LSB → unidades físicas), porque isso te dá um baseline para validar qualquer etapa posterior (filtros, fusão, DMP e quaternions). A própria InvenSense/TDK documenta o mapa de registradores e a especificação do dispositivo, que é o que vamos seguir aqui. (<a href="https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf?utm_source=chatgpt.com">TDK InvenSense</a>)</p>



<p class="wp-block-paragraph">Nesta primeira seção eu vou te entregar um “núcleo” em C: inicialização mínima, leitura de acelerômetro/giroscópio e conversão para <strong>g</strong>, <strong>m/s²</strong> e <strong>°/s</strong>. Na próxima seção, eu sigo para <strong>inclinação por trigonometria</strong> (pitch/roll por acelerômetro), depois <strong>integração do giroscópio</strong> e, em seguida, <strong>DMP + FIFO + quaternions</strong> (onde o ganho é enorme em estabilidade e praticidade).</p>


<div class="wp-block-image">
<figure class="alignright size-full is-resized"><img fetchpriority="high" decoding="async" width="600" height="600" src="https://mcu.tec.br/wp-content/uploads/2026/02/image-43.png" alt="" class="wp-image-1361" style="width:445px;height:auto" srcset="https://mcu.tec.br/wp-content/uploads/2026/02/image-43.png 600w, https://mcu.tec.br/wp-content/uploads/2026/02/image-43-300x300.png 300w, https://mcu.tec.br/wp-content/uploads/2026/02/image-43-150x150.png 150w" sizes="(max-width: 600px) 100vw, 600px" /></figure>
</div>


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



<h2 class="wp-block-heading">Leitura bruta e conversão para unidades físicas (C, I²C genérico)</h2>



<p class="wp-block-paragraph">A base do MPU6050 é simples: você configura alguns registradores de controle (clock, escalas, taxa de amostragem) e lê 14 bytes contínuos a partir do registrador de aceleração. Esses 14 bytes contêm <strong>AX, AY, AZ, temperatura, GX, GY, GZ</strong>, cada um em <strong>16 bits com sinal</strong> (two’s complement), com byte alto seguido de byte baixo. O endereço do registrador inicial e os registradores de controle usados abaixo estão no “Register Map and Descriptions”. (<a href="https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf?utm_source=chatgpt.com">TDK InvenSense</a>)</p>



<h3 class="wp-block-heading">Código (driver mínimo) — com callbacks de I²C</h3>



<p class="wp-block-paragraph">O código abaixo não “inventa HAL”. Ele assume que você já tem I²C funcionando e consegue implementar duas funções: <code>i2c_write_reg()</code> e <code>i2c_read_regs()</code>. Isso deixa o exemplo portável para STM32, AVR, ESP32, Linux, etc.</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>#include &lt;stdint.h>
#include &lt;stdbool.h>

#ifndef MPU6050_I2C_ADDR
// AD0=0 -> 0x68, AD0=1 -> 0x69 (endereço de 7 bits)
#define MPU6050_I2C_ADDR 0x68
#endif

// Registradores principais (MPU-6000/MPU-6050 Register Map)
#define REG_SMPLRT_DIV    0x19
#define REG_CONFIG        0x1A
#define REG_GYRO_CONFIG   0x1B
#define REG_ACCEL_CONFIG  0x1C
#define REG_INT_ENABLE    0x38
#define REG_ACCEL_XOUT_H  0x3B
#define REG_PWR_MGMT_1    0x6B
#define REG_WHO_AM_I      0x75

// Bits e campos úteis
#define PWR1_SLEEP_BIT    6

// FS_SEL (GYRO_CONFIG&#91;4:3&#93;) e AFS_SEL (ACCEL_CONFIG&#91;4:3&#93;)
typedef enum {
    MPU6050_GYRO_FS_250  = 0, // ±250 °/s
    MPU6050_GYRO_FS_500  = 1, // ±500 °/s
    MPU6050_GYRO_FS_1000 = 2, // ±1000 °/s
    MPU6050_GYRO_FS_2000 = 3  // ±2000 °/s
} mpu6050_gyro_fs_t;

typedef enum {
    MPU6050_ACCEL_FS_2G  = 0, // ±2 g
    MPU6050_ACCEL_FS_4G  = 1, // ±4 g
    MPU6050_ACCEL_FS_8G  = 2, // ±8 g
    MPU6050_ACCEL_FS_16G = 3  // ±16 g
} mpu6050_accel_fs_t;

typedef struct {
    mpu6050_gyro_fs_t  gyro_fs;
    mpu6050_accel_fs_t accel_fs;

    // fatores de escala (LSB por unidade)
    float accel_lsb_per_g;
    float gyro_lsb_per_dps;
} mpu6050_cfg_t;

typedef struct {
    int16_t ax, ay, az;
    int16_t gx, gy, gz;
    int16_t temp_raw;
} mpu6050_raw_t;

typedef struct {
    // aceleração
    float ax_g, ay_g, az_g;        // em g
    float ax_ms2, ay_ms2, az_ms2;  // em m/s²
    // rotação
    float gx_dps, gy_dps, gz_dps;  // em °/s
} mpu6050_si_t;

// Você implementa essas duas funções na sua plataforma:
extern bool i2c_write_reg(uint8_t addr7, uint8_t reg, uint8_t value);
extern bool i2c_read_regs(uint8_t addr7, uint8_t start_reg, uint8_t *buf, uint16_t len);

static float accel_lsb_per_g_from_fs(mpu6050_accel_fs_t fs) {
    // Do datasheet/register map: sensibilidade depende do AFS_SEL. :contentReference&#91;oaicite:2&#93;{index=2}
    switch (fs) {
        case MPU6050_ACCEL_FS_2G:  return 16384.0f;
        case MPU6050_ACCEL_FS_4G:  return 8192.0f;
        case MPU6050_ACCEL_FS_8G:  return 4096.0f;
        case MPU6050_ACCEL_FS_16G: return 2048.0f;
        default: return 16384.0f;
    }
}

static float gyro_lsb_per_dps_from_fs(mpu6050_gyro_fs_t fs) {
    // Do datasheet/register map: sensibilidade depende do FS_SEL. :contentReference&#91;oaicite:3&#93;{index=3}
    switch (fs) {
        case MPU6050_GYRO_FS_250:  return 131.0f;
        case MPU6050_GYRO_FS_500:  return 65.5f;
        case MPU6050_GYRO_FS_1000: return 32.8f;
        case MPU6050_GYRO_FS_2000: return 16.4f;
        default: return 131.0f;
    }
}

bool mpu6050_init(const mpu6050_cfg_t *cfg) {
    // 1) Acorda o chip e seleciona clock interno padrão (PWR_MGMT_1).
    // Escrever 0 em PWR_MGMT_1 limpa SLEEP e deixa o clock interno ativo. :contentReference&#91;oaicite:4&#93;{index=4}
    if (!i2c_write_reg(MPU6050_I2C_ADDR, REG_PWR_MGMT_1, 0x00)) return false;

    // 2) Configura escalas de acel/gyro nos campos &#91;4:3&#93;
    // ACCEL_CONFIG: AFS_SEL em bits 4:3
    uint8_t accel_cfg = ((uint8_t)cfg->accel_fs &amp; 0x03u) &lt;&lt; 3;
    if (!i2c_write_reg(MPU6050_I2C_ADDR, REG_ACCEL_CONFIG, accel_cfg)) return false;

    // GYRO_CONFIG: FS_SEL em bits 4:3
    uint8_t gyro_cfg = ((uint8_t)cfg->gyro_fs &amp; 0x03u) &lt;&lt; 3;
    if (!i2c_write_reg(MPU6050_I2C_ADDR, REG_GYRO_CONFIG, gyro_cfg)) return false;

    // 3) (Opcional, mas recomendado) filtro digital passa-baixa (DLPF) e taxa de amostragem
    // CONFIG: DLPF_CFG em bits &#91;2:0&#93;. Ex.: 3 => um corte típico para reduzir ruído (ver tabela no register map). :contentReference&#91;oaicite:5&#93;{index=5}
    if (!i2c_write_reg(MPU6050_I2C_ADDR, REG_CONFIG, 0x03)) return false;

    // SMPLRT_DIV define taxa efetiva: sample_rate = gyro_output_rate / (1 + SMPLRT_DIV).
    // gyro_output_rate é 8 kHz quando DLPF_CFG=0, senão 1 kHz (ver register map). :contentReference&#91;oaicite:6&#93;{index=6}
    if (!i2c_write_reg(MPU6050_I2C_ADDR, REG_SMPLRT_DIV, 0x04)) return false; // exemplo

    // 4) Interrupções ficam para depois (no DMP a gente usa bastante INT + FIFO).
    if (!i2c_write_reg(MPU6050_I2C_ADDR, REG_INT_ENABLE, 0x00)) return false;

    return true;
}

bool mpu6050_read_raw(mpu6050_raw_t *out) {
    uint8_t buf&#91;14&#93;;
    if (!i2c_read_regs(MPU6050_I2C_ADDR, REG_ACCEL_XOUT_H, buf, 14)) return false;

    // Cada eixo é big-endian: High, Low
    out->ax = (int16_t)((buf&#91;0&#93; &lt;&lt; 8) | buf&#91;1&#93;);
    out->ay = (int16_t)((buf&#91;2&#93; &lt;&lt; 8) | buf&#91;3&#93;);
    out->az = (int16_t)((buf&#91;4&#93; &lt;&lt; 8) | buf&#91;5&#93;);
    out->temp_raw = (int16_t)((buf&#91;6&#93; &lt;&lt; 8) | buf&#91;7&#93;);
    out->gx = (int16_t)((buf&#91;8&#93;  &lt;&lt; 8) | buf&#91;9&#93;);
    out->gy = (int16_t)((buf&#91;10&#93; &lt;&lt; 8) | buf&#91;11&#93;);
    out->gz = (int16_t)((buf&#91;12&#93; &lt;&lt; 8) | buf&#91;13&#93;);

    return true;
}

void mpu6050_convert_to_si(const mpu6050_cfg_t *cfg, const mpu6050_raw_t *raw, mpu6050_si_t *out) {
    const float lsb_per_g   = accel_lsb_per_g_from_fs(cfg->accel_fs);
    const float lsb_per_dps = gyro_lsb_per_dps_from_fs(cfg->gyro_fs);

    // aceleração em g
    out->ax_g = (float)raw->ax / lsb_per_g;
    out->ay_g = (float)raw->ay / lsb_per_g;
    out->az_g = (float)raw->az / lsb_per_g;

    // g -> m/s² (g padrão ~ 9.80665)
    const float g0 = 9.80665f;
    out->ax_ms2 = out->ax_g * g0;
    out->ay_ms2 = out->ay_g * g0;
    out->az_ms2 = out->az_g * g0;

    // giro em °/s
    out->gx_dps = (float)raw->gx / lsb_per_dps;
    out->gy_dps = (float)raw->gy / lsb_per_dps;
    out->gz_dps = (float)raw->gz / lsb_per_dps;
}
</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: #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 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>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">ifndef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_I2C_ADDR</span></span>
<span class="line"><span style="color: #616E88">// AD0=0 -&gt; 0x68, AD0=1 -&gt; 0x69 (endereço de 7 bits)</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">MPU6050_I2C_ADDR</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x68</span></span>
<span class="line"><span style="color: #D8DEE9FF">#</span><span style="color: #D8DEE9">endif</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Registradores principais (MPU-6000/MPU-6050 Register Map)</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">REG_SMPLRT_DIV</span><span style="color: #D8DEE9FF">    </span><span style="color: #B48EAD">0x19</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">REG_CONFIG</span><span style="color: #D8DEE9FF">        </span><span style="color: #B48EAD">0x1A</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">REG_GYRO_CONFIG</span><span style="color: #D8DEE9FF">   </span><span style="color: #B48EAD">0x1B</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">REG_ACCEL_CONFIG</span><span style="color: #D8DEE9FF">  </span><span style="color: #B48EAD">0x1C</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">REG_INT_ENABLE</span><span style="color: #D8DEE9FF">    </span><span style="color: #B48EAD">0x38</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">REG_ACCEL_XOUT_H</span><span style="color: #D8DEE9FF">  </span><span style="color: #B48EAD">0x3B</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">REG_PWR_MGMT_1</span><span style="color: #D8DEE9FF">    </span><span style="color: #B48EAD">0x6B</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">REG_WHO_AM_I</span><span style="color: #D8DEE9FF">      </span><span style="color: #B48EAD">0x75</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Bits e campos úteis</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">PWR1_SLEEP_BIT</span><span style="color: #D8DEE9FF">    </span><span style="color: #B48EAD">6</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// FS_SEL (GYRO_CONFIG&#91;4:3&#93;) e AFS_SEL (ACCEL_CONFIG&#91;4:3&#93;)</span></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">enum</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">MPU6050_GYRO_FS_250</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: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ±250 °/s</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">MPU6050_GYRO_FS_500</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: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ±500 °/s</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">MPU6050_GYRO_FS_1000</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ±1000 °/s</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">MPU6050_GYRO_FS_2000</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// ±2000 °/s</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_gyro_fs_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">enum</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">MPU6050_ACCEL_FS_2G</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: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ±2 g</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">MPU6050_ACCEL_FS_4G</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: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ±4 g</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">MPU6050_ACCEL_FS_8G</span><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// ±8 g</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">MPU6050_ACCEL_FS_16G</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// ±16 g</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_accel_fs_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">mpu6050_gyro_fs_t</span><span style="color: #D8DEE9FF">  </span><span style="color: #D8DEE9">gyro_fs</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">mpu6050_accel_fs_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">accel_fs</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// fatores de escala (LSB por unidade)</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">accel_lsb_per_g</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gyro_lsb_per_dps</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_cfg_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ax</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ay</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">az</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gx</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gy</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gz</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">temp_raw</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_raw_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">typedef</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">struct</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// aceleração</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ax_g</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ay_g</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">az_g</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">        </span><span style="color: #616E88">// em g</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ax_ms2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">ay_ms2</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">az_ms2</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// em m/s²</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// rotação</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gx_dps</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gy_dps</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gz_dps</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF">  </span><span style="color: #616E88">// em °/s</span></span>
<span class="line"><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_si_t</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Você implementa essas duas funções na sua plataforma:</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">i2c_write_reg</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr7</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">reg</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">value</span><span style="color: #D8DEE9FF">)</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">i2c_read_regs</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">addr7</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">start_reg</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">buf</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">len</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">accel_lsb_per_g_from_fs</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">mpu6050_accel_fs_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fs</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Do datasheet/register map: sensibilidade depende do AFS_SEL. :contentReference&#91;oaicite:2&#93;{index=2}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">switch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">fs</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_ACCEL_FS_2G</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 16384</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">0</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_ACCEL_FS_4G</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 8192</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">0</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_ACCEL_FS_8G</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 4096</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">0</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_ACCEL_FS_16G</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 2048</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">0</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">default</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 16384</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">0</span><span style="color: #D8DEE9">f</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: #D8DEE9">static</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">gyro_lsb_per_dps_from_fs</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">mpu6050_gyro_fs_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">fs</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Do datasheet/register map: sensibilidade depende do FS_SEL. :contentReference&#91;oaicite:3&#93;{index=3}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">switch</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">fs</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_GYRO_FS_250</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 131</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">0</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_GYRO_FS_500</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF">  </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 65</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">5</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_GYRO_FS_1000</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 32</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">8</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">case</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">MPU6050_GYRO_FS_2000</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 16</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">4</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">default</span><span style="color: #ECEFF4">:</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> 131</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">0</span><span style="color: #D8DEE9">f</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: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mpu6050_init</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_cfg_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">cfg</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 1) Acorda o chip e seleciona clock interno padrão (PWR_MGMT_1).</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// Escrever 0 em PWR_MGMT_1 limpa SLEEP e deixa o clock interno ativo. :contentReference&#91;oaicite:4&#93;{index=4}</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">i2c_write_reg</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MPU6050_I2C_ADDR</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">REG_PWR_MGMT_1</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x00</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">// 2) Configura escalas de acel/gyro nos campos &#91;4:3&#93;</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// ACCEL_CONFIG: AFS_SEL em bits 4:3</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">accel_cfg</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> ((</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">cfg</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">accel_fs</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> 0</span><span style="color: #D8DEE9">x03u</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</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: #81A1C1">!</span><span style="color: #88C0D0">i2c_write_reg</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MPU6050_I2C_ADDR</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">REG_ACCEL_CONFIG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">accel_cfg</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">// GYRO_CONFIG: FS_SEL em bits 4:3</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">gyro_cfg</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> ((</span><span style="color: #D8DEE9">uint8_t</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">cfg</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gyro_fs</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;</span><span style="color: #D8DEE9FF"> 0</span><span style="color: #D8DEE9">x03u</span><span style="color: #D8DEE9FF">) </span><span style="color: #81A1C1">&lt;&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">3</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: #81A1C1">!</span><span style="color: #88C0D0">i2c_write_reg</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MPU6050_I2C_ADDR</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">REG_GYRO_CONFIG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">gyro_cfg</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">// 3) (Opcional, mas recomendado) filtro digital passa-baixa (DLPF) e taxa de amostragem</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// CONFIG: DLPF_CFG em bits &#91;2:0&#93;. Ex.: 3 =&gt; um corte típico para reduzir ruído (ver tabela no register map). :contentReference&#91;oaicite:5&#93;{index=5}</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">i2c_write_reg</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MPU6050_I2C_ADDR</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">REG_CONFIG</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x03</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">// SMPLRT_DIV define taxa efetiva: sample_rate = gyro_output_rate / (1 + SMPLRT_DIV).</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// gyro_output_rate é 8 kHz quando DLPF_CFG=0, senão 1 kHz (ver register map). :contentReference&#91;oaicite:6&#93;{index=6}</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">i2c_write_reg</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MPU6050_I2C_ADDR</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">REG_SMPLRT_DIV</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x04</span><span style="color: #D8DEE9FF">)) </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// exemplo</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// 4) Interrupções ficam para depois (no DMP a gente usa bastante INT + FIFO).</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">i2c_write_reg</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MPU6050_I2C_ADDR</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">REG_INT_ENABLE</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0x00</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: #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>
<span class="line"><span style="color: #D8DEE9">bool</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mpu6050_read_raw</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">mpu6050_raw_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">out</span><span style="color: #D8DEE9FF">) </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">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">14</span><span style="color: #D8DEE9FF">&#93;</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: #81A1C1">!</span><span style="color: #88C0D0">i2c_read_regs</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">MPU6050_I2C_ADDR</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">REG_ACCEL_XOUT_H</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">buf</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">14</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">// Cada eixo é big-endian: High, Low</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ax</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF">)((</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">0</span><span style="color: #D8DEE9FF">&#93; </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">buf</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>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ay</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF">)((</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">2</span><span style="color: #D8DEE9FF">&#93; </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">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">3</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">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">az</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF">)((</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">4</span><span style="color: #D8DEE9FF">&#93; </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">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">5</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">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">temp_raw</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF">)((</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">6</span><span style="color: #D8DEE9FF">&#93; </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">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">7</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">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gx</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF">)((</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">8</span><span style="color: #D8DEE9FF">&#93;  </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">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">9</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">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gy</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF">)((</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">10</span><span style="color: #D8DEE9FF">&#93; </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">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">11</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">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gz</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF">)((</span><span style="color: #D8DEE9">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">12</span><span style="color: #D8DEE9FF">&#93; </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">buf</span><span style="color: #D8DEE9FF">&#91;</span><span style="color: #B48EAD">13</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>
<span class="line"><span style="color: #81A1C1">void</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">mpu6050_convert_to_si</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_cfg_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">cfg</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_raw_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">raw</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">mpu6050_si_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">out</span><span style="color: #D8DEE9FF">) </span><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">float</span><span style="color: #D8DEE9FF"> lsb_per_g   </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">accel_lsb_per_g_from_fs</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">cfg</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">accel_fs</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</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">float</span><span style="color: #D8DEE9FF"> lsb_per_dps </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">gyro_lsb_per_dps_from_fs</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">cfg</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gyro_fs</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">// aceleração em g</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ax_g</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">raw</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ax</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">lsb_per_g</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ay_g</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">raw</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ay</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">lsb_per_g</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">az_g</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">raw</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">az</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">lsb_per_g</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// g -&gt; m/s² (g padrão ~ 9.80665)</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">float</span><span style="color: #D8DEE9FF"> g0 </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> 9</span><span style="color: #ECEFF4">.</span><span style="color: #D8DEE9FF">80665</span><span style="color: #D8DEE9">f</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ax_ms2</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ax_g</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">g0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ay_ms2</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">ay_g</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">g0</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">az_ms2</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">az_g</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">g0</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// giro em °/s</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gx_dps</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">raw</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gx</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">lsb_per_dps</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gy_dps</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">raw</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gy</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">lsb_per_dps</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">out</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gz_dps</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> (</span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF">)</span><span style="color: #D8DEE9">raw</span><span style="color: #81A1C1">-&gt;</span><span style="color: #D8DEE9">gz</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">lsb_per_dps</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">O que esse código está fazendo (de verdade)</h3>



<p class="wp-block-paragraph">A inicialização começa acordando o sensor em <code>PWR_MGMT_1</code>. Se o bit <strong>SLEEP</strong> estiver ativo, o MPU não mede nada; então zerar esse registrador é o jeito mais direto de sair do modo sleep. O mapa de registradores descreve esse registrador e os campos de escala do acelerômetro e giroscópio que usamos em seguida. (<a href="https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf?utm_source=chatgpt.com">TDK InvenSense</a>)</p>



<p class="wp-block-paragraph">Logo depois, nós configuramos os ranges. Isso é crucial porque a conversão de “número cru” para unidade física depende diretamente disso. Quando você seleciona, por exemplo, <strong>±2 g</strong>, o datasheet/regmap define o fator típico <strong>16384 LSB/g</strong>; se trocar para <strong>±8 g</strong>, vira <strong>4096 LSB/g</strong>. O mesmo vale para o giroscópio: em <strong>±250 °/s</strong> é comum usar <strong>131 LSB/(°/s)</strong>, e em <strong>±2000 °/s</strong> cai para <strong>16.4 LSB/(°/s)</strong>. Essas relações são as que tornam a conversão objetiva e auditável. (<a href="https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf?utm_source=chatgpt.com">TDK InvenSense</a>)</p>



<p class="wp-block-paragraph">A leitura em <code>ACCEL_XOUT_H</code> pega um “bloco coeso” de 14 bytes, o que reduz risco de você ler um eixo “antes” e outro “depois” de uma atualização interna. Esse detalhe parece pequeno, mas evita inconsistências sutis quando você começa a amostrar rápido. A ordem dos registradores nesse bloco (accel, temp, gyro) também está definida no register map. (<a href="https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf?utm_source=chatgpt.com">TDK InvenSense</a>)</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img decoding="async" width="860" height="445" src="https://mcu.tec.br/wp-content/uploads/2026/02/image-45.png" alt="" class="wp-image-1363" srcset="https://mcu.tec.br/wp-content/uploads/2026/02/image-45.png 860w, https://mcu.tec.br/wp-content/uploads/2026/02/image-45-300x155.png 300w, https://mcu.tec.br/wp-content/uploads/2026/02/image-45-768x397.png 768w" sizes="(max-width: 860px) 100vw, 860px" /></figure>
</div>


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



<h3 class="wp-block-heading">Observação importante de bancada (qualidade de módulos no mercado)</h3>



<p class="wp-block-paragraph">Existe muita placa “MPU6050” no mercado com variação de qualidade (inclusive peças suspeitas/fora de especificação), o que aparece na prática como offsets absurdos, ruído fora do padrão ou instabilidade. Se seu baseline “cru” já estiver muito estranho, vale desconfiar do módulo antes de culpar o algoritmo. (<a href="https://forum.arduino.cc/t/my-mpu-6050-is-not-connecting/871276?utm_source=chatgpt.com">Arduino Forum</a>)</p><p>The post <a href="https://mcu.tec.br/sensores/mpu6050-em-projetos-reais-do-dado-cru-ao-angulo-e-preparando-terreno-para-o-dmp/">MPU6050 em projetos reais: do “dado cru” ao ângulo (e preparando terreno para o DMP)</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1359</post-id>	</item>
		<item>
		<title>MAX6816: Como Eliminar Bounce de Chaves Mecânicas com Solução Profissional de Debounce</title>
		<link>https://mcu.tec.br/sensores/max6816-como-eliminar-bounce-de-chaves-mecanicas-com-solucao-profissional-de-debounce/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=max6816-como-eliminar-bounce-de-chaves-mecanicas-com-solucao-profissional-de-debounce</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Mon, 16 Feb 2026 13:46:50 +0000</pubDate>
				<category><![CDATA[Sensores]]></category>
		<category><![CDATA[bounce em botão]]></category>
		<category><![CDATA[circuito anti-bounce]]></category>
		<category><![CDATA[debounce]]></category>
		<category><![CDATA[debounce hardware]]></category>
		<category><![CDATA[eletrônica embarcada]]></category>
		<category><![CDATA[entradas digitais]]></category>
		<category><![CDATA[filtro de chave mecânica]]></category>
		<category><![CDATA[filtro RC]]></category>
		<category><![CDATA[imunidade a ruído]]></category>
		<category><![CDATA[MAX6816]]></category>
		<category><![CDATA[microcontroladores]]></category>
		<category><![CDATA[Schmitt Trigger]]></category>
		<category><![CDATA[sistemas industriais]]></category>
		<category><![CDATA[tratamento de sinal digital]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=1389</guid>

					<description><![CDATA[<p>O MAX6816 é um circuito integrado dedicado ao tratamento de bounce em chaves mecânicas, oferecendo uma solução profissional, robusta e determinística para sistemas embarcados. Neste artigo explicamos o que é debounce, os riscos de não tratar o sinal de botões e contatos, as limitações das soluções com resistores e capacitores e como o MAX6816 garante imunidade a ruído, temporização controlada e saídas digitais limpas para microcontroladores em aplicações industriais, automotivas e IoT.</p>
<p>The post <a href="https://mcu.tec.br/sensores/max6816-como-eliminar-bounce-de-chaves-mecanicas-com-solucao-profissional-de-debounce/">MAX6816: Como Eliminar Bounce de Chaves Mecânicas com Solução Profissional de Debounce</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">O Problema do <em>Debounce</em> em Chaves Mecânicas</h2>


<div class="root-eb-toc-vwwbp wp-block-essential-blocks-table-of-contents"><div class="eb-parent-wrapper eb-parent-eb-toc-vwwbp "><div class="eb-toc-container eb-toc-vwwbp  eb-toc-is-not-sticky eb-toc-not-collapsible eb-toc-initially-not-collapsed eb-toc-scrollToTop style-1 list-style-none" data-scroll-top="false" data-scroll-top-icon="fas fa-angle-up" data-collapsible="false" data-sticky-hide-mobile="false" data-sticky="false" data-scroll-target="scroll_to_toc" data-copy-link="false" data-editor-type="" data-hide-desktop="false" data-hide-tab="false" data-hide-mobile="false" data-itemcollapsed="false" data-highlight-scroll="false"><div class="eb-toc-header"><h2 class="eb-toc-title">Table of Contents</h2></div><div class="eb-toc-wrapper " data-headers="[{&quot;level&quot;:2,&quot;content&quot;:&quot;O Problema do Debounce em Chaves Mec\u00e2nicas&quot;,&quot;text&quot;:&quot;O Problema do Debounce em Chaves Mec\u00e2nicas&quot;,&quot;link&quot;:&quot;eb-table-content-0&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;T\u00e9cnicas Cl\u00e1ssicas de Debounce e suas Limita\u00e7\u00f5es&quot;,&quot;text&quot;:&quot;T\u00e9cnicas Cl\u00e1ssicas de Debounce e suas Limita\u00e7\u00f5es&quot;,&quot;link&quot;:&quot;eb-table-content-1&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;O MAX6816 como Solu\u00e7\u00e3o Profissional para Debounce&quot;,&quot;text&quot;:&quot;O MAX6816 como Solu\u00e7\u00e3o Profissional para Debounce&quot;,&quot;link&quot;:&quot;eb-table-content-2&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Funcionamento Interno, Temporiza\u00e7\u00e3o e Integra\u00e7\u00e3o com Microcontroladores&quot;,&quot;text&quot;:&quot;Funcionamento Interno, Temporiza\u00e7\u00e3o e Integra\u00e7\u00e3o com Microcontroladores&quot;,&quot;link&quot;:&quot;eb-table-content-3&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Refer\u00eancias:&quot;,&quot;text&quot;:&quot;Refer\u00eancias:&quot;,&quot;link&quot;:&quot;eb-table-content-4&quot;}]" data-visible="[true,true,true,true,true,true]" data-delete-headers="[{&quot;label&quot;:&quot;O Problema do Debounce em Chaves Mec\u00e2nicas&quot;,&quot;value&quot;:&quot;o-problema-do-debounce-em-chaves-mec\u00e2nicas&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;T\u00e9cnicas Cl\u00e1ssicas de Debounce e suas Limita\u00e7\u00f5es&quot;,&quot;value&quot;:&quot;t\u00e9cnicas-cl\u00e1ssicas-de-debounce-e-suas-limita\u00e7\u00f5es&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;O MAX6816 como Solu\u00e7\u00e3o Profissional para Debounce&quot;,&quot;value&quot;:&quot;o-max6816-como-solu\u00e7\u00e3o-profissional-para-debounce&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Funcionamento Interno, Temporiza\u00e7\u00e3o e Integra\u00e7\u00e3o com Microcontroladores&quot;,&quot;value&quot;:&quot;funcionamento-interno-temporiza\u00e7\u00e3o-e-integra\u00e7\u00e3o-com-microcontroladores&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Refer\u00eancias:&quot;,&quot;value&quot;:&quot;refer\u00eancias&quot;,&quot;isDelete&quot;:false}]" data-smooth="true" data-top-offset=""><div class="eb-toc__list-wrap"><ul class="eb-toc__list"><li><a href="#eb-table-content-0">O Problema do Debounce em Chaves Mecânicas</a><li><a href="#eb-table-content-1">Técnicas Clássicas de Debounce e suas Limitações</a><li><a href="#eb-table-content-2">O MAX6816 como Solução Profissional para Debounce</a><li><a href="#eb-table-content-3">Funcionamento Interno, Temporização e Integração com Microcontroladores</a><li><a href="#eb-table-content-4">Referências:</a></ul></div></div></div></div></div>


<p class="wp-block-paragraph">Em praticamente todo sistema embarcado existe algum tipo de entrada digital proveniente de uma ação humana: um botão, uma chave seletora, um micro-switch, um contato de relé ou até mesmo sensores de fim de curso. À primeira vista, parece trivial: o usuário pressiona o botão, o nível lógico muda de 0 para 1 (ou vice-versa), e o firmware reage. No entanto, do ponto de vista físico e elétrico, o comportamento real é muito mais complexo. É nesse contexto que surge o fenômeno conhecido como <em>debounce</em>.</p>



<p class="wp-block-paragraph">Quando dois contatos metálicos se encostam mecanicamente, eles não estabelecem uma conexão limpa e instantânea. O que ocorre, na prática, é uma sequência rápida de microcolisões antes que o contato se estabilize. Esse comportamento é resultado da elasticidade do material, da vibração mecânica e da geometria dos contatos. Em termos elétricos, isso significa que, ao pressionar um botão, o sinal digital pode oscilar diversas vezes entre nível alto e baixo em poucos milissegundos. Em vez de uma única transição lógica, o microcontrolador pode “enxergar” múltiplas bordas.</p>



<p class="wp-block-paragraph">As consequências de não tratar o <em>debounce</em> são relevantes e, em muitos casos, críticas. Um simples botão pode ser interpretado como múltiplos pressionamentos, gerando erros de contagem, falhas de navegação em menus, disparos repetidos de comandos ou até mesmo comportamentos perigosos em sistemas industriais. Em aplicações de potência, por exemplo, uma entrada mal tratada pode ligar e desligar um estágio várias vezes em milissegundos, gerando estresse elétrico e térmico. Em sistemas de controle embarcado com interrupções externas, o problema pode se agravar ainda mais, causando sobrecarga de processamento e comportamento imprevisível.</p>


<div class="wp-block-image">
<figure class="alignright size-full is-resized"><img decoding="async" width="685" height="433" src="https://mcu.tec.br/wp-content/uploads/2026/02/image-54.png" alt="" class="wp-image-1390" style="width:501px;height:auto" srcset="https://mcu.tec.br/wp-content/uploads/2026/02/image-54.png 685w, https://mcu.tec.br/wp-content/uploads/2026/02/image-54-300x190.png 300w" sizes="(max-width: 685px) 100vw, 685px" /></figure>
</div>


<p class="wp-block-paragraph">Do ponto de vista de firmware, muitos desenvolvedores iniciantes tentam resolver o problema com atrasos fixos (<em>delays</em>) após a detecção de uma borda. Embora funcione em aplicações simples, essa abordagem bloqueia o processador e não é escalável em sistemas com múltiplas tarefas, especialmente quando se utiliza um sistema operacional de tempo real como o FreeRTOS. Além disso, <em>delays</em> arbitrários não garantem imunidade a ruídos eletromagnéticos ou a interferências externas no barramento.</p>



<p class="wp-block-paragraph">Portanto, o tratamento adequado do sinal de chaves mecânicas não é apenas uma questão de conveniência, mas de robustez de projeto. Um sistema profissional deve considerar tanto o comportamento mecânico do contato quanto a integridade elétrica do sinal digital entregue ao microcontrolador.</p><p>The post <a href="https://mcu.tec.br/sensores/max6816-como-eliminar-bounce-de-chaves-mecanicas-com-solucao-profissional-de-debounce/">MAX6816: Como Eliminar Bounce de Chaves Mecânicas com Solução Profissional de Debounce</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1389</post-id>	</item>
		<item>
		<title>Espectros Eletromagnéticos na Engenharia: UV, Visível, NIR e SWIR e Onde Usá-los</title>
		<link>https://mcu.tec.br/sensores/espectros-eletromagneticos-na-engenharia-uv-visivel-nir-e-swir-e-onde-usa-los/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=espectros-eletromagneticos-na-engenharia-uv-visivel-nir-e-swir-e-onde-usa-los</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Fri, 30 Jan 2026 13:28:21 +0000</pubDate>
				<category><![CDATA[Sensores]]></category>
		<category><![CDATA[agricultura de precisão]]></category>
		<category><![CDATA[câmeras multiespectrais]]></category>
		<category><![CDATA[edge computing]]></category>
		<category><![CDATA[engenharia eletrônica]]></category>
		<category><![CDATA[espectro eletromagnético]]></category>
		<category><![CDATA[espectro ultravioleta UV]]></category>
		<category><![CDATA[espectro visível]]></category>
		<category><![CDATA[identificação de materiais]]></category>
		<category><![CDATA[imageamento multiespectral]]></category>
		<category><![CDATA[infravermelho de onda curta SWIR]]></category>
		<category><![CDATA[infravermelho próximo NIR]]></category>
		<category><![CDATA[inspeção industrial]]></category>
		<category><![CDATA[iot industrial]]></category>
		<category><![CDATA[processamento de sinais]]></category>
		<category><![CDATA[sensores ópticos]]></category>
		<category><![CDATA[sensoriamento óptico]]></category>
		<category><![CDATA[sistemas embarcados]]></category>
		<category><![CDATA[visão computacional]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=1240</guid>

					<description><![CDATA[<p>Entenda o que são os espectros eletromagnéticos e como eles são aplicados na engenharia moderna. Este artigo apresenta, de forma técnica e didática, as principais faixas espectrais utilizadas em sistemas embarcados, visão computacional, IoT e inspeção industrial, incluindo ultravioleta (UV), espectro visível, infravermelho próximo (NIR) e infravermelho de onda curta (SWIR). O texto explica os fundamentos físicos de cada espectro, suas interações com os materiais, limitações técnicas, tipos de sensores envolvidos e critérios práticos de escolha para projetos reais. Também são discutidas combinações espectrais, impactos no processamento de sinais e na inteligência artificial embarcada, além de diretrizes de engenharia que ajudam a decidir qual espectro utilizar em aplicações como agricultura de precisão, inspeção industrial, robótica, monitoramento ambiental e identificação de materiais. Um guia essencial para engenheiros, desenvolvedores e pesquisadores que desejam projetar sistemas mais eficientes, robustos e fisicamente fundamentados.</p>
<p>The post <a href="https://mcu.tec.br/sensores/espectros-eletromagneticos-na-engenharia-uv-visivel-nir-e-swir-e-onde-usa-los/">Espectros Eletromagnéticos na Engenharia: UV, Visível, NIR e SWIR e Onde Usá-los</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<div class="root-eb-toc-hd1kz wp-block-essential-blocks-table-of-contents"><div class="eb-parent-wrapper eb-parent-eb-toc-hd1kz "><div class="eb-toc-container eb-toc-hd1kz  eb-toc-is-not-sticky eb-toc-not-collapsible eb-toc-initially-not-collapsed eb-toc-scrollToTop style-1 list-style-none" data-scroll-top="false" data-scroll-top-icon="fas fa-angle-up" data-collapsible="false" data-sticky-hide-mobile="false" data-sticky="false" data-scroll-target="scroll_to_toc" data-copy-link="false" data-editor-type="" data-hide-desktop="false" data-hide-tab="false" data-hide-mobile="false" data-itemcollapsed="false" data-highlight-scroll="false"><div class="eb-toc-header"><h2 class="eb-toc-title">Table of Contents</h2></div><div class="eb-toc-wrapper " data-headers="[{&quot;level&quot;:2,&quot;content&quot;:&quot;1 \u2014 Espectro Ultravioleta (UV): fundamentos f\u00edsicos e aplica\u00e7\u00f5es&quot;,&quot;text&quot;:&quot;1 \u2014 Espectro Ultravioleta (UV): fundamentos f\u00edsicos e aplica\u00e7\u00f5es&quot;,&quot;link&quot;:&quot;eb-table-content-0&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;2 \u2014 Espectro Vis\u00edvel: percep\u00e7\u00e3o humana, limites f\u00edsicos e aplica\u00e7\u00f5es&quot;,&quot;text&quot;:&quot;2 \u2014 Espectro Vis\u00edvel: percep\u00e7\u00e3o humana, limites f\u00edsicos e aplica\u00e7\u00f5es&quot;,&quot;link&quot;:&quot;eb-table-content-1&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;3 \u2014 NIR (Infravermelho Pr\u00f3ximo): propriedades f\u00edsicas e aplica\u00e7\u00f5es estrat\u00e9gicas&quot;,&quot;text&quot;:&quot;3 \u2014 NIR (Infravermelho Pr\u00f3ximo): propriedades f\u00edsicas e aplica\u00e7\u00f5es estrat\u00e9gicas&quot;,&quot;link&quot;:&quot;eb-table-content-2&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;4 \u2014 SWIR (Infravermelho de Onda Curta): identifica\u00e7\u00e3o de materiais e composi\u00e7\u00e3o qu\u00edmica&quot;,&quot;text&quot;:&quot;4 \u2014 SWIR (Infravermelho de Onda Curta): identifica\u00e7\u00e3o de materiais e composi\u00e7\u00e3o qu\u00edmica&quot;,&quot;link&quot;:&quot;eb-table-content-3&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;5 \u2014 Combina\u00e7\u00f5es espectrais e crit\u00e9rios de escolha em projetos reais&quot;,&quot;text&quot;:&quot;5 \u2014 Combina\u00e7\u00f5es espectrais e crit\u00e9rios de escolha em projetos reais&quot;,&quot;link&quot;:&quot;eb-table-content-4&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;6 \u2014 Diretrizes pr\u00e1ticas para escolha do espectro em sistemas embarcados, IoT e vis\u00e3o computacional&quot;,&quot;text&quot;:&quot;6 \u2014 Diretrizes pr\u00e1ticas para escolha do espectro em sistemas embarcados, IoT e vis\u00e3o computacional&quot;,&quot;link&quot;:&quot;eb-table-content-5&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;7 \u2014 Impactos da escolha espectral em algoritmos, IA embarcada e processamento de sinais&quot;,&quot;text&quot;:&quot;7 \u2014 Impactos da escolha espectral em algoritmos, IA embarcada e processamento de sinais&quot;,&quot;link&quot;:&quot;7-impactos-da-escolha-espectral-em-algoritmos-ia-embarcada-e-processamento-de-sinais&quot;},{&quot;level&quot;:2,&quot;content&quot;:&quot;Conclus\u00e3o \u2014 Espectros como decis\u00e3o de engenharia, n\u00e3o como detalhe \u00f3ptico&quot;,&quot;text&quot;:&quot;Conclus\u00e3o \u2014 Espectros como decis\u00e3o de engenharia, n\u00e3o como detalhe \u00f3ptico&quot;,&quot;link&quot;:&quot;eb-table-content-7&quot;}]" data-visible="[true,true,true,true,true,true]" data-delete-headers="[{&quot;label&quot;:&quot;1 \u2014 Espectro Ultravioleta (UV): fundamentos f\u00edsicos e aplica\u00e7\u00f5es&quot;,&quot;value&quot;:&quot;1-espectro-ultravioleta-uv-fundamentos-f\u00edsicos-e-aplica\u00e7\u00f5es&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;2 \u2014 Espectro Vis\u00edvel: percep\u00e7\u00e3o humana, limites f\u00edsicos e aplica\u00e7\u00f5es&quot;,&quot;value&quot;:&quot;2-espectro-vis\u00edvel-percep\u00e7\u00e3o-humana-limites-f\u00edsicos-e-aplica\u00e7\u00f5es&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;3 \u2014 NIR (Infravermelho Pr\u00f3ximo): propriedades f\u00edsicas e aplica\u00e7\u00f5es estrat\u00e9gicas&quot;,&quot;value&quot;:&quot;3-nir-infravermelho-pr\u00f3ximo-propriedades-f\u00edsicas-e-aplica\u00e7\u00f5es-estrat\u00e9gicas&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;4 \u2014 SWIR (Infravermelho de Onda Curta): identifica\u00e7\u00e3o de materiais e composi\u00e7\u00e3o qu\u00edmica&quot;,&quot;value&quot;:&quot;4-swir-infravermelho-de-onda-curta-identifica\u00e7\u00e3o-de-materiais-e-composi\u00e7\u00e3o-qu\u00edmica&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;5 \u2014 Combina\u00e7\u00f5es espectrais e crit\u00e9rios de escolha em projetos reais&quot;,&quot;value&quot;:&quot;5-combina\u00e7\u00f5es-espectrais-e-crit\u00e9rios-de-escolha-em-projetos-reais&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;6 \u2014 Diretrizes pr\u00e1ticas para escolha do espectro em sistemas embarcados, IoT e vis\u00e3o computacional&quot;,&quot;value&quot;:&quot;6-diretrizes-pr\u00e1ticas-para-escolha-do-espectro-em-sistemas-embarcados-iot-e-vis\u00e3o-computacional&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;7 \u2014 Impactos da escolha espectral em algoritmos, IA embarcada e processamento de sinais&quot;,&quot;value&quot;:&quot;7-impactos-da-escolha-espectral-em-algoritmos-ia-embarcada-e-processamento-de-sinais&quot;,&quot;isDelete&quot;:false},{&quot;label&quot;:&quot;Conclus\u00e3o \u2014 Espectros como decis\u00e3o de engenharia, n\u00e3o como detalhe \u00f3ptico&quot;,&quot;value&quot;:&quot;conclus\u00e3o-espectros-como-decis\u00e3o-de-engenharia-n\u00e3o-como-detalhe-\u00f3ptico&quot;,&quot;isDelete&quot;:false}]" data-smooth="true" data-top-offset=""><div class="eb-toc__list-wrap"><ul class="eb-toc__list"><li><a href="#eb-table-content-0">1 — Espectro Ultravioleta (UV): fundamentos físicos e aplicações</a><li><a href="#eb-table-content-1">2 — Espectro Visível: percepção humana, limites físicos e aplicações</a><li><a href="#eb-table-content-2">3 — NIR (Infravermelho Próximo): propriedades físicas e aplicações estratégicas</a><li><a href="#eb-table-content-3">4 — SWIR (Infravermelho de Onda Curta): identificação de materiais e composição química</a><li><a href="#eb-table-content-4">5 — Combinações espectrais e critérios de escolha em projetos reais</a><li><a href="#eb-table-content-5">6 — Diretrizes práticas para escolha do espectro em sistemas embarcados, IoT e visão computacional</a><li><a href="#7-impactos-da-escolha-espectral-em-algoritmos-ia-embarcada-e-processamento-de-sinais">7 — Impactos da escolha espectral em algoritmos, IA embarcada e processamento de sinais</a><li><a href="#eb-table-content-7">Conclusão — Espectros como decisão de engenharia, não como detalhe óptico</a></ul></div></div></div></div></div>


<p class="wp-block-paragraph">O que são espectros e por que eles importam</p>



<p class="wp-block-paragraph">Quando falamos em <strong>espectros</strong>, estamos nos referindo às diferentes <strong>faixas do espectro eletromagnético</strong>, organizadas de acordo com o comprimento de onda (λ) ou frequência da radiação. Embora o ser humano esteja limitado à percepção do <strong>espectro visível</strong>, a física nos mostra que a luz é apenas uma pequena janela de um universo muito mais amplo de interações eletromagnéticas. Cada uma dessas faixas carrega informações físicas distintas sobre os materiais, o ambiente e os fenômenos observados.</p>



<p class="wp-block-paragraph">Do ponto de vista de engenharia — especialmente em <strong>sistemas embarcados, sensoriamento, visão computacional, IoT e instrumentação</strong> — compreender os espectros não é um luxo acadêmico, mas uma <strong>decisão de projeto</strong>. A escolha entre UV, Visível, NIR ou SWIR define diretamente o tipo de sensor, a óptica, o custo do sistema, o consumo energético e, principalmente, <strong>qual fenômeno físico será detectado</strong>. Em muitos casos, mudar a faixa espectral é mais eficiente do que aplicar algoritmos complexos sobre dados inadequados.</p>



<p class="wp-block-paragraph">Este artigo tem como objetivo apresentar, de forma <strong>didática e técnica</strong>, o que são os principais espectros usados em aplicações modernas — <strong>UV, Visível, NIR e SWIR</strong>, além de suas combinações — explicando <strong>onde e por que cada um deve ser utilizado</strong>. A proposta não é apenas descrever faixas de comprimento de onda, mas conectar cada espectro às <strong>aplicações reais</strong>, aos <strong>sensores disponíveis</strong> e às <strong>decisões de arquitetura</strong> em sistemas embarcados e industriais.</p><p>The post <a href="https://mcu.tec.br/sensores/espectros-eletromagneticos-na-engenharia-uv-visivel-nir-e-swir-e-onde-usa-los/">Espectros Eletromagnéticos na Engenharia: UV, Visível, NIR e SWIR e Onde Usá-los</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1240</post-id>	</item>
		<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 loading="lazy" 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 loading="lazy" 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 loading="lazy" 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>O Futuro das Câmeras de Alta Velocidade: Sensores, IA e Novas Fronteiras da Captura Ultrarrápida</title>
		<link>https://mcu.tec.br/sensores/o-futuro-das-cameras-de-alta-velocidade-sensores-ia-e-novas-fronteiras-da-captura-ultrarrapida/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=o-futuro-das-cameras-de-alta-velocidade-sensores-ia-e-novas-fronteiras-da-captura-ultrarrapida</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Wed, 19 Nov 2025 13:27:13 +0000</pubDate>
				<category><![CDATA[Sensores]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=849</guid>

					<description><![CDATA[<p>As câmeras de alta velocidade estão evoluindo rapidamente graças a avanços em sensores, ótica, inteligência artificial e fotografia computacional. Este artigo explora como a expansão para espectros como UV, SWIR e térmico, a redução do tempo morto entre quadros, a gestão inteligente de grandes volumes de dados e o uso de IA embarcada estão redefinindo o que é possível observar em fenômenos ultrarrápidos. Também discutimos desafios como sensibilidade, resolução, sincronização e ruggedização, mostrando como essas tecnologias estão transformando aplicações científicas, industriais e aeroespaciais. Ideal para quem deseja entender o futuro da captura de eventos em microssegundos.</p>
<p>The post <a href="https://mcu.tec.br/sensores/o-futuro-das-cameras-de-alta-velocidade-sensores-ia-e-novas-fronteiras-da-captura-ultrarrapida/">O Futuro das Câmeras de Alta Velocidade: Sensores, IA e Novas Fronteiras da Captura Ultrarrápida</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 às Câmeras de Alta Velocidade</strong></h2>



<p class="wp-block-paragraph">As câmeras de alta velocidade, antes restritas a laboratórios especializados, tornaram-se ferramentas centrais em pesquisa, indústria, defesa e desenvolvimento tecnológico. Esses equipamentos são capazes de registrar fenômenos extremamente rápidos — desde explosões microscópicas até movimentos biomecânicos complexos — operando com milhares ou até milhões de quadros por segundo (fps, <em>frames per second</em>). Esta capacidade ampliou de forma significativa a compreensão de eventos que ocorrem em escalas de tempo que o olho humano jamais conseguiria perceber.</p>



<p class="wp-block-paragraph">O avanço contínuo da eletrônica, da óptica e dos métodos computacionais levou essas câmeras para patamares ainda mais sofisticados. Hoje, elas não apenas capturam imagens ultrarrápidas, mas também incorporam inteligência embarcada, sensores especializados, técnicas avançadas de processamento e ferramentas de análise automática. Cada novo avanço, no entanto, traz seus próprios desafios, seja em custo, sensibilidade, robustez ou gestão de dados.</p>



<p class="wp-block-paragraph">Nesta série de seções, vamos explorar as principais tendências que moldam o futuro da captura de alta velocidade — expandindo espectros além do visível, reduzindo o tempo morto entre frames, integrando inteligência artificial, melhorando sensibilidade, e enfrentando os desafios associados ao volume de dados e às limitações físicas dos sensores.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="576" src="https://mcu.tec.br/wp-content/uploads/2025/11/image-1-1024x576.png" alt="" class="wp-image-851" srcset="https://mcu.tec.br/wp-content/uploads/2025/11/image-1-1024x576.png 1024w, https://mcu.tec.br/wp-content/uploads/2025/11/image-1-300x169.png 300w, https://mcu.tec.br/wp-content/uploads/2025/11/image-1-768x432.png 768w, https://mcu.tec.br/wp-content/uploads/2025/11/image-1-1536x864.png 1536w, https://mcu.tec.br/wp-content/uploads/2025/11/image-1.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<h2 class="wp-block-heading">Expansão para Além do Espectro Visível</h2>



<p class="wp-block-paragraph">Uma das transformações mais marcantes no campo das câmeras de alta velocidade é a expansão para faixas espectrais que vão além da luz visível. Durante décadas, os sistemas tradicionais registravam apenas aquilo que o olho humano poderia enxergar. Porém, a necessidade de estudar fenômenos físicos, químicos e biológicos invisíveis ao espectro comum levou ao desenvolvimento de sensores especializados para <strong>UV (ultravioleta)</strong>, <strong>SWIR (infravermelho de onda curta)</strong> e <strong>imagens térmicas</strong>.</p>



<p class="wp-block-paragraph">A captura em UV permite observar reações químicas, luminescência de materiais e eventos que emitem radiação acima do violeta — fenômenos cuja dinâmica é extremamente rápida e antes inacessível em detalhes temporais tão precisos. Já o SWIR facilita a investigação de processos de penetração de luz em materiais, detecção de compostos específicos e análise de fluidos que possuem assinatura óptica característica nessa faixa. A imagem térmica, por sua vez, tornou-se vital em aplicações que exigem medir temperatura e dissipação térmica com precisão de microssegundos, como testes de motores, eletrônica de potência e inspeção industrial.</p>



<p class="wp-block-paragraph">Essa ampliação do espectro exige <strong>ópticas especiais</strong>, materiais sensíveis a comprimentos de onda não visíveis e sensores que, muitas vezes, são mais complexos e mais caros. Além disso, sistemas UV, SWIR e térmicos tendem a ser mais suscetíveis a ruídos ambientais — desde temperatura até radiação externa — o que aumenta a demanda por calibração precisa e controles ambientais rigorosos. Segundo o <em>Office of Science</em> do Departamento de Energia dos EUA, técnicas multispectrais de alta velocidade têm sido fundamentais em pesquisas com plasma e ciência de materiais, demonstrando tanto o potencial quanto a complexidade dessa expansão.</p>



<h2 class="wp-block-heading"><strong>Redução do Dead Time (Tempo Morto Entre Quadros)</strong></h2>



<p class="wp-block-paragraph">Outro avanço decisivo no campo das câmeras de alta velocidade é a redução do <em>dead time</em>, também chamado de intervalo entre quadros (<em>interframe interval</em>). Esse intervalo representa o período em que o sensor não está capturando imagem porque está ocupado realizando a leitura dos dados anteriores. Em aplicações comuns isso passa despercebido, mas em experimentos ultrarrápidos — como combustão, colisões, dinâmica de fluidos ou biomecânica — até alguns microssegundos sem registro podem significar perda de eventos críticos.</p>



<p class="wp-block-paragraph">Para superar esse problema, novos métodos de captura vêm sendo desenvolvidos, incluindo <strong>global shutters mais rápidos</strong>, <strong>exposições sobrepostas</strong> e <strong>modos de captura dupla (double-shutter)</strong>. O objetivo é permitir que o sensor comece a registrar o próximo quadro ao mesmo tempo em que lê o anterior, minimizando lacunas. Quanto menor o <em>dead time</em>, maior a fidelidade temporal do fenômeno capturado.</p>



<p class="wp-block-paragraph">Isso é particularmente importante em situações onde os eventos não são repetitivos. Em testes de explosão, plasma, arcos elétricos ou falhas mecânicas, o fenômeno ocorre uma única vez e não pode ser replicado. Assim, perder alguns microssegundos significa perder dados irrecuperáveis. Segundo o NIST (National Institute of Standards and Technology), otimizar a arquitetura de leitura, o obturador e os sistemas internos de temporização é fundamental para medições precisas em ambientes experimentais e industriais.</p>



<h2 class="wp-block-heading"><strong>Gestão de Massivos Volumes de Dados</strong></h2>



<p class="wp-block-paragraph">À medida que as câmeras de alta velocidade alcançam taxas de quadros mais altas e resoluções cada vez maiores, surge um dos desafios mais intensos desse campo: <strong>a explosão no volume de dados</strong>. Em muitos sistemas modernos, alguns segundos de captura podem gerar terabytes de informação, criando gargalos sérios de transferência, armazenamento e processamento.</p>



<p class="wp-block-paragraph">Esse volume cresce porque cada quadro adicional — especialmente em alta resolução — deve ser transferido do sensor para a memória com extrema rapidez. Além disso, quanto maior a profundidade de bits (por exemplo, 12 ou 14 bits por pixel para permitir análises científicas), maior se torna o tamanho de cada imagem. O resultado é um fluxo de dados que exige hardware especializado, circuitos de alta largura de banda e arquiteturas de memória otimizadas.</p>



<p class="wp-block-paragraph">Para lidar com esse cenário, as fabricantes vêm incorporando técnicas inteligentes, como:</p>



<ul class="wp-block-list">
<li><strong>ROI (Region of Interest)</strong>: permite capturar apenas a área relevante da imagem, reduzindo drasticamente o volume de dados.</li>



<li><strong>Smart Triggering</strong>: captura somente quando um evento específico ocorre, economizando armazenamento e evitando gravação redundante.</li>



<li><strong>Processamento no sensor (On-sensor processing)</strong>: pequenos algoritmos executados diretamente no chip filtram, comprimem ou pré-analisam a imagem antes mesmo de ela chegar ao processador principal.</li>
</ul>



<p class="wp-block-paragraph">Essas abordagens melhoram não apenas o fluxo de dados, mas também a capacidade de resposta em tempo real. Pesquisadores do MIT demonstraram que estratégias de captura inteligente reduzem custos computacionais e aumentam a precisão de análises instantâneas, permitindo decisões mais rápidas em experimentos científicos e linhas industriais automatizadas.</p>



<h2 class="wp-block-heading"><strong>Integração com IA, Aprendizado de Máquina e Fotografia Computacional</strong></h2>



<p class="wp-block-paragraph">A integração entre câmeras de alta velocidade, inteligência artificial (IA), aprendizado de máquina (ML) e técnicas de fotografia computacional representa um dos avanços mais impactantes do setor nos últimos anos. Diferentemente das câmeras tradicionais, que apenas registram imagens, os sistemas modernos começam a <strong>interpretar</strong> o que está sendo capturado, transformando dados brutos em informação útil quase instantaneamente.</p>



<p class="wp-block-paragraph">Antes mesmo da captura, a IA pode atuar como um gatilho inteligente, identificando padrões, movimentos ou comportamentos específicos no ambiente e disparando a câmera apenas quando o evento de interesse ocorre. Isso evita gravações desnecessárias e reduz drasticamente o volume de dados a ser processado. Em laboratório, isso é especialmente útil para fenômenos imprevisíveis, como falhas mecânicas ou reações que acontecem subitamente.</p>



<p class="wp-block-paragraph">Após a captura, algoritmos de ML realizam análises automáticas em tempo real. Eles podem identificar anomalias em experimentos, extrair medidas quantitativas (como velocidade, aceleração, temperatura estimada, deformação de materiais) ou reconstruir informações ausentes. Técnicas de fotografia computacional, por sua vez, permitem reconstruir trajetórias de objetos mesmo com quadros parcialmente amostrados ou previstos, aumentando a resolução temporal sem aumentar a taxa de quadros.</p>



<p class="wp-block-paragraph">Segundo pesquisas da U.S. Naval Research Laboratory, combinar IA e high-speed imaging tem ampliado significativamente a capacidade de detecção e previsão em ambientes complexos — do monitoramento submarino à vigilância aérea — permitindo que sistemas automatizados reajam mais rapidamente a fenômenos dinâmicos.</p>



<h2 class="wp-block-heading"><strong>Sensibilidade, Baixa Iluminação e Ruggedização</strong></h2>



<p class="wp-block-paragraph">A sensibilidade do sensor é uma das limitações mais críticas em câmeras de alta velocidade. Isso ocorre porque, ao aumentar a taxa de quadros, o tempo disponível para cada exposição cai drasticamente — muitas vezes para a faixa dos microssegundos. Quanto menor a exposição, menos fótons são capturados, o que pode resultar em imagens escuras ou com alto nível de ruído. A solução para esse problema passa por avanços significativos na engenharia de sensores.</p>



<p class="wp-block-paragraph">Os fabricantes têm adotado tecnologias como <strong>poços de pixels maiores</strong>, capazes de armazenar mais carga elétrica por fóton recebido, e <strong>sensores back-illuminated</strong>, nos quais a luz atinge a região fotossensível diretamente, sem atravessar camadas metálicas. Também se popularizam revestimentos ópticos especiais e sistemas de <strong>resfriamento do sensor</strong>, que reduzem ruído térmico, aumentando a qualidade da imagem mesmo em condições de luminosidade mínima. Essas inovações já foram aplicadas por agências como a NASA, possibilitando registrar fenômenos aeroespaciais ultrarrápidos sob iluminação extremamente limitada.</p>



<p class="wp-block-paragraph">Além da sensibilidade, outro fator essencial é a <strong>ruggedização</strong> — a capacidade de operar em ambientes severos. Câmeras usadas em experimentos de combustão, testes balísticos, pesquisas oceânicas, aplicações militares ou inspeção industrial precisam resistir a vibração intensa, choques térmicos, poeira, umidade e variações bruscas de pressão. Estruturas reforçadas, conectores robustos, portas padronizadas e interfaces ópticas, como fibra, garantem que o sistema continue operando mesmo sob condições extremas. O Departamento de Defesa dos EUA destaca que, em cenários como testes de voo e instrumentação de campo, a robustez ambiental é tão importante quanto a capacidade óptica da câmera.</p>



<h2 class="wp-block-heading"><strong>Desafios Atuais e Trade-offs Tecnológicos</strong></h2>



<p class="wp-block-paragraph">Apesar de todos os avanços apresentados até aqui, as câmeras de alta velocidade continuam enfrentando limitações fundamentais impostas pela física, pelos materiais e pela própria arquitetura eletrônica. O primeiro grande desafio é o equilíbrio entre <strong>taxa de quadros e sensibilidade</strong>. Quanto maior a velocidade, menor o tempo de exposição e, portanto, menor a quantidade de luz capturada. Para compensar isso, é necessário aumentar a iluminação ou melhorar a eficiência do sensor — ambas soluções que trazem custos e complexidade adicionais.</p>



<p class="wp-block-paragraph">Outro desafio recorrente envolve a <strong>resolução espacial</strong>. Aumentar a resolução significa usar pixels menores, mas pixels menores capturam menos luz e são mais suscetíveis a ruído. Em certas aplicações científicas e industriais, a busca por detalhes espaciais entra em conflito direto com a necessidade de registrar fenômenos extremamente rápidos. Da mesma forma, expandir a captura para faixas como UV, SWIR e térmico requer o uso de materiais específicos e ópticas especiais, que elevam o custo e diminuem a durabilidade do sistema.</p>



<p class="wp-block-paragraph">A <strong>latência e a sincronização</strong> também apresentam obstáculos consideráveis. Muitos experimentos, como estudos de dinâmica química ultrarrápida ou medições de alta energia, precisam de sincronização em nível de microssegundos entre múltiplas câmeras, fontes de luz e sistemas de aquisição de dados. Qualquer jitter — pequenas variações de tempo — pode comprometer completamente o experimento, inviabilizando a reconstrução precisa de eventos transientes. Por isso, mecanismos de controle de tempo e clock distribuído tornam-se tão importantes quanto os próprios sensores.</p>



<p class="wp-block-paragraph">Por fim, questões econômicas desempenham papel central no desenvolvimento do setor. Muitas das tecnologias mais avançadas requerem componentes caros, processos de fabricação complexos e calibração meticulosa. Assim, fabricantes precisam decidir cuidadosamente quais recursos entregar em cada modelo e qual público-alvo atender, equilibrando desempenho, custo e aplicabilidade.</p>



<h2 class="wp-block-heading"><strong>Novas Possibilidades e Conclusão</strong></h2>



<p class="wp-block-paragraph">A evolução das câmeras de alta velocidade segue uma trajetória marcada por inovações ópticas, eletrônicas e computacionais que ampliam drasticamente o que é possível observar, medir e analisar. À medida que o setor avança, surgem novas oportunidades científicas e industriais impulsionadas pela combinação de recursos antes considerados incompatíveis — como alta sensibilidade, captura multispectral, inteligência artificial embarcada e operação em ambientes extremos.</p>



<p class="wp-block-paragraph">A expansão para além do espectro visível abre portas para estudos avançados em química, física de materiais, termografia e análise ultravioleta, áreas nas quais fenômenos rápidos e invisíveis desempenham papel determinante. Paralelamente, a redução do <em>dead time</em> e o aperfeiçoamento dos mecanismos de obturação permitem acompanhar processos contínuos com precisão temporal sem precedentes. Em conjunto, esses avanços redefinem a capacidade de registrar eventos únicos e irrepetíveis.</p>



<p class="wp-block-paragraph">Outra fronteira importante está na inteligência computacional integrada. Ao incorporar IA, aprendizado de máquina e técnicas de fotografia computacional, as câmeras deixam de ser apenas dispositivos de captura para se tornarem sistemas de análise em tempo real. Essa transição é particularmente significativa para aplicações críticas, como vigilância avançada, controle industrial, robótica autônoma e instrumentação científica. A informação passa a ser produzida, filtrada e interpretada no próprio dispositivo, reduzindo latência e melhorando a tomada de decisão.</p>



<p class="wp-block-paragraph">Sensores mais sensíveis, estruturas robustas e integração modular garantem que essas tecnologias possam operar em condições ambientais cada vez mais desafiadoras — desde experimentos aeroespaciais conduzidos pela NASA até testes balísticos ou inspeções industriais realizadas em campo. A combinação entre robustez física e precisão temporal transforma as câmeras de alta velocidade em instrumentos confiáveis para ambientes que exigem resiliência.</p>



<p class="wp-block-paragraph">Entretanto, os desafios técnicos permanecem. Questões como o balanço entre resolução e sensibilidade, o custo elevado de materiais especializados e a necessidade de sincronização precisa ainda exigem soluções complexas e, muitas vezes, personalizadas. Isso significa que o futuro do setor dependerá não apenas de inovações isoladas, mas da capacidade de integrar diferentes tecnologias de forma otimizada e economicamente viável.</p>



<p class="wp-block-paragraph">O panorama que se desenha é o de câmeras cada vez mais inteligentes, rápidas e versáteis — sistemas completos capazes de observar fenômenos ultrarrápidos, processar dados massivos e gerar conhecimento de forma autônoma. À medida que novas pesquisas avançam, especialmente em sensores de nova geração e arquiteturas computacionais emergentes, a tendência é que a captura de alta velocidade deixe de ser uma ferramenta exclusiva de grandes laboratórios e se torne um recurso amplamente acessível em diversas áreas da engenharia e da ciência aplicada.</p><p>The post <a href="https://mcu.tec.br/sensores/o-futuro-das-cameras-de-alta-velocidade-sensores-ia-e-novas-fronteiras-da-captura-ultrarrapida/">O Futuro das Câmeras de Alta Velocidade: Sensores, IA e Novas Fronteiras da Captura Ultrarrápida</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">849</post-id>	</item>
		<item>
		<title>Microsensores e Nanosensores Eletroquímicos: Funcionamento, Tipos e Aplicações</title>
		<link>https://mcu.tec.br/sensores/microsensores-e-nanosensores-eletroquimicos-funcionamento-tipos-e-aplicacoes/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=microsensores-e-nanosensores-eletroquimicos-funcionamento-tipos-e-aplicacoes</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Sat, 30 Aug 2025 18:05:39 +0000</pubDate>
				<category><![CDATA[Sensores]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=782</guid>

					<description><![CDATA[<p>Os microsensores e nanosensores eletroquímicos estão revolucionando a forma como medimos grandezas químicas e biológicas em tempo real. Este artigo apresenta, de forma clara e técnica, o funcionamento dos principais tipos de sensores — potenciométricos, amperométricos, impedimétricos e baseados em transistores — destacando suas vantagens, limitações e aplicações práticas em áreas como saúde, monitoramento ambiental, indústria química e dispositivos portáteis. Exploramos ainda as tendências futuras, incluindo a integração com nanomateriais, sistemas híbridos e inteligência artificial, que ampliam a sensibilidade e seletividade desses dispositivos.</p>
<p>The post <a href="https://mcu.tec.br/sensores/microsensores-e-nanosensores-eletroquimicos-funcionamento-tipos-e-aplicacoes/">Microsensores e Nanosensores Eletroquímicos: Funcionamento, Tipos e Aplicações</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">Microsensores e nanosensores são dispositivos que convertem uma grandeza física, química ou biológica (temperatura, pressão, concentração iônica, glicose, etc.) em um sinal elétrico (tensão, corrente, impedância, frequência). Em termos de escala, costuma-se chamar de <strong>microsensores</strong> aqueles cujas estruturas ativas têm dimensões típicas entre ~1 µm e 1 mm; <strong>nanosensores</strong> operam quando uma ou mais dimensões críticas estão abaixo de ~100 nm. A miniaturização não é apenas “tornar menor”: ela altera as leis que governam sensibilidade, ruído, resposta dinâmica e consumo de energia — e é justamente isso que torna micro/nano tão atraentes.</p>



<p class="wp-block-paragraph">Um efeito central é a <strong>relação área/volume</strong>. Para uma geometria simples (p. ex., um cubo de aresta L), vale \(\frac{S}{V}=\frac{6}{L}\).</p>



<p class="wp-block-paragraph">À medida que L diminui, S/V cresce. Em sensores químicos/biológicos, isso implica <strong>mais sítios de interação por unidade de volume</strong>, aumentando a eficiência de adsorção/reação; em sensores térmicos, menor massa térmica acelera o aquecimento/resfriamento; em sensores mecânicos (p. ex., vigas piezorresistivas), a diminuição da seção aumenta deformações específicas, favorecendo a sensibilidade.</p>



<p class="wp-block-paragraph">A <strong>sensibilidade</strong> de um sensor, em termos gerais, é a razão entre a variação do sinal de saída e a variação da grandeza medida: </p>



<p class="wp-block-paragraph">\[S=\frac{\Delta y}{\Delta x} \quad \big[\text{por exemplo, V/Pa ou }\mu\text{A}/\text{mM}\big].\]



<p class="wp-block-paragraph">Na prática, o menor sinal útil é limitado pelo <strong>ruído</strong>. Um limite fundamental para dispositivos eletrônicos é o ruído térmico (Johnson–Nyquist) em um resistor R, medido numa largura de banda B: \[v_{n,\mathrm{rms}}=\sqrt{4k_\mathrm{B}TB R}\],</p>



<p class="wp-block-paragraph">onde \(k_\mathrm{B})\ é a constante de Boltzmann e T a temperatura absoluta. Uma métrica de desempenho largamente utilizada é o <strong>limite de detecção (LOD)</strong>, aproximado por \(\mathrm{LOD} \approx \frac{3\,\sigma_\text{branco}}{\text{slope}},\)</p>



<p class="wp-block-paragraph">em que \(\sigma_\text{branco}\) é o desvio-padrão do sinal sem analito (ruído de fundo) e <em>slope</em> é a inclinação da curva de calibração (isto é, a sensibilidade analítica). Miniaturizar ajuda o <em>slope</em> (mais interação por volume) e pode permitir reduzir R e B, mas também pode introduzir outras fontes de ruído flicker 1/f, shot, ruído de interface), exigindo projeto cuidadoso.</p>



<p class="wp-block-paragraph">O <strong>tempo de resposta</strong> muitas vezes é controlado por difusão ou transferência de calor/carga. Quando a etapa limitante é difusiva, o tempo característico escala aproximadamente como \(t \sim \frac{L^{2}}{D}\), onde D é o coeficiente de difusão do analito (ou a difusividade térmica em sensores térmicos). Assim, reduzir L de 100 µm para 10 µm reduz t em ~100×, explicando por que micro/nanosensores costumam ser <strong>mais rápidos</strong> que seus equivalentes macroscópicos.</p>


<div class="wp-block-image">
<figure class="alignleft size-full"><img loading="lazy" decoding="async" width="350" height="350" src="https://mcu.tec.br/wp-content/uploads/2025/08/image-26.png" alt="" class="wp-image-789" srcset="https://mcu.tec.br/wp-content/uploads/2025/08/image-26.png 350w, https://mcu.tec.br/wp-content/uploads/2025/08/image-26-300x300.png 300w, https://mcu.tec.br/wp-content/uploads/2025/08/image-26-150x150.png 150w" sizes="(max-width: 350px) 100vw, 350px" /></figure>
</div>


<p class="wp-block-paragraph">Há diversas <strong>classes de transdução</strong>: (i) <strong>mecânica</strong> (piezorresistiva, piezoelétrica, ressonadores MEMS/NEMS), (ii) <strong>elétrica</strong> (capacitiva, condutiva, FET-baseada), (iii) <strong>térmica</strong> (bolômetros, termopares/termopilhas), (iv) <strong>óptica</strong> (guia de onda, plasmonics, microcavidades), e (v) <strong>eletroquímica</strong> (potenciométrica, amperométrica, impedimétrica e dispositivos baseados em transistores como ISFET/EGFET). Neste artigo daremos ênfase especial à <strong>eletroquímica</strong>, pois é nela que a alta área específica e a engenharia de superfícies em micro/nanoescala produzem saltos visíveis em seletividade, rapidez e LOD.</p>



<p class="wp-block-paragraph">Por fim, um comentário sobre <strong>calibração e linearidade</strong>: miniaturização pode aumentar histerese, <em>drift</em> e efeitos parasitas de interface (camadas duplas, cargas presas, envenenamento de eletrodo). Técnicas como funcionalização seletiva, <em>guard rings</em>, modulação de frequência (para separar sinal de fundo) e modelos de correção são parte integrante do projeto de micro/nanosensores de alto desempenho.</p>



<h1 class="wp-block-heading">Classificação e Princípios de Transdução</h1>



<p class="wp-block-paragraph">Microsensores e nanosensores podem ser classificados segundo o <strong>princípio de transdução</strong>, isto é, a forma como convertem uma grandeza física, química ou biológica em um sinal mensurável. De maneira geral, distinguem-se cinco famílias principais: <strong>mecânicos</strong>, <strong>elétricos</strong>, <strong>térmicos</strong>, <strong>ópticos</strong> e <strong>eletroquímicos</strong>. Cada uma apresenta vantagens específicas, mas também limitações decorrentes da física da detecção e da integração com a eletrônica de leitura.</p>



<p class="wp-block-paragraph"><strong>Sensores mecânicos</strong> utilizam deformações ou ressonâncias em estruturas microfabricadas (MEMS — <em>Micro-Electro-Mechanical Systems</em> e NEMS — <em>Nano-Electro-Mechanical Systems</em>). Um exemplo clássico é o acelerômetro piezorresistivo, onde a deflexão de uma viga altera a resistência elétrica segundo a lei: \[\frac{\Delta R}{R} = \pi_l \sigma_l + \pi_t \sigma_t\],</p>



<p class="wp-block-paragraph">em que \(\pi_l\) e \(\pi_t\) são os coeficientes piezorresistivos longitudinal e transversal, e σ as tensões mecânicas. Esses dispositivos são robustos e compatíveis com processos CMOS, mas podem sofrer com histerese mecânica e envelhecimento.</p>



<p class="wp-block-paragraph"><strong>Sensores elétricos</strong> exploram variações de capacitância, condutância ou efeito de campo em transistores. Capacitores micrométricos detectam deslocamentos de femtômetros por meio da relação \(C = \epsilon A/d\). Já os nanosensores FET (<em>Field Effect Transistor</em>) detectam adsorção de moléculas na superfície do canal, alterando a densidade de portadores. A grande vantagem está na integração direta com circuitos eletrônicos, embora a seletividade química exija funcionalização da superfície.</p>



<p class="wp-block-paragraph"><strong>Sensores térmicos</strong> incluem termopares miniaturizados, termistores e bolômetros. Em escala micro/nano, a massa térmica reduzida resulta em tempos de resposta muito rápidos \(t \sim L^2/\alpha\), sendo α a difusividade térmica). A limitação está no ruído térmico e na dependência do ambiente, exigindo encapsulamento adequado.</p>



<p class="wp-block-paragraph"><strong>Sensores ópticos</strong> utilizam microcavidades, guias de onda ou estruturas plasmônicas. A ressonância óptica de uma cavidade pode deslocar-se em função de uma mudança de índice de refração local, conforme: \(\Delta \lambda = \lambda \frac{\Delta n}{n_{\text{eff}}}\),</p>



<p class="wp-block-paragraph">onde Δn é a variação do índice e \(n_{\text{eff}}\) o índice efetivo do modo óptico. Esses sensores alcançam limites de detecção extremamente baixos, chegando a uma única molécula, mas demandam fontes e detectores ópticos externos.</p>



<p class="wp-block-paragraph">Por fim, os <strong>sensores eletroquímicos</strong> constituem uma família crucial, sobretudo em aplicações biomédicas e ambientais. Eles se subdividem em:</p>



<ul class="wp-block-list">
<li><strong>Potenciométricos</strong> (medem diferenças de potencial em ausência de corrente significativa).</li>



<li><strong>Amperométricos</strong> (corrente proporcional à concentração de analito).</li>



<li><strong>Impedimétricos</strong> (monitoram variações de impedância interfacial).</li>



<li><strong>Transistores baseados em efeito de campo</strong> (ISFETs e variantes, onde íons ou moléculas modulam a condutância do canal).</li>
</ul>



<p class="wp-block-paragraph">Esses sensores serão tratados em seções dedicadas devido à sua relevância prática e à riqueza de fundamentos físico-químicos envolvidos.</p>



<h1 class="wp-block-heading">Sensores Eletroquímicos: Potenciométricos</h1>


<div class="wp-block-image">
<figure class="alignright size-full"><img loading="lazy" decoding="async" width="229" height="220" src="https://mcu.tec.br/wp-content/uploads/2025/08/image-25.png" alt="" class="wp-image-788"/></figure>
</div>


<p class="wp-block-paragraph">Os <strong>sensores potenciométricos</strong> são talvez os mais antigos e difundidos da eletroquímica. Seu princípio fundamental é a medição da <strong>diferença de potencial elétrico</strong> entre dois eletrodos, em ausência de corrente significativa. Essa diferença reflete o equilíbrio termodinâmico de íons ou espécies químicas na interface eletrodo/solução, permitindo inferir concentrações de analitos.</p>



<p class="wp-block-paragraph">O exemplo clássico é o <strong>eletrodo íon-seletivo (ISE, <em>Ion-Selective Electrode</em>)</strong>, como o eletrodo de vidro para pH. Ele possui uma membrana sensível que interage seletivamente com determinados íons (H⁺, Na⁺, K⁺, Ca²⁺, etc.), criando um potencial de junção que pode ser comparado a um eletrodo de referência estável (como Ag/AgCl).</p>



<p class="wp-block-paragraph">O comportamento de tais sensores é descrito pela <strong>equação de Nernst</strong>: \[E = E^0 + \frac{RT}{zF} \ln a_{\text{ion}}\]



<ul class="wp-block-list">
<li>E = potencial medido</li>



<li>\(E^0\) = potencial padrão do eletrodo</li>



<li>R = constante universal dos gases (8,314 J·mol⁻¹·K⁻¹)</li>



<li>T = temperatura absoluta (K)</li>



<li>z = carga do íon em questão</li>



<li>F = constante de Faraday (96485 C·mol⁻¹)</li>



<li>\(a_{\text{ion}}\) = atividade do íon na solução</li>
</ul>



<p class="wp-block-paragraph">Na prática, a atividade é aproximada pela concentração para soluções diluídas. Para o caso dos íons H⁺, essa equação se traduz diretamente na escala de <strong>pH</strong>: \[E = E^0 &#8211; 0,0591 \cdot \text{pH} \quad \text{(a 25 °C)}\]



<p class="wp-block-paragraph">Isso mostra que a cada variação de uma unidade de pH, o potencial muda aproximadamente <strong>59 mV</strong>.</p>



<h3 class="wp-block-heading">Vantagens</h3>



<ul class="wp-block-list">
<li>Não consomem reagentes nem exigem corrente elétrica significativa.</li>



<li>Estrutura simples, baixo custo e resposta direta.</li>



<li>Podem operar continuamente em campo (monitoramento de água, processos industriais, fisiologia).</li>
</ul>



<h3 class="wp-block-heading">Limitações</h3>



<ul class="wp-block-list">
<li>Seletividade imperfeita: íons interferentes podem alterar o potencial.</li>



<li>Necessidade de eletrodo de referência estável.</li>



<li>Deriva do potencial com o tempo, exigindo calibração frequente.</li>



<li>Resposta limitada a faixas de concentração (tipicamente 10⁻¹ a 10⁻⁶ mol/L).</li>
</ul>



<h3 class="wp-block-heading">Aplicações</h3>



<ul class="wp-block-list">
<li><strong>Medição de pH</strong> em processos industriais, análises laboratoriais e monitoramento ambiental.</li>



<li>Eletrodos seletivos de íons para <strong>sódio, potássio, cálcio, nitrato, fluoreto</strong>, entre outros — muito usados em bioquímica clínica.</li>



<li>Controle de qualidade em indústrias de alimentos e farmacêuticas.</li>



<li>Sistemas portáteis e <em>wearables</em> para monitoramento fisiológico, como sensores de pH em saliva ou suor.</li>
</ul>



<p class="wp-block-paragraph">Os sensores potenciométricos representam a base da instrumentação analítica eletroquímica moderna, servindo como porta de entrada para tecnologias mais sofisticadas. Eles ilustram como um conceito físico-químico simples pode ser traduzido em um dispositivo robusto e útil no cotidiano.</p>



<h1 class="wp-block-heading">Sensores Eletroquímicos: Amperométricos</h1>



<p class="wp-block-paragraph">Enquanto os sensores potenciométricos medem diferenças de potencial em equilíbrio, os <strong>sensores amperométricos</strong> operam em regime dinâmico, impondo uma diferença de potencial controlada entre eletrodo de trabalho e eletrodo de referência. Essa polarização força uma reação de <strong>oxirredução (redox)</strong> do analito, e a corrente elétrica resultante é proporcional à sua concentração.</p>



<p class="wp-block-paragraph">O princípio básico é dado pela <strong>lei de Faraday da eletrólise</strong>: \[I = n F A k C\]



<ul class="wp-block-list">
<li>I = corrente medida (A)</li>



<li>n = número de elétrons transferidos por molécula de analito</li>



<li>F = constante de Faraday (96485 C·mol⁻¹)</li>



<li>A = área efetiva do eletrodo (cm²)</li>



<li>k = coeficiente de transporte de massa (cm/s)</li>



<li>C = concentração do analito (mol/L)</li>
</ul>



<p class="wp-block-paragraph">Em condições controladas (difusão limitada), a corrente atinge um <strong>platô</strong> característico chamado <strong>corrente de difusão</strong>. O valor dessa corrente segue a equação de <strong>Cottrell</strong> para transientes ou de <strong>Levich</strong> em sistemas hidrodinâmicos. No caso mais simples, em regime de difusão linear: \[I_d = n F A D \frac{C}{\delta}\]



<ul class="wp-block-list">
<li>D = coeficiente de difusão (cm²/s)</li>



<li>δ = espessura da camada de difusão (cm)</li>
</ul>



<p class="wp-block-paragraph">Isso mostra a dependência direta entre corrente e concentração, característica que torna esses sensores altamente quantitativos.</p>



<h3 class="wp-block-heading">Vantagens</h3>



<ul class="wp-block-list">
<li><strong>Alta sensibilidade</strong>, chegando a níveis de detecção de nanomolar.</li>



<li><strong>Rápida resposta</strong>, determinada por difusão e cinética de reação.</li>



<li>Permitem monitoramento contínuo de espécies redox ativas.</li>



<li>Compatíveis com <strong>microsistemas</strong> (microeletrodos têm camada de difusão mais fina, aumentando a resposta).</li>
</ul>



<h3 class="wp-block-heading">Limitações</h3>



<ul class="wp-block-list">
<li>Exigem polarização elétrica e controle rigoroso do potencial aplicado.</li>



<li>Podem sofrer <strong>interferência</strong> de espécies redox semelhantes.</li>



<li>O eletrodo pode ser envenenado ou degradado por subprodutos da reação.</li>



<li>Requerem eletrônica mais complexa (potenciostato ou circuito equivalente).</li>
</ul>



<h3 class="wp-block-heading">Aplicações</h3>



<ul class="wp-block-list">
<li><strong>Sensores de glicose</strong> (os mais famosos): utilizam a enzima glicose-oxidase que gera peróxido de hidrogênio, oxidado amperometricamente no eletrodo.</li>



<li><strong>Monitoramento ambiental</strong>: detecção de oxigênio dissolvido, nitrito, peróxido, metais pesados.</li>



<li><strong>Controle industrial</strong>: processos de fermentação, tratamento de água e controle de gases tóxicos.</li>



<li><strong>Dispositivos biomédicos implantáveis</strong>: monitoramento in vivo de neurotransmissores, lactato, dopamina.</li>
</ul>



<p class="wp-block-paragraph">A grande contribuição dos sensores amperométricos foi abrir caminho para a chamada <strong>bioeletroquímica aplicada</strong>, unindo enzimas, membranas seletivas e microeletrônica em sistemas robustos — um exemplo emblemático é o glicosímetro portátil, essencial no tratamento do diabetes.</p>



<h1 class="wp-block-heading">Sensores Eletroquímicos: Impedimétricos</h1>



<p class="wp-block-paragraph">Os <strong>sensores impedimétricos</strong> distinguem-se dos potenciométricos e amperométricos por não se limitarem à medida de uma corrente contínua ou de um potencial em equilíbrio. Em vez disso, eles analisam a <strong>resposta em frequência</strong> de um sistema eletroquímico quando submetido a um sinal alternado de pequena amplitude. Essa técnica, chamada <strong>Espectroscopia de Impedância Eletroquímica (EIS, <em>Electrochemical Impedance Spectroscopy</em>)</strong>, permite investigar propriedades interfaciais e processos de transporte de massa com alta sensibilidade.</p>



<p class="wp-block-paragraph">A impedância é definida como a razão entre a tensão aplicada e a corrente resultante: \[Z(\omega) = \frac{V(\omega)}{I(\omega)} = Z'(\omega) + jZ&#8221;(\omega)\]



<ul class="wp-block-list">
<li>Z(ω) = impedância complexa</li>



<li>Z′(ω) = parte real (resistiva)</li>



<li>Z′′(ω) = parte imaginária (reativa)</li>



<li>\(\omega = 2\pi f\) = frequência angular do sinal</li>
</ul>



<p class="wp-block-paragraph">A resposta do sistema é interpretada por meio de <strong>circuitos equivalentes</strong>, sendo o mais simples o de <strong>Randles</strong>, que combina uma resistência de solução (\(R_s\)), uma capacitância da dupla camada elétrica \((C_{dl})\), uma resistência de transferência de carga (\(R_{ct}\)) e um elemento difusivo de Warburg (\(Z_w\)): \[Z(\omega) = R_s + \frac{1}{\frac{1}{R_{ct} + Z_w} + j\omega C_{dl}}\]



<p class="wp-block-paragraph">Esse modelo mostra como a presença de um analito pode alterar a resistência de transferência de carga ou a capacitância interfacial, modificando a impedância total.</p>



<h3 class="wp-block-heading">Vantagens</h3>



<ul class="wp-block-list">
<li><strong>Altíssima sensibilidade</strong>: capaz de detectar mudanças moleculares muito sutis, como a ligação antígeno–anticorpo.</li>



<li><strong>Método não destrutivo</strong>: o sinal aplicado é de baixa amplitude, preservando a amostra.</li>



<li>Possibilita análise de <strong>múltiplos mecanismos</strong> (cinética, difusão, adsorção).</li>



<li>Adequado para <strong>biofuncionalização de superfícies</strong>: a ligação de proteínas ou DNA em eletrodos funcionalizados causa variações detectáveis em \(R_{ct}\) ou \(C_{dl}\).</li>
</ul>



<h3 class="wp-block-heading">Limitações</h3>



<ul class="wp-block-list">
<li>Requer <strong>instrumentação sofisticada</strong> para análise em frequência (gerador de sinal e analisador de resposta).</li>



<li>Interpretação dos dados depende de <strong>modelagem complexa</strong>, podendo levar a ambiguidades.</li>



<li>Mais sensível a ruídos elétricos externos e à estabilidade do eletrodo.</li>



<li>O tempo de medição pode ser maior, já que envolve varredura de frequências.</li>
</ul>



<h3 class="wp-block-heading">Aplicações</h3>



<ul class="wp-block-list">
<li><strong>Biossensores de DNA e proteínas</strong>: identificação de mutações genéticas, marcadores tumorais, patógenos.</li>



<li><strong>Sensores de corrosão</strong>: monitoramento do estado de estruturas metálicas em ambiente marinho ou industrial.</li>



<li><strong>Controle de revestimentos e filmes finos</strong>: avaliação de barreiras protetoras e camadas dielétricas.</li>



<li><strong>Nanobiossensores</strong>: integração com nanopartículas de ouro, nanotubos de carbono e grafeno, aumentando a área efetiva e a sensibilidade.</li>
</ul>



<p class="wp-block-paragraph">Os sensores impedimétricos representam a fronteira entre a química analítica e a engenharia de materiais. Diferenciam-se por não apenas medir a concentração de espécies químicas, mas também por fornecer uma “assinatura elétrica” do processo de interação, o que abre espaço para diagnósticos mais seletivos e multifatoriais.</p>



<h1 class="wp-block-heading">Sensores Eletroquímicos Baseados em Transistores</h1>



<p class="wp-block-paragraph">Os <strong>sensores eletroquímicos baseados em transistores</strong> representam uma evolução dos princípios potenciométricos, ao integrar a sensibilidade iônica diretamente em dispositivos de estado sólido. O exemplo mais conhecido é o <strong>ISFET (Ion-Sensitive Field Effect Transistor)</strong>, um transistor de efeito de campo sensível a íons. Ele deriva do MOSFET convencional, mas substitui o eletrodo metálico da porta por uma camada isolante (óxido, nitreto de silício, Ta₂O₅, Al₂O₃, etc.) em contato direto com a solução eletrolítica.</p>



<p class="wp-block-paragraph">Quando íons interagem com essa superfície, modificam o <strong>potencial de superfície (\(\psi_0\))</strong>, o que, por sua vez, altera a densidade de portadores no canal do transistor. Assim, a <strong>corrente de dreno</strong> (\(I_D\)) torna-se dependente da concentração iônica do meio: \[I_D = \mu C_{ox} \frac{W}{L} \left( V_{GS} &#8211; V_{th}(pH) \right) V_{DS}\]



<ul class="wp-block-list">
<li>μ = mobilidade dos portadores no canal</li>



<li>\(C_{ox}\) = capacitância por unidade de área da camada isolante</li>



<li>W/L = razão largura/comprimento do canal</li>



<li>\(V_{GS}\) = tensão porta-fonte aplicada</li>



<li>\(V_{DS}\) = tensão dreno-fonte aplicada</li>



<li>\(V_{th}(pH)\) = tensão de limiar dependente do pH ou do íon específico</li>
</ul>



<p class="wp-block-paragraph">O deslocamento do limiar (\(V_{th}\)) obedece à <strong>relação de Nernst</strong>, gerando uma variação típica de até <strong>59 mV/pH</strong> a 25 °C, semelhante ao observado em eletrodos de vidro, mas em um dispositivo semicondutor integrável.</p>



<h3 class="wp-block-heading">Vantagens</h3>



<ul class="wp-block-list">
<li><strong>Integração em chips CMOS</strong>: permite sistemas de baixo custo e alta densidade de sensores.</li>



<li><strong>Miniaturização extrema</strong>: ideal para <em>lab-on-a-chip</em> e aplicações biomédicas portáteis.</li>



<li><strong>Resposta rápida</strong> devido à baixa capacitância e alta sensibilidade superficial.</li>



<li>Possibilidade de funcionalização seletiva da superfície (DNA, enzimas, anticorpos).</li>
</ul>



<h3 class="wp-block-heading">Limitações</h3>



<ul class="wp-block-list">
<li><strong>Deriva do limiar</strong> causada por cargas presas no óxido e envelhecimento do dielétrico.</li>



<li>Necessidade de encapsulamento adequado para operação estável em líquidos.</li>



<li>Sensibilidade limitada por efeitos de dupla camada elétrica e ruído 1/f.</li>



<li>Requer calibração frequente, principalmente em ambientes biológicos complexos.</li>
</ul>



<h3 class="wp-block-heading">Aplicações</h3>



<ul class="wp-block-list">
<li><strong>Medidores de pH em estado sólido</strong>, substituindo eletrodos de vidro frágeis.</li>



<li><strong>Biossensores enzimáticos</strong>: a reação enzimática altera o pH local (p. ex., glicose-oxidase → variação de pH detectada pelo ISFET).</li>



<li><strong>Sensores de DNA</strong>: a hibridização de cadeias modifica a carga superficial, modulando a corrente do canal.</li>



<li><strong>Nanotransistores biofuncionalizados</strong> (com nanotubos de carbono ou nanofios de silício), ampliando a área específica e atingindo sensibilidade em nível de molécula única.</li>
</ul>



<p class="wp-block-paragraph">Esse tipo de sensor ilustra a fusão entre <strong>nanoeletrônica e bioquímica</strong>, pois explora a física de dispositivos semicondutores para traduzir fenômenos de superfície em sinais elétricos robustos. Hoje, eles já são encontrados em <strong>microssistemas descartáveis de diagnóstico rápido (point-of-care)</strong> e despontam como a base de futuros implantes inteligentes de monitoramento metabólico.</p>



<h1 class="wp-block-heading">Comparação Crítica e Aplicações Integradas</h1>



<p class="wp-block-paragraph">Após explorar os quatro principais tipos de sensores eletroquímicos (potenciométricos, amperométricos, impedimétricos e baseados em transistores), é essencial realizar uma análise crítica comparativa. Cada classe de sensor possui <strong>vantagens únicas</strong> que a tornam ideal para determinados contextos, mas também <strong>limitações estruturais</strong> que podem comprometer sua aplicação em situações específicas.</p>



<h3 class="wp-block-heading">Comparação de Princípios e Desempenho</h3>



<ul class="wp-block-list">
<li><strong>Potenciométricos</strong>: simples, robustos e de baixo custo. São ideais para medições contínuas de pH e íons específicos em soluções diluídas. Entretanto, sua seletividade é imperfeita, sofrem interferências iônicas e exigem calibrações frequentes.</li>



<li><strong>Amperométricos</strong>: muito sensíveis e quantitativos, com rápida resposta e detecção em níveis de nanomolar. São preferidos quando se deseja acompanhar reações enzimáticas ou metabólicas (ex.: glicosímetros). Porém, exigem polarização constante e podem sofrer degradação do eletrodo.</li>



<li><strong>Impedimétricos</strong>: fornecem uma &#8220;assinatura elétrica&#8221; detalhada do sistema, permitindo detectar não apenas concentrações, mas também interações moleculares complexas. São ideais para biossensores de DNA e proteínas, embora requeiram instrumentação mais cara e sofisticada.</li>



<li><strong>Transistores (ISFETs e variantes)</strong>: possibilitam integração em chips CMOS e uso em sistemas <em>lab-on-a-chip</em>. São rápidos, miniaturizáveis e altamente escaláveis, mas sofrem com deriva do limiar, ruído eletrônico e estabilidade limitada em líquidos agressivos.</li>
</ul>



<h3 class="wp-block-heading">Critérios de Escolha</h3>



<ul class="wp-block-list">
<li>Para <strong>monitoramento ambiental contínuo</strong> (pH, íons dissolvidos), sensores potenciométricos ainda são imbatíveis em simplicidade e custo.</li>



<li>Para <strong>detecção bioquímica quantitativa</strong> (glicose, lactato, oxigênio), sensores amperométricos são a melhor escolha.</li>



<li>Para <strong>diagnósticos de alta seletividade</strong> (DNA, marcadores tumorais), sensores impedimétricos oferecem o maior potencial, apesar da complexidade.</li>



<li>Para <strong>integração em dispositivos portáteis inteligentes</strong> (<em>wearables</em>, implantes), sensores baseados em transistores trazem vantagens de miniaturização e compatibilidade com microeletrônica.</li>
</ul>



<h3 class="wp-block-heading">Aplicações Integradas</h3>



<p class="wp-block-paragraph">Um avanço importante é o <strong>uso combinado dessas tecnologias</strong> em sistemas híbridos:</p>



<ul class="wp-block-list">
<li>Em <strong>lab-on-a-chip</strong>, pode-se usar um ISFET para monitorar pH, enquanto sensores impedimétricos detectam ligações biomoleculares específicas.</li>



<li>Em <strong>diagnósticos multiparamétricos</strong>, um mesmo microdispositivo pode reunir eletrodos amperométricos para glicose e lactato, junto a impedimétricos para proteínas, fornecendo um panorama clínico completo.</li>



<li>Em <strong>nanobiossensores</strong>, a integração com nanotubos de carbono, nanofios de silício ou grafeno potencializa todas essas abordagens, ampliando a área superficial e reduzindo os limites de detecção.</li>
</ul>



<h3 class="wp-block-heading">Tendências Futuras</h3>



<p class="wp-block-paragraph">A convergência entre <strong>nanoeletrônica, biotecnologia e inteligência artificial</strong> está levando a sensores capazes de não apenas medir, mas também <strong>interpretar dados em tempo real</strong>, abrindo caminho para <strong>diagnósticos personalizados</strong> e <strong>monitoramento contínuo em saúde</strong>. Além disso, a escalabilidade dos transistores biofuncionalizados e a sensibilidade da espectroscopia de impedância estão criando a base para <strong>implantes inteligentes</strong> e <strong>sensores vestíveis conectados</strong> a sistemas de telemedicina.</p>



<p class="wp-block-paragraph">Em resumo, a escolha do tipo de sensor não é excludente, mas sim estratégica: muitas vezes, o melhor sistema é aquele que combina diferentes tecnologias para explorar o que cada uma tem de melhor.</p>



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



<h2 class="wp-block-heading">Livros gerais sobre sensores micro/nano e eletroquímicos</h2>



<ol class="wp-block-list">
<li><strong>Handbook of Modern Sensors</strong>, 4ª edição — Jacob Fraden (Springer, 2010)<br>— Um clássico que aborda ampla variedade de sensores, incluindo princípios de micro e nanosensoriamento. (<a href="https://onlinecourses.nptel.ac.in/noc25_ee177/preview?utm_source=chatgpt.com">onlinecourses.nptel.ac.in</a>)</li>



<li><strong>Micro‑ and Nano‑Scale Sensors and Transducers</strong>, 1ª edição — E. G. Bakhoum (Taylor &amp; Francis, 2019)<br>— Foca em sensores e transdutores nas escalas micro e nano. (<a href="https://onlinecourses.nptel.ac.in/noc25_ee177/preview?utm_source=chatgpt.com">onlinecourses.nptel.ac.in</a>)</li>



<li><strong>Introduction to Sensors</strong>, 1ª edição — J. Vetelino &amp; A. Reghu (CRC Press, 2011)<br>— Um texto introdutório sobre princípios e tipologias de sensores. (<a href="https://onlinecourses.nptel.ac.in/noc25_ee177/preview?utm_source=chatgpt.com">onlinecourses.nptel.ac.in</a>)</li>



<li><strong>Smart Sensors and MEMS</strong>, 2ª edição — S. Nihtianov &amp; A. Luque (Springer, 2018)<br>— Aborda sensores inteligentes e sistemas microeletromecânicos (MEMS). (<a href="https://onlinecourses.nptel.ac.in/noc25_ee177/preview?utm_source=chatgpt.com">onlinecourses.nptel.ac.in</a>)</li>
</ol>



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



<h2 class="wp-block-heading">Livros especializados em sensores eletroquímicos e biossensores</h2>



<ol start="5" class="wp-block-list">
<li><strong>Electrochemical Sensors</strong>, presente no catálogo da ScienceDirect (Elsevier)<br>— Introduz fundamentos da eletroquímica e descreve diferentes tipos de sensores eletroquímicos. (<a href="https://www.sciencedirect.com/book/9780128231487/electrochemical-sensors?utm_source=chatgpt.com">ScienceDirect</a>)</li>



<li><strong>Electrochemical Sensors and Biosensors</strong>, 1ª edição — Hasan Bagheri et al. (Elsevier)<br>— Aborda desde princípios básicos até dispositivos comerciais, incluindo aplicações em saúde, meio ambiente e vestíveis. (<a href="https://shop.elsevier.com/books/electrochemical-sensors-and-biosensors/bagheri/978-0-443-15297-9?utm_source=chatgpt.com">Elsevier Shop</a>, <a href="https://www.mdpi.com/2079-4991/12/21/3736?utm_source=chatgpt.com">MDPI</a>)</li>



<li><strong>Electrochemical Sensors and Biosensors: Green Sustainable Process for Chemical and Environmental Engineering and Science</strong> — Neves Cruz et al. (Elsevier)<br>— Explora desenvolvimentos recentes, materiais, técnicas de fabricação, miniaturização e integração de sensores. (<a href="https://shop.elsevier.com/books/electrochemical-sensors-and-biosensors/neves-cruz/978-0-443-31562-6?utm_source=chatgpt.com">Elsevier Shop</a>)</li>



<li><strong>Electrochemical Sensors, Biosensors and their Biomedical Applications</strong> (Elsevier)<br>— Revisão abrangente de técnicas modernas e aplicação em sensores químicos e biossensores com relevância biomédica. (<a href="https://www.sciencedirect.com/book/9780123737380/electrochemical-sensors-biosensors-and-their-biomedical-applications?utm_source=chatgpt.com">ScienceDirect</a>)</li>



<li><strong>Nanomaterials‑Based Electrochemical Sensors: Properties, Applications and Recent Advances</strong> (ScienceDirect, Elsevier)<br>— Foca em sensores eletroquímicos baseados em nanomateriais, sua fabricação e aplicações emergentes. (<a href="https://www.sciencedirect.com/book/9780128225127/nanomaterials-based-electrochemical-sensors-properties-applications-and-recent-advances?utm_source=chatgpt.com">ScienceDirect</a>)</li>
</ol>



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



<h2 class="wp-block-heading">Referências de tipo “handbook” ou compilações técnicas</h2>



<ol start="10" class="wp-block-list">
<li><strong>Handbook of Nanosensors: Materials and Technological Applications</strong> — Gomaa A. M. Ali, Kwok Feng Chong, Abdel Salam H. Makhlouf (Springer, 2024)<br>— Aborda tecnologias e materiais empregados em nanosensores, bem como suas aplicações em medicina, biologia, meio ambiente e indústria. (<a href="https://link.springer.com/book/10.1007/978-3-031-47180-3?utm_source=chatgpt.com">SpringerLink</a>)</li>



<li><strong>Handbook of Electrochemistry</strong>, editado por Cynthia Zoski (Elsevier, 2006)<br>— Fonte de referência ampla para fundamentos eletroquímicos, técnicas experimentais e aplicações. (<a href="https://en.wikipedia.org/wiki/Handbook_of_Electrochemistry?utm_source=chatgpt.com">Wikipedia</a>)</li>
</ol>



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



<h2 class="wp-block-heading">Autores reconhecidos com livros relevantes</h2>



<ol start="12" class="wp-block-list">
<li><strong>Analytical Electrochemistry</strong>, diversas edições (a mais recente em 2023) — Joseph Wang (University of California, San Diego)<br>— Um dos principais textos em eletroquímica analítica com várias edições. (<a href="https://en.wikipedia.org/wiki/Joseph_Wang?utm_source=chatgpt.com">Wikipedia</a>)</li>



<li><strong>Biosensors: Microelectrochemical Devices</strong> — M. Lambrechts &amp; W. Sansen (Institute of Physics Publishing, 1992)<br>— Aborda dispositivos microeletroquímicos aplicados a biossensores. (<a href="https://en.wikipedia.org/wiki/Willy_Sansen?utm_source=chatgpt.com">Wikipedia</a>)</li>



<li>(Contexto histórico) <strong>Electrochemical Methods: Fundamentals and Applications</strong> — A. J. Bard &amp; L. R. Faulkner (Wiley, 1980)<br>— Clássico da eletroquímica, frequentemente citado em capítulos sobre sensores eletroquímicos. (<a href="https://link.springer.com/chapter/10.1007/978-1-4757-6257-0_4?utm_source=chatgpt.com">SpringerLink</a>)</li>
</ol>



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



<h2 class="wp-block-heading">Resumo das referências</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Tema</th><th>Título / Autor</th></tr></thead><tbody><tr><td>Visão geral de sensores</td><td><em>Handbook of Modern Sensors</em> — Fraden (2010)</td></tr><tr><td>Micro/Nanosensores</td><td><em>Micro- and Nano-Scale Sensors and Transducers</em> — Bakhoum (2019)</td></tr><tr><td>Fundamentos de sensores</td><td><em>Introduction to Sensors</em> — Vetelino &amp; Reghu (2011)</td></tr><tr><td>MEMS e sensores inteligentes</td><td><em>Smart Sensors and MEMS</em> — Nihtianov &amp; Luque (2018)</td></tr><tr><td>Eletroquímica básica e sensores</td><td><em>Handbook of Electrochemistry</em> — Zoski (2006)</td></tr><tr><td>Eletroquímica analítica</td><td><em>Analytical Electrochemistry</em> — Wang (2023)</td></tr><tr><td>Sensores eletroquímicos</td><td><em>Electrochemical Sensors</em> ; <em>Electrochemical Sensors and Biosensors</em> (Bagheri et al.) ; <em>Electrochemical Sensors and Biosensors&#8230;</em> (Neves Cruz et al.)</td></tr><tr><td>Nanomateriais em sensores</td><td><em>Nanomaterials-Based Electrochemical Sensors</em></td></tr><tr><td>Tecnologia de nanosensores</td><td><em>Handbook of Nanosensors</em> — Ali, Chong &amp; Makhlouf (2024)</td></tr><tr><td>Biossensores microeletroquímicos</td><td><em>Biosensors: Microelectrochemical Devices</em> — Lambrechts &amp; Sansen (1992)</td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/><p>The post <a href="https://mcu.tec.br/sensores/microsensores-e-nanosensores-eletroquimicos-funcionamento-tipos-e-aplicacoes/">Microsensores e Nanosensores Eletroquímicos: Funcionamento, Tipos e Aplicações</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">782</post-id>	</item>
		<item>
		<title>Estacionariedade, Média e Variância no DSP com ESP32: Análise Estatística de Sinais em Sistemas Embarcados</title>
		<link>https://mcu.tec.br/algoritimos/estacionariedade-media-e-variancia-no-dsp-com-esp32-analise-estatistica-de-sinais-em-sistemas-embarcados/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=estacionariedade-media-e-variancia-no-dsp-com-esp32-analise-estatistica-de-sinais-em-sistemas-embarcados</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Fri, 08 Aug 2025 18:26:12 +0000</pubDate>
				<category><![CDATA[Algoritimos]]></category>
		<category><![CDATA[Sensores]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=694</guid>

					<description><![CDATA[<p>Aprenda como aplicar média, variância e análise de estacionariedade em sinais digitais com ESP32, usando C e ESP-IDF. Com exemplos práticos e código real.</p>
<p>The post <a href="https://mcu.tec.br/algoritimos/estacionariedade-media-e-variancia-no-dsp-com-esp32-analise-estatistica-de-sinais-em-sistemas-embarcados/">Estacionariedade, Média e Variância no DSP com ESP32: Análise Estatística de Sinais em Sistemas Embarcados</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">No universo do processamento digital de sinais (DSP), especialmente em sistemas embarcados como o ESP32, é comum lidar com sinais que possuem variações complexas no tempo. Antes de aplicar filtros, algoritmos de detecção ou métodos de diagnóstico, é essencial compreender as características estatísticas desses sinais. Dois conceitos fundamentais que ajudam a caracterizar e interpretar sinais são a <strong>média</strong> e a <strong>variância</strong>.</p>



<p class="wp-block-paragraph">A <strong>média</strong> de um sinal representa o valor central em torno do qual os dados oscilam. Em sensores analógicos — como os de temperatura, pressão, ou detecção de gás — a média pode indicar a leitura predominante durante um intervalo de tempo. Já a <strong>variância</strong> mede a dispersão dos valores em relação à média, revelando o grau de flutuação ou ruído no sinal. Altas variâncias, por exemplo, indicam instabilidade ou presença de interferência significativa.</p>



<p class="wp-block-paragraph">Esses dois indicadores são frequentemente utilizados para construir janelas de análise em tempo real. São úteis tanto na detecção de anomalias (como a mudança súbita na média) quanto na adaptação de filtros dinâmicos (como os filtros de média móvel adaptativa ou algoritmos LMS).</p>



<p class="wp-block-paragraph">Além disso, ao analisar a <strong>estabilidade</strong> estatística dos sinais — observando se seus parâmetros se mantêm constantes ao longo do tempo — introduz-se um conceito crucial: a <strong>estacionariedade</strong>. A partir dela, decidimos se é possível aplicar técnicas estatísticas convencionais ou se será necessário recorrer a abordagens mais robustas e adaptativas.</p>



<p class="wp-block-paragraph">Nesta jornada, exploraremos os fundamentos desses conceitos, sua relevância prática em sistemas embarcados com ESP32 e como implementar essas análises com código em linguagem C, usando o ESP-IDF. Essa base é indispensável para projetos de aquisição de dados, monitoramento de sensores, diagnóstico de falhas e desenvolvimento de algoritmos inteligentes embarcados.</p>



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



<h2 class="wp-block-heading">Estacionariedade: Definição e Implicações</h2>



<p class="wp-block-paragraph">No contexto do processamento de sinais, o conceito de <strong>estacionariedade</strong> é essencial para determinar qual tipo de análise estatística pode ser aplicada a um sinal ao longo do tempo. Em termos simples, um sinal é dito <strong>estacionário</strong> quando suas propriedades estatísticas — como a média, a variância e a autocorrelação — permanecem constantes ao longo do tempo. Por outro lado, sinais <strong>não estacionários</strong> apresentam mudanças nessas propriedades, refletindo alterações no ambiente, no sistema ou nas condições de medição.</p>



<p class="wp-block-paragraph">Por exemplo, um sensor de temperatura em um ambiente climatizado pode produzir um sinal aproximadamente estacionário durante um intervalo de tempo em que a temperatura se mantém estável. No entanto, esse mesmo sensor se tornará fonte de um sinal não estacionário quando o ar-condicionado é desligado ou quando uma janela é aberta, alterando as características térmicas do ambiente.</p>



<p class="wp-block-paragraph">A identificação de um sinal como estacionário ou não tem implicações diretas sobre os algoritmos que podemos utilizar. Muitos modelos clássicos de DSP, como os filtros FIR ou IIR tradicionais, assumem estacionariedade. Isso significa que, ao aplicar esses filtros em sinais não estacionários, corre-se o risco de obter resultados enganosos ou imprecisos.</p>



<p class="wp-block-paragraph">Sinais não estacionários exigem abordagens mais flexíveis e adaptativas. Técnicas como filtros adaptativos (ex: LMS – Least Mean Squares), janelas móveis com reavaliação constante de parâmetros, ou análise em domínios transformados (como Wavelet), são comumente empregadas para lidar com essa variação dinâmica.</p>



<p class="wp-block-paragraph">É importante ressaltar que a estacionariedade é uma <strong>propriedade relativa ao tempo de observação</strong>. Um sinal pode ser considerado aproximadamente estacionário em uma janela curta e não estacionário em uma janela longa. Assim, a escolha de janelas de análise e a atualização dinâmica dos parâmetros estatísticos tornam-se práticas fundamentais em sistemas embarcados, especialmente quando o processamento ocorre em tempo real, como em aplicações com ESP32.</p>



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



<h2 class="wp-block-heading">Como a Média e a Variância se Comportam em Cada Caso</h2>



<p class="wp-block-paragraph">Compreender o comportamento da média e da variância ao longo do tempo é fundamental para distinguir sinais estacionários de não estacionários. Em sinais <strong>estacionários</strong>, espera-se que a média (μ) e a variância (σ²) permaneçam aproximadamente constantes durante a janela de observação. Isso permite utilizar essas estatísticas como referências confiáveis para detecção de desvios ou anomalias. Já em sinais <strong>não estacionários</strong>, essas grandezas tendem a variar significativamente, o que exige que sejam recalculadas continuamente em janelas móveis.</p>



<p class="wp-block-paragraph">A média de um conjunto de amostras \(x_1, x_2, &#8230;, x_n\) é dada por: \(\mu = \frac{1}{n} \sum_{i=1}^{n} x_i\)</p>



<p class="wp-block-paragraph">Essa fórmula oferece uma estimativa do valor central do sinal. Em aplicações com sensores, a média pode representar a leitura &#8220;normal&#8221; ou &#8220;esperada&#8221; — como a concentração média de um gás em ambientes industriais ou o valor de corrente em um motor.</p>



<p class="wp-block-paragraph">A <strong>variância</strong> é definida como: \(a^2 = \frac{1}{n} \sum_{i=1}^{n} (x_i &#8211; \mu)^2\)</p>



<p class="wp-block-paragraph">Ela expressa o grau de dispersão das amostras em torno da média. Um aumento súbito da variância em um sistema embarcado pode indicar ruído excessivo, instabilidade de leitura ou eventos externos interferentes.</p>



<p class="wp-block-paragraph">Em sinais estacionários, se monitorarmos continuamente média e variância ao longo de janelas sucessivas, os valores devem oscilar pouco. Isso nos permite aplicar limiares fixos para detectar eventos anormais. Já em sinais não estacionários, esses valores mudam com o tempo, o que pode levar a falsos positivos se forem usados limiares estáticos.</p>



<p class="wp-block-paragraph">Para contornar esse problema, empregam-se estratégias como o uso de janelas deslizantes (sliding windows) e atualizações adaptativas da média e variância, por exemplo via <em>média exponencialmente ponderada</em> (EWMA) ou outras formas de estimadores adaptativos. Essa abordagem é ideal para sistemas embarcados como o ESP32, que precisam operar com recursos limitados e decisões em tempo real.</p>



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



<h2 class="wp-block-heading">Exemplos Práticos em C para ESP32</h2>



<p class="wp-block-paragraph">Vamos aplicar os conceitos discutidos em um sistema embarcado com ESP32, utilizando o SDK <strong>ESP-IDF</strong>. Assumimos que temos um buffer de amostras provenientes de um ADC (conversor analógico-digital), preenchido a partir de leituras periódicas.</p>



<h3 class="wp-block-heading">Cálculo da média e da variância</h3>



<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" data-code="#include <stdio.h&gt;
#include <math.h&gt;
#include <stdint.h&gt;

#define BUFFER_SIZE 64

float calcular_media(const int16_t *dados, size_t tamanho) {
    float soma = 0;
    for (size_t i = 0; i < tamanho; i++) {
        soma += dados[i];
    }
    return soma / tamanho;
}

float calcular_variancia(const int16_t *dados, size_t tamanho, float media) {
    float soma_quad = 0;
    for (size_t i = 0; i < tamanho; i++) {
        float diff = dados[i] - media;
        soma_quad += diff * diff;
    }
    return soma_quad / tamanho;
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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: #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 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">math</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">BUFFER_SIZE</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">64</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">calcular_media</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">dados</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">size_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tamanho</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">soma</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">size_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">tamanho</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">soma</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">dados</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 style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">soma</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tamanho</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">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">calcular_variancia</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">const</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">int16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9">dados</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">size_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tamanho</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">soma_quad</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">size_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">tamanho</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">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">diff</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">dados</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: #D8DEE9">media</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">soma_quad</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">diff</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">*</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">diff</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: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">soma_quad</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">/</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">tamanho</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">Essa função pode ser chamada após o preenchimento do buffer com leituras do ADC:</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" data-code="int16_t buffer_adc[BUFFER_SIZE]; // preenchido em outro trecho do código

float media = calcular_media(buffer_adc, BUFFER_SIZE);
float variancia = calcular_variancia(buffer_adc, BUFFER_SIZE, media);

printf(&quot;Média: %.2f | Variância: %.2f\n&quot;, media, variancia);
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">int16_t</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">buffer_adc</span><span style="color: #D8DEE9FF">[</span><span style="color: #D8DEE9">BUFFER_SIZE</span><span style="color: #D8DEE9FF">]</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// preenchido em outro trecho do código</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">calcular_media</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">buffer_adc</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUFFER_SIZE</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">variancia</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">calcular_variancia</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">buffer_adc</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUFFER_SIZE</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #88C0D0">printf</span><span style="color: #D8DEE9FF">(</span><span style="color: #ECEFF4">&quot;</span><span style="color: #A3BE8C">Média: %.2f | Variância: %.2f</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">media</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">variancia</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<h3 class="wp-block-heading">Detecção de mudança estatística (simples)</h3>



<p class="wp-block-paragraph">Vamos agora detectar uma <strong>mudança significativa</strong> na média do sinal — o que pode indicar eventos como interferência, presença de objeto/sujeito em sensores de proximidade ou até falhas.</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" data-code="bool detectar_mudanca_de_media(float media_anterior, float media_atual, float limiar) {
    float diferenca = fabs(media_atual - media_anterior);
    return diferenca &gt; limiar;
}
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">detectar_mudanca_de_media</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media_anterior</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media_atual</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">limiar</span><span style="color: #D8DEE9FF">) </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">diferenca</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">fabs</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">media_atual</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media_anterior</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">diferenca</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">limiar</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">Uso:</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" data-code="static float media_anterior = 0;
float media_atual = calcular_media(buffer_adc, BUFFER_SIZE);

if (detectar_mudanca_de_media(media_anterior, media_atual, 50.0)) {
    printf(&quot;Mudança detectada no sinal!\n&quot;);
}

media_anterior = media_atual;
" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><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">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media_anterior</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: #D8DEE9">float</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media_atual</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">calcular_media</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">buffer_adc</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">BUFFER_SIZE</span><span style="color: #D8DEE9FF">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> (</span><span style="color: #88C0D0">detectar_mudanca_de_media</span><span style="color: #D8DEE9FF">(</span><span style="color: #D8DEE9">media_anterior</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media_atual</span><span style="color: #ECEFF4">,</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">50.0</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">Mudança detectada no sinal!</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: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #D8DEE9">media_anterior</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #D8DEE9">media_atual</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span></code></pre></div>



<p class="wp-block-paragraph">Esse tipo de monitoramento pode ser feito periodicamente em uma <strong>task do FreeRTOS</strong> para obter respostas em tempo real.</p>



<h3 class="wp-block-heading">Observações de uso</h3>



<ul class="wp-block-list">
<li>Para aplicações com janelas deslizantes, o buffer pode ser tratado como um anel (ring buffer).</li>



<li>A variância pode ser usada para acionar um alarme de ruído ou instabilidade.</li>



<li>Para maior eficiência, pode-se usar algoritmos que calculam média e variância de forma incremental (<em>online algorithms</em>), sem a necessidade de armazenar todo o buffer.</li>



<li>Se o ESP32 estiver utilizando múltiplos núcleos ou FreeRTOS, essas análises podem ser feitas em tarefas dedicadas.</li>
</ul>



<p class="wp-block-paragraph">Perfeito. Abaixo segue a seção final do artigo:</p>



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



<h2 class="wp-block-heading">Conclusão: Boas Práticas para Análise de Sinais em Sistemas Embarcados</h2>



<p class="wp-block-paragraph">A análise estatística de sinais em sistemas embarcados não é apenas uma questão teórica — ela define o sucesso de aplicações que dependem de confiabilidade, robustez e capacidade de adaptação em tempo real. Compreender os conceitos de <strong>média</strong>, <strong>variância</strong> e <strong>estacionariedade</strong> permite ao engenheiro implementar diagnósticos inteligentes, detectar falhas e tomar decisões com base em dados consistentes.</p>



<p class="wp-block-paragraph">Como vimos, sinais <strong>estacionários</strong> permitem a aplicação de filtros tradicionais e limiares fixos. Já sinais <strong>não estacionários</strong> exigem algoritmos adaptativos e análises por janelas móveis ou métodos estatísticos mais elaborados. Essa distinção é fundamental ao projetar sistemas embarcados em ambientes ruidosos ou em constante mudança, como sistemas de aquisição em campo, dispositivos IoT e sensores industriais.</p>



<p class="wp-block-paragraph">Na prática com o ESP32, esses conceitos podem ser implementados de maneira eficiente, mesmo em aplicações com restrições de processamento. O uso de tarefas paralelas com <strong>FreeRTOS</strong> permite, por exemplo, que a aquisição de dados ocorra em uma task enquanto a análise estatística é feita em outra, promovendo paralelismo e maior responsividade do sistema. Além disso, a adoção de buffers circulares, técnicas de média exponencial ponderada e filtros adaptativos complementa as estratégias de análise robusta.</p>



<p class="wp-block-paragraph">Portanto, ao lidar com sinais em sistemas embarcados, recomenda-se:</p>



<ul class="wp-block-list">
<li><strong>Sempre avaliar a estacionariedade do sinal</strong> antes de aplicar filtros ou modelos estatísticos.</li>



<li><strong>Utilizar janelas móveis</strong> para reavaliar média e variância de forma contínua.</li>



<li><strong>Aproveitar o FreeRTOS</strong> para dividir responsabilidades entre tarefas e evitar bloqueios na aquisição.</li>



<li><strong>Analisar eventos de mudança de média ou variância</strong> como potenciais indícios de falha ou eventos externos.</li>



<li><strong>Ajustar limiares dinamicamente</strong> conforme o contexto de operação e tipo de sensor.</li>
</ul>



<p class="wp-block-paragraph">Com essas práticas, o engenheiro pode garantir maior robustez, previsibilidade e inteligência aos sistemas baseados em ESP32, mesmo em cenários críticos de operação.</p><p>The post <a href="https://mcu.tec.br/algoritimos/estacionariedade-media-e-variancia-no-dsp-com-esp32-analise-estatistica-de-sinais-em-sistemas-embarcados/">Estacionariedade, Média e Variância no DSP com ESP32: Análise Estatística de Sinais em Sistemas Embarcados</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">694</post-id>	</item>
		<item>
		<title>Catóptrica, Dioptria e Eletrônica Embarcada na Radiologia Digital: Fundamentos e Aplicações</title>
		<link>https://mcu.tec.br/sensores/catoptrica-dioptria-e-eletronica-embarcada-na-radiologia-digital-fundamentos-e-aplicacoes/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=catoptrica-dioptria-e-eletronica-embarcada-na-radiologia-digital-fundamentos-e-aplicacoes</link>
		
		<dc:creator><![CDATA[Carlos Delfino]]></dc:creator>
		<pubDate>Fri, 08 Aug 2025 11:24:27 +0000</pubDate>
				<category><![CDATA[Sensores]]></category>
		<category><![CDATA[catóptrica]]></category>
		<category><![CDATA[cintiladores]]></category>
		<category><![CDATA[dioptria]]></category>
		<category><![CDATA[eletrônica embarcada]]></category>
		<category><![CDATA[espelhos galvanométricos]]></category>
		<category><![CDATA[espelhos ópticos]]></category>
		<category><![CDATA[fluoroscopia digital]]></category>
		<category><![CDATA[foco automático]]></category>
		<category><![CDATA[FPGA em processamento de imagem]]></category>
		<category><![CDATA[inspeção industrial por imagem]]></category>
		<category><![CDATA[lentes de foco líquido]]></category>
		<category><![CDATA[lentes focais]]></category>
		<category><![CDATA[microcontroladores STM32]]></category>
		<category><![CDATA[radiologia digital]]></category>
		<category><![CDATA[sensores CCD]]></category>
		<category><![CDATA[sensores CMOS]]></category>
		<category><![CDATA[sistemas de visão embarcados]]></category>
		<category><![CDATA[sistemas ópticos]]></category>
		<category><![CDATA[tecnologia médica avançada]]></category>
		<category><![CDATA[tomografia CBCT]]></category>
		<guid isPermaLink="false">https://mcu.tec.br/?p=713</guid>

					<description><![CDATA[<p>Entenda como princípios de reflexão (catóptrica) e refração (dioptria) se integram à eletrônica embarcada para criar sistemas avançados de radiologia digital, unindo óptica e processamento de sinais em aplicações médicas e industriais.</p>
<p>The post <a href="https://mcu.tec.br/sensores/catoptrica-dioptria-e-eletronica-embarcada-na-radiologia-digital-fundamentos-e-aplicacoes/">Catóptrica, Dioptria e Eletrônica Embarcada na Radiologia Digital: Fundamentos e Aplicações</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">A convergência entre óptica e eletrônica embarcada tem impulsionado avanços significativos em áreas como diagnóstico médico, inspeção industrial e sistemas de visão de alta precisão. Neste artigo, exploramos de forma aprofundada quatro pilares técnicos interconectados: <strong>catóptrica</strong>, que estuda a reflexão da luz e fundamenta sistemas de detecção baseados em espelhos e superfícies refletoras; <strong>dioptria</strong>, conceito central na determinação da potência óptica de lentes e no controle da refração para obtenção de imagens nítidas; <strong>eletrônica embarcada</strong>, responsável pela aquisição, processamento e controle de sinais provenientes de sensores ópticos; e <strong>radiologia digital</strong>, tecnologia que integra elementos ópticos, sensores e processamento eletrônico para a visualização e análise de estruturas internas, com destaque para aplicações em tempo real.</p>



<p class="wp-block-paragraph">A <strong>catóptrica</strong> fornece o arcabouço teórico para projetar sistemas que redirecionam feixes luminosos ou de radiação convertida, maximizando eficiência e precisão na captura da informação. A <strong>dioptria</strong>, por sua vez, estabelece quantitativamente como lentes moldam e focam a luz, permitindo o ajuste fino de sistemas ópticos para aplicações como microscopia, tomografia computadorizada por feixe cônico (CBCT) e câmeras embarcadas. Esses princípios ópticos, quando aliados à <strong>eletrônica embarcada</strong>, possibilitam a integração de sensores CCD/CMOS, fotodiodos, tubos fotomultiplicadores e módulos de varredura a microcontroladores e FPGAs, criando sistemas autônomos de medição e visualização. Por fim, a <strong>radiologia digital</strong> exemplifica a aplicação prática dessa integração, combinando detecção baseada em cintiladores, espelhos de varredura e algoritmos de reconstrução para fornecer imagens diagnósticas de alta definição em tempo real.</p>



<p class="wp-block-paragraph">Ao longo deste artigo, cada seção irá aprofundar-se nos aspectos teóricos, matemáticos e práticos de cada tema, sempre destacando como eles se conectam na construção de sistemas avançados para engenharia médica e industrial. Serão apresentadas equações fundamentais, diagramas conceituais e exemplos concretos que ilustram a transição da teoria óptica para soluções embarcadas e de radiologia digital, tornando este material uma referência abrangente para engenheiros, técnicos e estudantes avançados interessados na interseção entre óptica e eletrônica aplicada.</p>



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



<h2 class="wp-block-heading"><strong>Introdução à Catóptrica – Teoria e Aplicações</strong></h2>



<p class="wp-block-paragraph">A <strong>catóptrica</strong> é o ramo da óptica dedicado ao estudo da <strong>reflexão da luz</strong>, fenômeno que ocorre quando uma onda luminosa incide sobre uma superfície e retorna ao meio de origem. Diferentemente da dioptria, que trata da refração e do comportamento da luz ao atravessar diferentes meios, a catóptrica foca na interação com superfícies refletoras, como espelhos planos, côncavos e convexos, fundamentais em instrumentação óptica.</p>



<p class="wp-block-paragraph">O princípio básico que rege a catóptrica é a <strong>Lei da Reflexão</strong>, expressa matematicamente como: \(\theta_i = \theta_r\)</p>



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



<ul class="wp-block-list">
<li>θi\theta_i é o ângulo de incidência, medido entre o raio incidente e a normal à superfície;</li>



<li>θr\theta_r é o ângulo de reflexão, medido entre o raio refletido e a normal à superfície.</li>
</ul>



<p class="wp-block-paragraph">Em termos vetoriais, considerando um vetor de incidência \(vec{I}\), a normal à superfície \(\vec{N}\) (unitária) e o vetor de reflexão \(\vec{R}\), a relação é dada por: \[\vec{R} = \vec{I} &#8211; 2 (\vec{I} \cdot \vec{N}) \vec{N}\]



<p class="wp-block-paragraph">Essa formulação é particularmente útil quando se modela a trajetória da luz em softwares de simulação óptica ou se implementa o cálculo em firmware embarcado para controle de sistemas de varredura com espelhos móveis.</p>



<h3 class="wp-block-heading">Superfícies Refletoras e Propriedades Ópticas</h3>



<p class="wp-block-paragraph">A geometria da superfície refletora define o comportamento do feixe luminoso:</p>



<ul class="wp-block-list">
<li><strong>Espelho plano</strong>: mantém o tamanho e a forma do objeto, inverte lateralmente a imagem.</li>



<li><strong>Espelho côncavo</strong>: concentra os raios refletidos em um ponto focal, permitindo aumento de intensidade e foco — ideal para coleta de radiação em sistemas de baixa luminosidade.</li>



<li><strong>Espelho convexo</strong>: diverge os raios, ampliando o campo de visão — útil em sistemas de monitoramento panorâmico.</li>
</ul>



<p class="wp-block-paragraph">A distância focal ff de um espelho esférico relaciona-se com seu raio de curvatura RR por: \[\frac{R}{2}\]



<p class="wp-block-paragraph">Essa relação é explorada em sistemas embarcados com alinhamento óptico automático, onde microcontroladores ajustam mecanicamente a posição do espelho para maximizar a captação do sinal refletido.</p>



<h3 class="wp-block-heading">Integração com Sistemas Eletrônicos</h3>



<p class="wp-block-paragraph">Em aplicações modernas, princípios catóptricos são combinados com <strong>sensores fotossensíveis</strong> e <strong>atuadores eletromecânicos</strong>. Um exemplo comum é o uso de <strong>espelhos galvanométricos</strong> ou <strong>espelhos MEMS</strong> (Micro-Electro-Mechanical Systems) para varrer feixes de laser em dispositivos como:</p>



<ul class="wp-block-list">
<li><strong>LIDARs</strong> para mapeamento 3D;</li>



<li><strong>Sistemas de varredura de raios X em tempo real</strong>;</li>



<li><strong>Inspeção industrial por feixe refletido</strong>.</li>
</ul>



<p class="wp-block-paragraph">O microcontrolador ou FPGA atua como núcleo de controle, sincronizando o ângulo de espelho com a leitura dos sensores ópticos, garantindo que cada ponto refletido seja correlacionado corretamente com sua posição espacial.</p>



<h3 class="wp-block-heading">Aplicações Médicas e Industriais</h3>



<p class="wp-block-paragraph">Na área médica, a catóptrica está presente em <strong>fluoroscopia digital</strong> e <strong>tomografia odontológica</strong>, onde espelhos direcionam radiação visível gerada por cintiladores para câmeras de alta sensibilidade. Na indústria, encontra aplicação em <strong>sistemas de inspeção não destrutiva</strong>, <strong>alinhamento a laser</strong> e <strong>metrologia de precisão</strong>, onde a estabilidade e precisão angular do espelho determinam a qualidade da medição.</p>



<p class="wp-block-paragraph">Vamos então para a próxima parte, <strong>Fundamentos de Dioptria – cálculo e uso em sistemas ópticos</strong>, mantendo a abordagem técnica e já conectando aos sistemas embarcados.</p>



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



<h2 class="wp-block-heading"><strong>Fundamentos de Dioptria – Cálculo e Uso em Sistemas Ópticos</strong></h2>



<p class="wp-block-paragraph">A <strong>dioptria</strong> é uma unidade de medida que expressa a potência óptica de uma lente ou sistema de lentes. Diferente da catóptrica, que se baseia na reflexão, a dioptria trata do <strong>fenômeno da refração</strong>, ou seja, a mudança de direção da luz ao atravessar interfaces entre meios com diferentes índices de refração.</p>



<p class="wp-block-paragraph">A potência óptica DD é definida como o inverso da distância focal ff, medida em metros: D=1fD = \frac{1}{f}</p>



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



<ul class="wp-block-list">
<li>DD é a potência óptica em dioptrias (D),</li>



<li>ff é a distância focal em metros.</li>
</ul>



<p class="wp-block-paragraph">Por exemplo, uma lente com \(f = 0{,}5 \, \text{m}\) possui: \[D = \frac{1}{0{,}5} = 2 \, \text{D}\]



<p class="wp-block-paragraph">Essa definição é fundamental em oftalmologia, microscopia, câmeras e sistemas de medição óptica. Em aplicações de engenharia, o ajuste da dioptria permite adaptar o foco de um sistema para diferentes distâncias de observação ou condições de luminosidade.</p>



<h3 class="wp-block-heading">Óptica Geométrica e Lei de Snell</h3>



<p class="wp-block-paragraph">O comportamento refrativo que dá origem à dioptria pode ser modelado pela <strong>Lei de Snell</strong>: \[n_1 \sin \theta_1 = n_2 \sin \theta_2\]



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



<ul class="wp-block-list">
<li>\(n_1\) e \(n_2\) são os índices de refração dos meios de incidência e transmissão;</li>



<li>\\theta_1\) e \(\theta_2\) são os ângulos de incidência e refração, respectivamente.</li>
</ul>



<p class="wp-block-paragraph">Essa equação é utilizada para projetar lentes e sistemas ópticos que direcionam a luz de forma precisa sobre sensores, garantindo a melhor resolução possível.</p>



<h3 class="wp-block-heading">Associação de Lentes</h3>



<p class="wp-block-paragraph">Em sistemas embarcados que utilizam múltiplas lentes, como microscópios digitais e câmeras industriais, a potência óptica total DtD_t é a soma das potências individuais: \[D_t = D_1 + D_2 + \dots + D_n\]



<p class="wp-block-paragraph">Isso permite projetar sistemas modulares, onde lentes intercambiáveis são combinadas para alcançar diferentes distâncias focais.</p>



<h3 class="wp-block-heading">Integração com Eletrônica Embarcada</h3>



<p class="wp-block-paragraph">Nos sistemas ópticos embarcados, a dioptria é ajustada dinamicamente para manter o foco, especialmente em dispositivos que realizam <strong>autofoco</strong>. Exemplos:</p>



<ul class="wp-block-list">
<li><strong>Câmeras CMOS com atuadores de foco</strong>: motores de passo ou piezelétricos deslocam a lente, alterando ff e, portanto, a dioptria.</li>



<li><strong>Sistemas de inspeção industrial</strong>: ajustam a lente para compensar variações na altura do objeto analisado.</li>



<li><strong>Equipamentos médicos de imagem</strong>: adaptam a potência óptica para diferentes profundidades de campo, como em exames intraorais e oftálmicos.</li>
</ul>



<p class="wp-block-paragraph">O controle embarcado geralmente envolve sensores de posição da lente, drivers de motor e algoritmos de maximização de contraste ou detecção de bordas para determinar o ponto ótimo de foco.</p>



<h3 class="wp-block-heading">Aplicações Médicas e Industriais</h3>



<ul class="wp-block-list">
<li><strong>Oftalmologia</strong>: medição e compensação de dioptria para correção visual.</li>



<li><strong>Microscopia digital</strong>: ajuste dinâmico do foco para diferentes camadas de amostra.</li>



<li><strong>Tomografia óptica coerente (OCT)</strong>: utiliza ajustes precisos de dioptria para penetrar diferentes profundidades de tecido.</li>



<li><strong>Inspeção robótica</strong>: robôs industriais equipados com câmeras que ajustam foco conforme a distância do objeto.</li>
</ul>



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



<h2 class="wp-block-heading"><strong>Integração com Eletrônica Embarcada – Sensores, Circuitos e Processamento de Sinais</strong></h2>



<p class="wp-block-paragraph">A junção dos princípios ópticos da <strong>catóptrica</strong> e da <strong>dioptria</strong> com a <strong>eletrônica embarcada</strong> é o que transforma fenômenos físicos da luz em informação digital utilizável. Essa integração é a base de dispositivos modernos de inspeção industrial, diagnóstico médico e sistemas de visão embarcados.</p>



<p class="wp-block-paragraph">O núcleo dessa interligação reside em três elementos: <strong>captura óptica</strong>, <strong>conversão eletro-óptica</strong> e <strong>processamento embarcado</strong>.</p>



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



<h3 class="wp-block-heading">Captura Óptica e Sensores</h3>



<p class="wp-block-paragraph">Na etapa inicial, a radiação luminosa ou convertida (como no caso de raios X transformados em luz visível via cintiladores) precisa ser direcionada corretamente.<br>A <strong>catóptrica</strong> fornece o alinhamento e a orientação do feixe através de espelhos fixos ou móveis, enquanto a <strong>dioptria</strong> garante que esse feixe esteja focado no plano sensível do detector.</p>



<p class="wp-block-paragraph">Os sensores mais comuns são:</p>



<ul class="wp-block-list">
<li><strong>CCD (Charge-Coupled Device)</strong> – com alta precisão na captação de luz, frequentemente usado em câmeras científicas e médicas.</li>



<li><strong>CMOS (Complementary Metal-Oxide-Semiconductor)</strong> – mais econômicos e integráveis, usados em câmeras industriais embarcadas.</li>



<li><strong>Fotodiodos e Fototransistores</strong> – para detecção pontual de intensidade luminosa.</li>



<li><strong>Tubos Fotomultiplicadores (PMTs)</strong> – ainda usados em sistemas de baixa luminosidade ou com radiação de alta energia, onde se exige grande amplificação do sinal.</li>
</ul>



<p class="wp-block-paragraph">A escolha do sensor impacta diretamente a resolução, a sensibilidade e a taxa de amostragem do sistema embarcado.</p>



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



<h3 class="wp-block-heading">Conversão Eletro-Óptica e Circuitos de Condicionamento</h3>



<p class="wp-block-paragraph">Os sinais ópticos detectados precisam ser convertidos em sinais elétricos adequados para digitalização. Essa etapa envolve:</p>



<ul class="wp-block-list">
<li><strong>Pré-amplificação</strong> – utilizando amplificadores de transimpedância (TIA) para converter corrente foto-gerada em tensão.</li>



<li><strong>Filtragem analógica</strong> – para reduzir ruídos e eliminar componentes de alta frequência indesejadas.</li>



<li><strong>Conversão Analógico-Digital (ADC)</strong> – geralmente de alta resolução (12 a 16 bits) e taxas ajustadas à velocidade da varredura óptica.</li>
</ul>



<p class="wp-block-paragraph">O projeto eletrônico deve levar em conta:</p>



<ul class="wp-block-list">
<li><strong>Impedância de entrada do sensor</strong> (particularmente alta em CCDs e PMTs).</li>



<li><strong>Proteção contra sobrecarga luminosa</strong> (que pode saturar ou danificar sensores).</li>



<li><strong>Sincronização com atuadores</strong> (espelhos galvanométricos, motores de foco, filtros rotativos).</li>
</ul>



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



<h3 class="wp-block-heading">Processamento Embarcado</h3>



<p class="wp-block-paragraph">Com o sinal digitalizado, entra em ação o núcleo computacional do sistema, que pode ser um:</p>



<ul class="wp-block-list">
<li><strong>Microcontrolador (MCU)</strong> – como STM32, ESP32 ou RP2040, para sistemas compactos.</li>



<li><strong>FPGA</strong> – para aplicações que exigem processamento paralelo e alta taxa de dados, como reconstrução de imagens médicas em tempo real.</li>



<li><strong>SoC com GPU integrada</strong> – usado em sistemas de visão computacional com processamento local.</li>
</ul>



<p class="wp-block-paragraph">As tarefas típicas do firmware incluem:</p>



<ul class="wp-block-list">
<li>Correção geométrica da imagem (compensando distorções de espelho ou lente).</li>



<li>Ajuste dinâmico de foco via controle de dioptria (motores de passo, atuadores piezelétricos).</li>



<li>Sincronização da varredura catóptrica com a leitura do sensor.</li>



<li>Processamento de imagem: redução de ruído, realce de contraste, reconstrução volumétrica (no caso de tomografia).</li>
</ul>



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



<h3 class="wp-block-heading">Exemplo Integrado</h3>



<p class="wp-block-paragraph">Um sistema de <strong>fluoroscopia odontológica digital</strong> pode conter:</p>



<ol class="wp-block-list">
<li>Um <strong>cintilador</strong> que converte raios X em luz visível.</li>



<li>Um <strong>espelho côncavo</strong> que concentra essa luz em um sensor CCD.</li>



<li>Um <strong>conjunto de lentes</strong> ajustáveis em dioptria para manter o foco no CCD.</li>



<li>Um <strong>pré-amplificador</strong> de baixa corrente e ADC de 14 bits.</li>



<li>Um <strong>STM32H7</strong> controlando espelhos galvanométricos e processando as imagens em tempo real para exibição no monitor.</li>
</ol>



<p class="wp-block-paragraph">Esse exemplo demonstra como princípios de reflexão (catóptrica) e refração (dioptria) se traduzem em decisões práticas de projeto eletrônico e firmware.</p>



<h2 class="wp-block-heading"><strong>Radiologia Digital – Fundamentos Técnicos e Integração Óptica-Eletrônica</strong></h2>



<p class="wp-block-paragraph">A <strong>radiologia digital</strong> é a evolução natural dos sistemas radiográficos convencionais, substituindo o filme fotográfico por detectores eletrônicos capazes de converter radiação em sinais digitais processáveis. Ela se beneficia diretamente dos princípios da <strong>catóptrica</strong> e da <strong>dioptria</strong>, pois a captura e a formação da imagem dependem de <strong>espelhos e lentes</strong> para conduzir, concentrar e focar a luz ou radiação convertida antes da detecção eletrônica.</p>



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



<h3 class="wp-block-heading">Fundamentos da Aquisição Digital</h3>



<p class="wp-block-paragraph">O processo inicia-se com a emissão de radiação ionizante, normalmente <strong>raios X</strong>. Ao atravessar o objeto ou paciente, essa radiação interage de forma diferenciada com cada tecido ou material, produzindo um <strong>padrão de atenuação</strong> característico.<br>Para transformar esse padrão em imagem digital, é necessária a conversão da radiação em sinais ópticos ou elétricos.</p>



<p class="wp-block-paragraph">Existem dois métodos principais:</p>



<ol class="wp-block-list">
<li><strong>Conversão Indireta</strong> – A radiação atinge um <strong>cintilador</strong> (ex.: CsI:Tl – iodeto de césio dopado com tálio) que converte fótons de raios X em fótons de luz visível.<br>Essa luz é então guiada por <strong>espelhos (catóptrica)</strong> e focalizada por <strong>lentes (dioptria)</strong> sobre um sensor CCD/CMOS ou tubo fotomultiplicador.<br>Esse método é comum em fluoroscopia e tomografia por feixe cônico (CBCT).</li>



<li><strong>Conversão Direta</strong> – Um detector semicondutor (ex.: selênio amorfo) converte diretamente a radiação em carga elétrica, que é lida por um circuito de leitura.<br>Embora não use catóptrica ou dioptria na etapa de detecção, ainda pode utilizá-las no sistema auxiliar de alinhamento e visualização.</li>
</ol>



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



<h3 class="wp-block-heading">Integração Óptica-Eletrônica</h3>



<p class="wp-block-paragraph">Nos sistemas de conversão indireta, a precisão óptica é crucial:</p>



<ul class="wp-block-list">
<li><strong>Espelhos côncavos</strong> concentram a luz do cintilador no sensor, maximizando a sensibilidade.</li>



<li><strong>Lentes de distância focal calculada</strong> (em dioptrias) ajustam a nitidez e o tamanho da imagem no sensor.</li>



<li><strong>Espelhos galvanométricos ou MEMS</strong> permitem a varredura controlada, especialmente em equipamentos portáteis ou intraorais.</li>
</ul>



<p class="wp-block-paragraph">A eletrônica embarcada nesse contexto deve:</p>



<ul class="wp-block-list">
<li>Sincronizar a varredura mecânica dos espelhos com a leitura dos pixels do sensor.</li>



<li>Controlar a abertura e a exposição, evitando saturação do detector.</li>



<li>Processar as imagens em tempo real, aplicando correções de distorção e algoritmos de realce.</li>
</ul>



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



<h3 class="wp-block-heading">Processamento e Exibição</h3>



<p class="wp-block-paragraph">Após a digitalização, o sinal é processado por <strong>MCUs de alto desempenho, FPGAs ou sistemas híbridos SoC</strong>, onde podem ser aplicadas técnicas como:</p>



<ul class="wp-block-list">
<li><strong>Filtragem espacial</strong> para redução de ruído quântico.</li>



<li><strong>Equalização de histograma</strong> para melhor contraste.</li>



<li><strong>Reconstrução volumétrica 3D</strong> no caso de tomografia.</li>
</ul>



<p class="wp-block-paragraph">O resultado final é exibido em monitores médicos calibrados, permitindo diagnósticos imediatos e precisos.</p>



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



<h3 class="wp-block-heading">Aplicações e Tendências</h3>



<ul class="wp-block-list">
<li><strong>Odontologia</strong>: sistemas CBCT e fluoroscopia digital para diagnóstico em tempo real.</li>



<li><strong>Medicina Intervencionista</strong>: guiamento de procedimentos por fluoroscopia.</li>



<li><strong>Inspeção Industrial</strong>: detecção de defeitos internos em peças metálicas ou compósitos.</li>



<li><strong>Segurança</strong>: scanners de bagagens e carga com reconstrução digital.</li>
</ul>



<p class="wp-block-paragraph">As tendências atuais apontam para:</p>



<ul class="wp-block-list">
<li>Miniaturização de detectores e sistemas ópticos.</li>



<li>Uso de <strong>inteligência artificial embarcada</strong> para interpretação automática de imagens.</li>



<li>Sistemas <strong>portáteis</strong> com conectividade sem fio para integração em redes hospitalares e industriais.</li>
</ul>



<h2 class="wp-block-heading"><strong>Conclusão – Perspectivas e Tendências Futuras</strong></h2>



<p class="wp-block-paragraph">A interseção entre <strong>catóptrica</strong>, <strong>dioptria</strong>, <strong>eletrônica embarcada</strong> e <strong>radiologia digital</strong> representa um campo em constante evolução, impulsionado pela demanda por sistemas de imagem mais precisos, rápidos e compactos. Ao longo deste artigo, vimos que a catóptrica, ao tratar da reflexão controlada da luz, fornece a base para redirecionar e alinhar feixes ópticos com alta precisão. A dioptria, por sua vez, atua no ajuste e focalização desses feixes, garantindo que a energia luminosa ou convertida seja direcionada ao sensor na melhor condição possível para captura.</p>



<p class="wp-block-paragraph">Na prática, esses dois domínios da óptica não operam isoladamente: eles são parte essencial do caminho da luz até os sensores, interagindo diretamente com os módulos eletrônicos que realizam a conversão eletro-óptica, a amplificação, a digitalização e o processamento de sinais. A eletrônica embarcada, com microcontroladores, FPGAs e SoCs especializados, não apenas executa essas tarefas, mas também implementa algoritmos de correção, reconstrução e análise de imagens. Na radiologia digital, essa integração se traduz em sistemas capazes de fornecer diagnósticos quase instantâneos, com qualidade superior à obtida por métodos analógicos.</p>



<p class="wp-block-paragraph">O avanço tecnológico projeta um futuro em que esses sistemas serão cada vez mais <strong>portáteis, energicamente eficientes e inteligentes</strong>. Já se observa a adoção de <strong>IA embarcada</strong> para detecção automática de anomalias em exames, a substituição de espelhos mecânicos por <strong>espelhos MEMS</strong> para varredura ultrarrápida, e a utilização de <strong>lentes de foco líquido</strong> que alteram dioptria sem partes móveis. No campo da radiologia, há um movimento para integrar sensores de alta sensibilidade diretamente em placas de leitura compactas, reduzindo etapas ópticas e simplificando o alinhamento.</p>



<p class="wp-block-paragraph">Para engenheiros, técnicos e pesquisadores, compreender profundamente a física da reflexão e refração, o cálculo e aplicação de dioptrias, e a arquitetura de sistemas embarcados para processamento óptico não é apenas um diferencial — é uma necessidade estratégica para projetar a próxima geração de dispositivos médicos, industriais e científicos. A engenharia do futuro, nesse contexto, será marcada pela <strong>convergência total entre óptica e eletrônica</strong>, onde a fronteira entre o caminho da luz e o caminho do sinal digital será cada vez mais tênue, mas tecnicamente mais sofisticada.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="1024" height="683" src="https://mcu.tec.br/wp-content/uploads/2025/08/image-13.png" alt="" class="wp-image-714" srcset="https://mcu.tec.br/wp-content/uploads/2025/08/image-13.png 1024w, https://mcu.tec.br/wp-content/uploads/2025/08/image-13-300x200.png 300w, https://mcu.tec.br/wp-content/uploads/2025/08/image-13-768x512.png 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure><p>The post <a href="https://mcu.tec.br/sensores/catoptrica-dioptria-e-eletronica-embarcada-na-radiologia-digital-fundamentos-e-aplicacoes/">Catóptrica, Dioptria e Eletrônica Embarcada na Radiologia Digital: Fundamentos e Aplicações</a> first appeared on <a href="https://mcu.tec.br">MCU & FPGA</a>.</p>]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">713</post-id>	</item>
	</channel>
</rss>
