It was a hot, really hot, really very hot summer in 2012 in place where I used to live. I bought some cheap fan, though it was quite powerful, but there were two major drawbacks for me:
- No remote control
- No timer for scheduling switching off, let say at night. And I did not want it to make noise a whole night.

So, what do we have handy:
1. A pic16f628a microcontroller in a soic package;
2. Two 5V couple amps relays;
3. A fan;
Not that bad,we have the stuff which can be unscrewed and I can dig into entrails. Disassembling the fan firstly, inside we have the standard mechanical 4 modes switch: 3 for speed change and 1 for the moving the fan around. One can represent the fan schematic like this:

Do not pay attention to the inductance values, they don’t carry any meaning for our small project.
The task #1 – the load control by the uC, I used the easiest solution – a relay, just I wanted to leave the manual control as well. Putting everything together to the schematic and adding a fuse, just in case.

The default mode (with uC is switched off) the voltage goes through RL1 to the manual control. When we enable the remote control (IRON = 1), we are bypassing one manual speed with RL2 and controlling on/off state with IRFAN bit. I use just a single speed for remote, since at the moment I had just two relays in my stashes.
Adding the microcontroller and some indicators:

I did not show the crystal oscillator and IR TSOP1738 receiver IC (the application diagram can be viewed in this article) . The D7 LED serves as an indicator of entering to the remote control mode. Other 4 LEDs represent timer value in the binary form. All we have left to do is to connect some power supply to power the remote interface device. I found some old mobile supply charger which worked pretty well.
Time to disclose the code I wrote for this.
#include <htc.h>
#include <stdio.h>
#include "usart.h"
#define _XTAL_FREQ 4000000
#define ON RA0 //пин включения реле для питания
#define IRpin RB0 //пин Ик
#define FAN RA1 //пин включения вентилятора
volatile static bit direction; //1 - rising, 0 - falling
volatile unsigned char IRbyte; //принятый байт
volatile bit togglebit; //бит переключалка
volatile bit oldtogglebit; //хранение старого значения бита-переключалки
volatile bit buffer;
volatile unsigned char bytecount;
volatile unsigned char i=0;
volatile unsigned short long tick = 0;
volatile unsigned short long tickCount = 0;
volatile unsigned short long time = 0;
__CONFIG(MCLRDIS & LVPDIS & WDTDIS & UNPROTECT & XT);
void StartTimer(void); //инициализация таймера 0
void StartTimer2(void); //инициализация таймера 2
void main() {
unsigned int delta = 4596; //Переменная дельта для промежутка таймера - 4596 ~ 5 минут
CMCON = 0x07; //Аналоговые функции не нужны
TRISA = 0x00;
TRISB = 0b00001001; // Порт В на выход
PORTB = 0x00; // Выключаем все выходы порта В
PORTA = 0x00;
init_comms(); //Инициализация уарта
GIE = 1;
PEIE = 1;
buffer = 0;
IRbyte = 0;
bytecount = 0;
direction = 0;
INTEDG = 0;
INTE = 1;
printf("Starting done! \r\n");
SLEEP(); //Все настроено, засыпаем чтобы не жрать зря энергию
for (;;)
{ // Запускаем бесконечный цикл
//---------------Обработка ИК команд---------------
if (bytecount>13)
{
GIE = 0;
if (oldtogglebit != togglebit)
{
printf("\r\nPressed button is %d", IRbyte);
switch(IRbyte)
{
case 31 : ON = !ON;
if (!ON)
{
time = 0;
FAN = 0; //Если выключено электронное управление, то выключаем реле вентилятора
PORTB &= 0b00001111;
TMR2ON = 0; TMR2IE = 0;
SLEEP();
}
break;
case 15 : if ((time < 16)&&(ON))
{
FAN = 1;
time++;
unsigned char temp = time << 4;
tickCount = delta*time; //примерно 5 минут * на нужный промежуток
printf("Tickcount %d", tickCount);
PORTB &= 0b00001111;
PORTB |= temp;
tick = 0;
StartTimer2();
} else if (ON)
{
time = 0;
PORTB &= 0b00001111;
}
break;
case 37 : time = 0;
PORTB &= 0b00001111;
break;
case 23 : if (ON) FAN = !FAN;
else FAN = 0;
break;
}
}
IRbyte = 0;
bytecount=0;
INTEDG = 0;
buffer = 0;
oldtogglebit = togglebit;
GIE = 1;
}
//---------------Конец обработки IR команд---------------
if ((tick%delta == 0)&&(tick>0)) //Гасим светодиоды в обратном порядке
{
unsigned char temp = (time - (tick/delta)) << 4;
PORTB &= 0b00001111;
PORTB |= temp;
}
}
}//for(;;)
interrupt isr() {
//-------------------IR decoding-------------------
if (INTF)
{
if (bytecount<1)
{
direction = 1;
INTEDG = 1;
StartTimer();
bytecount++;
} else
{
direction = !direction;
if (direction==buffer)
{
StartTimer();
bytecount++;
}
INTEDG = direction;
}
INTF = 0;
}// if INTF
else
{
if (TMR1IF)
{
buffer = IRpin;
TMR1ON = 0;
TMR1IF = 0;
if (bytecount==2) togglebit = buffer;
if ((bytecount>7)&&(bytecount<14)) //забираем только команду
{
IRbyte <<= 1;
IRbyte |= buffer;
}
}
}//else
if (TMR2IF)
{
GIE = 0;
if (tick < tickCount)
{
tick++;
TMR2IF = 0;
StartTimer2();
}
else
{
tick = 0;
FAN = 0;
ON = 0;
TMR2ON = 0;
TMR2IE = 0;
tickCount = 0;
time = 0;
PORTB &= 0b00001111;
}
TMR2IF = 0;
GIE = 1;
}
}
//--------------------End interrupts---------------------
/* ---------------------------------------------Функции--------------------------------------------*/
void StartTimer(void)
{
T1CKPS1 = 0;
T1CKPS0 = 0;
T1OSCEN = 0; //выключаем внутренний генератор
TMR1CS = 0; // Fosc/4
TMR1IE = 1; // прерывание по переполнению TMR1
TMR1H = 0b11111011; TMR1L = 0b00010110; //1.257ms
//TMR1H = 0b00000000; TMR1L = 0x00;
TMR1ON = 1; // включаем таймер
}
void StartTimer2(void)
{
//printf("\r\nStart timer");
TMR2 = 0x00; //стартуем с 0
PR2 = 0xFF; //считаем по 255*16 мкс
T2CKPS0 = 1; T2CKPS1 = 1; //1 делитель максимум
TOUTPS2 = 1; TOUTPS1 = 1; TOUTPS3 = 1; TOUTPS0 = 1; //2 делитель максимум
TMR2IE = 1;
TMR2ON = 1; // Запуск таймера!
}Thus, I got the fan with the remote control, with indication of the entering to remote mode and with binary indicators of the timer value. The base time delay count equals to 5 mins, so the max possible timer value is 5*(2^4) =80 minutes.
There is a short video how the thing works: