<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>Alaisdair&#39;s Site</title>
<link>https://awest.adegator.net/</link>
<atom:link href="https://awest.adegator.net/index.xml" rel="self" type="application/rss+xml"/>
<description>A blog where I share my passion for programming and electronics</description>
<generator>quarto-1.9.36</generator>
<lastBuildDate>Tue, 07 Apr 2026 14:00:00 GMT</lastBuildDate>
<item>
  <title>ATtiny85 &amp; TSSP4038 IR Barrier</title>
  <dc:creator>Alaisdair West</dc:creator>
  <link>https://awest.adegator.net/posts/attiny-ir-barrier/</link>
  <description><![CDATA[ 





<p>I recently bought some HO &amp; OO scale DC model trains, I run them on 3 separate loops and there are level crossings where one loop crosses two others. I thought it would be fun to try and automate my railway to prevent collisions and even add stops at stations. Fundamentally, I need a way to detect the presence of a train and I don’t want to make any modifications to the trains themselves. This is where infrared (IR) light presence detection comes in.</p>
<section id="ir-presence-detection-techniques" class="level1">
<h1>IR Presence Detection Techniques</h1>
<p>Presence detection is used when our only concern is whether an object is in a specified area or not. We don’t care how far away it is or if it is moving. There are two common methods for presence detection using IR light.</p>
<p>The first method is by reflection, in this configuration the IR emitter is located adjacent to the receiver. When something is in front of the sensor the light is reflected from the emitter onto the receiver, as depicted in Figure&nbsp;1. Common examples of this include automatic hand dryers and soap dispensers used in public bathrooms. <span class="citation" data-cites="schafer2024">Schäfer (2024)</span> is a handy application note from VISHAY which discusses these applications and how to design your own. While simple to construct, some tuning is required to control the detection distance.</p>
<div id="fig-reflection" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-reflection-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://awest.adegator.net/posts/attiny-ir-barrier/reflection.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-reflection-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: Reflective presence sensor, image from <span class="citation" data-cites="schafer2024">Schäfer (2024)</span>.
</figcaption>
</figure>
</div>
<p>The second method is to create an IR Barrier or break-beam sensor. Unlike the reflection sensor, the emitter and receiver are set up to face each other. As the name suggests we detect presence when the continuous beam between the emitter and receiver is broken. This is the opposite logic to the reflection setup, we’re interested in when there is no light. These are useful for applications like burglar alarms <span class="citation" data-cites="lightbarriers">(Vishay 2024)</span>.</p>
<p>Neither of these methods is generally superior and you should always consider what is appropriate for your application. From preliminary testing with no-name IR LEDs and TSSP4038 I found that the reflection setup had too much range. In a small model railway setup, precise control over the detection area is important. As the title suggests I decided to use an IR barrier, but the code I use here can easily be adapted for reflection.</p>
</section>
<section id="choosing-an-ir-detector" class="level1">
<h1>Choosing an IR Detector</h1>
<p>When choosing your IR receiver it’s best to avoid sensors with automatic gain control (AGC). IR receivers with AGC (such as the TSOP series or the common VS1838B) are designed for remote control systems (like TV remotes) and filter out continuous beams. It is possible to use these sensors but it requires complex emitter-receiver code to time pulses <span class="citation" data-cites="vs1838B_barrier">(see Pons 2025)</span>. The TSSP series lack AGC and are designed for these applications.</p>
<p>I also recommend getting a receiver that requires a modulated signal. The TSSP4038 I’m using requires 38kHz modulation, meaning that the IR emitter must be turned on and off at 38,000 times per second. By requiring a modulated signal external sources of IR can be ignored (like the Sun) <span class="citation" data-cites="vs1838B_barrier">(Pons 2025)</span>.</p>
</section>
<section id="the-setup" class="level1">
<h1>The setup</h1>
<p>As a simple project I made a simple IR barrier that would turn on an LED when blocked, this allowed me to experiment with different trains and lighting conditions.</p>
<p>The full code and schematic are in my <a href="https://codeberg.org/awest03/simple-ir-barrier">Codeberg</a> repository for the project, but I will go through it all here.</p>
<div id="fig-schematic" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-schematic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://awest.adegator.net/posts/attiny-ir-barrier/schematic.svg" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-schematic-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;2: Schematic for the ATtiny85 &amp; TSSP4038 IR Barrier
</figcaption>
</figure>
</div>
<p>Of particular interest in Figure&nbsp;2 are C1 and R1 which act as a low-pass noise filter on the receiver, without it I found the receiver output to be useless.</p>
<p>C2 was needed to smooth the power supply for the ATtiny85 and filter the electrical noise from the railway. Without it, I found that the ATtiny85 would be constantly switching off and on.</p>
</section>
<section id="the-code" class="level1">
<h1>The code</h1>
<p>In this setup the ATtiny85 has two tasks, it needs to control both the emitter and receiver ends of the barrier. In setups requiring longer range these tasks would be handled by separate circuits as running wires between each would be impractical.</p>
<section id="emission" class="level2">
<h2 class="anchored" data-anchor-id="emission">Emission</h2>
<p>To generate the required 38kHz square wave signal I used the ATtiny85’s Timer0 peripheral in CTC mode. In CTC mode Timer0 can be configured to flip an output pin once the relevant comparison register overflows. This is limited to two output pins OC0A and OC0B, with corresponding registers OCR0A and OCR0B. I only need one of them for this project and chose output A which is shared with PB0.</p>
<p>The trick now is finding the right value for OCR0A, but luckily it’s not that hard thanks to page 72 of the ATtiny85 datasheet <span class="citation" data-cites="attiny85_datasheet">(Atmel 2013)</span>. <span id="eq-freq"><img src="https://latex.codecogs.com/png.latex?%0Af_%5Ctext%7BOC0A%7D%20=%20%5Cfrac%7Bf_%5Ctext%7Bclk%5C_I/O%7D%7D%7B2N(1+%5Ctext%7BOCR0A%7D)%7D%0A%5Ctag%7B1%7D"></span> We can rearrange the equation at the bottom of page 72 (Equation&nbsp;1) to solve for the value of OCR0A that will get us the desired output frequency: <span id="eq-ocr0a"><img src="https://latex.codecogs.com/png.latex?%0A%5Ctext%7BOCR0A%7D%20=%20%5Cfrac%7Bf_%5Ctext%7Bclk%5C_I/O%7D%7D%7B2Nf_%5Ctext%7BOC0A%7D%7D-1%0A%5Ctag%7B2%7D"></span></p>
<p>Where:</p>
<ul>
<li><img src="https://latex.codecogs.com/png.latex?f_%5Ctext%7Bclk%5C_I/O%7D"> is the clock frequency in Hz (I stuck with the default 1MHz)</li>
<li><img src="https://latex.codecogs.com/png.latex?f_%5Ctext%7BOCR0A%7D"> is the desired output frequency (38kHz)</li>
<li><img src="https://latex.codecogs.com/png.latex?N%20%5Cin%20%5C%7B1,8,64,256,1024%5C%7D"> is the prescale factor which divides the clock cycles giving us some more room for adjustment.</li>
</ul>
<p>If I use <img src="https://latex.codecogs.com/png.latex?N=1"> with Equation&nbsp;2 I get <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BOCR0A%7D=12.16">, and <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BOCR0A%7D=0.64"> with <img src="https://latex.codecogs.com/png.latex?N=8">. OCR0A is an 8-bit unsigned integer so we’ll need to round these two values to <img src="https://latex.codecogs.com/png.latex?12"> and <img src="https://latex.codecogs.com/png.latex?1">, respectively. To see what frequency we will actually get we plug these numbers back into Equation&nbsp;1. This yields <img src="https://latex.codecogs.com/png.latex?f_%5Ctext%7BOC0A%7D=38.46%5Ctext%7BkHz%7D"> for <img src="https://latex.codecogs.com/png.latex?N=1"> and <img src="https://latex.codecogs.com/png.latex?f_%5Ctext%7BOC0A%7D=31.25%5Ctext%7BkHz%7D"> for <img src="https://latex.codecogs.com/png.latex?N=8">. <img src="https://latex.codecogs.com/png.latex?N=1"> with <img src="https://latex.codecogs.com/png.latex?%5Ctext%7BOCR0A%7D=12">, is the best we can do with the 1Mhz clock. Luckily this frequency is within the <img src="https://latex.codecogs.com/png.latex?%5Cpm5%5C%25"> tolerance of the TSSP4038 <span class="citation" data-cites="tssp4038_datasheet">(Vishay 2025)</span>.</p>
<p>In the C code I configured Timer0 in the <code>init_timer0</code> function:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb1-1"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">#include </span><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">&lt;avr/io.h&gt;</span></span>
<span id="cb1-2"></span>
<span id="cb1-3"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> init_timer0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb1-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb1-5">    TCCR0A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> WGM01<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Put Timer0 into CTC mode</span></span>
<span id="cb1-6">        <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> COM0A0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Toggle OC0A each cycle (blink the IR LED)</span></span>
<span id="cb1-7">    TCCR0B <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> CS00<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// no prescaler</span></span>
<span id="cb1-8">    OCR0A <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">12</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Oscillate at approx 38.46kHz</span></span>
<span id="cb1-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>I call this at the start of my main function and that’s all there is to generating the emitter output. This is called in the setup part of my <code>main</code> function:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb2-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> main<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb2-2"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-3">    DDRB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_IR_LED<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb2-4">    init_timer0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb2-5">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// ...</span></span></code></pre></div></div>
</section>
<section id="detection" class="level2">
<h2 class="anchored" data-anchor-id="detection">Detection</h2>
<p>The detection code is fairly simple, the TSSP4038 is active LOW. This means that the output pin on the TSSP4038 will be LOW when there is an IR signal and HIGH when there is none. In other words when the sensor is blocked the output will be HIGH. I wrapped this in the <code>update_indicator</code> function:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb3-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> update_indicator<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb3-2"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb3-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Sensor pin will be high when blocked</span></span>
<span id="cb3-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>PINB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_SENSOR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb3-5">        PORTB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_INDICATOR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb3-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span></span>
<span id="cb3-7">        PORTB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_INDICATOR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb3-8"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
<span class="screen-reader-only">Tip</span>Use as a reflective sensor
</div>
</div>
<div class="callout-body-container callout-body">
<p>The code can easily be adapted to work as a reflective sensor, simply invert the logic in <code>update_indicator</code>:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb4-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> update_indicator<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb4-2"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-3">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Sensor pin will be low when train present</span></span>
<span id="cb4-4">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">if</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>PINB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_SENSOR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">))</span></span>
<span id="cb4-5">        PORTB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&amp;=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">~(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_INDICATOR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb4-6">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">else</span></span>
<span id="cb4-7">        PORTB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_INDICATOR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb4-8"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
</div>
</div>
<p>To handle detection I use a pin change interrupt, in particular INT0 which is the highest priority interrupt and is mapped to PB2. By using an interrupt we keep the CPU free to handle other tasks (or idle) instead of constantly polling the PINB register. The interrupt was configured as such:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb5-1"><span class="pp" style="color: #AD0000;
background-color: null;
font-style: inherit;">#include </span><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">&lt;avr/interrupt.h&gt;</span></span>
<span id="cb5-2"></span>
<span id="cb5-3">ISR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span>INT0_vect<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb5-4"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-5">    update_indicator<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb5-6"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb5-7"></span>
<span id="cb5-8"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span> init_interrupt0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb5-9"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb5-10">    GIMSK <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> INT0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Enable INT0</span></span>
<span id="cb5-11">    MCUCR <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> ISC00<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Interrupt on any change</span></span>
<span id="cb5-12">    sei<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb5-13"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>Now, you might be wondering why I even bothered to split the barrier checking logic into a separate function if I’m only going to call it in the ISR. It actually needs to be called on startup as well to poll the initial state. Since the ISR is only called on a change if there is already a train blocking the barrier it will not be registered.</p>
<p>Finally, since the TSSP4038 is active LOW we need to enable the internal pullup resistor on that pin to prevent a floating state. This results in this final <code>main</code> function:</p>
<div class="code-copy-outer-scaffold"><div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode c code-with-copy"><code class="sourceCode c"><span id="cb6-1"><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">int</span> main<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">void</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb6-2"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb6-3">    DDRB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_IR_LED<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_INDICATOR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span></span>
<span id="cb6-4">    PORTB <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">|=</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;&lt;</span> PIN_SENSOR<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">);</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Pullup the IR sensor</span></span>
<span id="cb6-5">    init_interrupt0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb6-6">    init_timer0<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb6-7"></span>
<span id="cb6-8">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Since the interrupt will only fire on a change,</span></span>
<span id="cb6-9">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// check the initial state of the barrier incase</span></span>
<span id="cb6-10">    <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// it is already blocked</span></span>
<span id="cb6-11">    update_indicator<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">();</span></span>
<span id="cb6-12"></span>
<span id="cb6-13">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">while</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">(</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">1</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">)</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">{}</span> <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Loop forever</span></span>
<span id="cb6-14">    <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb6-15"><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div></div>
<p>The full code for this project is on <a href="https://codeberg.org/awest03/simple-ir-barrier">Codeberg</a>.</p>
</section>
</section>
<section id="results" class="level1">
<h1>Results</h1>
<p>With all of that set up here’s a photo of my simple IR barrier in action:</p>
<div id="fig-action" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-action-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://awest.adegator.net/posts/attiny-ir-barrier/barrier_in_action.jpg" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-action-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;3: The IR Barrier in action (TSSP4038 is hidden by the blue LED and IR LED is on the other side of the train)
</figcaption>
</figure>
</div>
<p>The IR barrier worked great at detecting solid objects (like the <em>Mallard</em>), however light could travel through carriages with windows. A possible solution is to move the sensor to be above and below the train. With some fine tuning I may change this to a reflective sensor either mounted under the track or on some overhead structure.</p>
<p>This is a part of an ongoing <a href="http://localhost:4800/projects/model-railway/">project</a> to automate my railway.</p>



</section>

<div id="quarto-appendix" class="default"><section class="quarto-appendix-contents" id="quarto-bibliography"><h2 class="anchored quarto-appendix-heading">References</h2><div id="refs" class="references csl-bib-body hanging-indent">
<div id="ref-attiny85_datasheet" class="csl-entry">
Atmel. 2013. <em>ATtiny25/v/ATtiny45/v/ATtiny85/v</em>. <a href="https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf">https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/Atmel-2586-AVR-8-bit-Microcontroller-ATtiny25-ATtiny45-ATtiny85_Datasheet.pdf</a>.
</div>
<div id="ref-vs1838B_barrier" class="csl-entry">
Pons, Giulio. 2025. <em>How to Build an Infrared Barrier with IR Led and VS1838B Receiver and Arduino</em>. <a href="https://www.barattalo.it/making/how-to-build-infrared-barrier-vs1838b-arduino/">https://www.barattalo.it/making/how-to-build-infrared-barrier-vs1838b-arduino/</a>.
</div>
<div id="ref-schafer2024" class="csl-entry">
Schäfer, Sebastian. 2024. <em>Vishay Infrared Receivers for Presence Sensor Applications</em>. <a href="https://www.vishay.com/docs/82904/irreceiversprecencesensorapps.pdf">https://www.vishay.com/docs/82904/irreceiversprecencesensorapps.pdf</a>.
</div>
<div id="ref-lightbarriers" class="csl-entry">
Vishay. 2024. <em>RECEIVERS AND EMITTERS FOR LIGHT BARRIERS</em>. <a href="https://www.vishay.com/docs/49650/pt0402-lightbarriers.pdf">https://www.vishay.com/docs/49650/pt0402-lightbarriers.pdf</a>.
</div>
<div id="ref-tssp4038_datasheet" class="csl-entry">
Vishay. 2025. <em>TSSP40..</em> <a href="https://www.vishay.com/docs/82458/tssp40.pdf">https://www.vishay.com/docs/82458/tssp40.pdf</a>.
</div>
</div></section></div> ]]></description>
  <category>electronics</category>
  <category>model-railway</category>
  <category>ir</category>
  <category>code</category>
  <guid>https://awest.adegator.net/posts/attiny-ir-barrier/</guid>
  <pubDate>Tue, 07 Apr 2026 14:00:00 GMT</pubDate>
  <media:content url="https://awest.adegator.net/posts/attiny-ir-barrier/barrier_in_action.jpg" medium="image" type="image/jpeg"/>
</item>
</channel>
</rss>
