Friday, June 10, 2011

Variable intermittent wiper control - Part 3

Variable intermittent wiper control - Part 2

Rather than use a 555 for the variable intermittent wiper circuit (VIWC) as we saw in Part 1 I employed a microcontroller instead for the Innova. An MCU's timing accuracy is far better than the 555 and is far more powerful and flexible and requires less discrete components.

I chose a baseline PIC with analog to digital converter (ADC) instead of a midrange PIC because I need only two pins and both Flash and RAM requirements are minimal. What I have on hand right now is the PIC10F222, but the 10F220 just might suffice depending on the optimization level available on the compiler--the Hi -Tech C freebie version I use throws up obscenely long codes and probably gobbles up RAM as well.

Given the wiper module's electronics it is necessary to electrically disconnect it from the VIWC to prevent any conflicts and possible shorts. Through tests I've determined that the module's electronics is powered via W-VDD. So disconnecting the circuit from this net will prevent it from being powered up. However, we will be using W-PP and that goes right into the board. W-PP carries a +12V which could possibly wreak havoc on the circuitry particularly with W-VDD cut off. With the wiper stalk switch at OFF and INT, W-PP is connected to W-LO. This is actually fine but no harm in breaking this connection while the VIWC is powered up. Tests thus far show that W-LO isn't connected to the board or relay. So we don't have to sever this connection to the wiper module. We'll just need to tap into it to trigger--briefly turn on--the wiper motor. Here's a diagram of the wires leading to the connectors that we'd need to break. Actually only one connector needs to be modified.

Take note of the new wire labels. Those are used in the following schematic. Note that all switches and relay contacts are shown in their normal position--with the circuit powered down.


In the initial design I opted to use a DPDT switch rather than the DPDT relay. I decided on the relay and SPST switch design because I would be able to use a smaller switch on the dashboard and would have to bring only two wires to it.

REL1 is a Telemecanique RXM2AB2JD  12-volt relay with 12A DPDT contacts and a green LED indicator lamp. REL2 is a 12-volt relay with 10A SPDT contacts.

When S-POW is closed REL1 is energized. Power to wiper module is cut off while the VIWC is powered up. Simultaneously, WW-PP is disconnected from W-PP and connected instead to REL2's NC contact, thus making sure that when REL2 is de-energized the wiper motor will automatically bring the wiper blades back to their parking position.

You will notice I have not used W-GND but connected the circuit directly to chassis ground. Tests show both are the same net even when ignition is off. I want to cut and cut into as few of the car's wires as possible.

For the pot I used a cheap low quality one. Trying to get a particular time interval with it can become vexing. I'm still trying to find a better pot that has a much more even resistance across its entire range. Another option is to use a pot with a switch thus integrating S-POW with R1 in one package.

A 78L05 100-mA voltage regulator provides +5V to the MCU. Filter cap is 100uF.



The microcontroller is run at 4MHz. Watchdog timer is enabled. The prescaler is assigned to timer0 so WDT will time out in 18ms (nominal value as per datasheet). In the firmware WDT is cleared during the polling of TMR0.

With the single 8-bit timer I wanted to get the highest possible tick. At 4Mhz--which translates to a million instructions/sec--that would be 65.536ms with TMR0 = 0 and a prescale of 1:256. But that's not a good tick value. 50ms is easier and more sensible to work with. To obtain that, prescale is set to 1:256 and TMR0 reinitialized to 0x3D (decimal 61) every time it rolls over to zero. Given those values TMR0 will overflow every (256 - 61)(256)(1us) = 49.92ms.

Remember baseline PICs don't have interrupts. We have to poll the timer to determine when it's overflowed. But for some reason using the conditional "while(TMR0 != 0)" doesn't work. Using any value other than zero, however, works. So in the firmware below I have "while(TMR0 != 0xFF)" instead. With that conditional perhaps I should initialize TMR0 to 0x3C instead.

What I wanted was for the time interval between wipes to be increments of 1 second, that is, as the user turns the potentiometer the interval would get longer/shorter but it would jump from 1 second to 2 to 3 and so on, and not fractions thereof. As for maximum interval, I initially specified 60sec but then I settled on 30. Minimum interval would be 1sec.

Note that time interval is defined as the time between de-energization of the REL2 and its re-energization.

In order to realize the above specs, it occured to me there's a simple and elegant way of doing so. The ADC onboard the 10F222 has an 8-bit resolution. That's 256 values, from 0 to 255. Well what we can do is to degrade the resolution to less than 8 bits. That's easily done by right shifting the ADC value (the number the ADC spits out after the conversion). Shift it right twice and we have a 6-bit number--from 0 to 63. Or shift thrice and we a 5-bit value--0 to 31. We can then take those numbers as the time interval (in seconds). But since we specified a minimum of 1 second, we should add 1 to the 5-bit ADC value giving us a range of 1 to 32. Now keep in mind this is the number of seconds. Our timer tick, however, is ~50ms. To get the time interval in terms of ticks we have to multiply the ADC value by 1sec/0.05sec = 20. Therefore, to count 32 seconds, we need to wait for 32(20) = 640 ticks.

The potentiometer is read by the ADC every timer tick. The time interval setting is therefore updated 20 times a second, except when a wipe action is being executed--the ADC is not reading the pot during that time.

The firmware is such that, every timer tick, it compares the latest time interval chosen by user and the amount of time elapsed since the last wipe. If time elapsed already exceeds the latest time interval setting, then a wipe is immediately performed and the 16-bit counter monitoring the amount of time elapsed is reset to zero.

For example if the pot was previously set to a time interval of say 25 sec, and 15 seconds has already elapsed, and the user has just turned the pot down to 12sec, the firmware will immediately issue a wipe action and reset the time elapsed counter. (In reality, with a read rate of 20x a second--somewhat faster than the driver can turn the pot--firmware will see the pot setting crossing the 15sec mark and issue a wipe action at that point). On the other hand, if the user had turned up the pot instead, to say 30sec., then the firmware will count all the way to 30sec before the next wipe.

When powered up an initial wipe is made. Thereafter, when the succeeding wipes will occur will depend on the pot setting. The length of time I've chosen for the wiper to be triggered (turned on briefly) is one second (20 timer ticks). As mentioned in Part 2 the time for the wiper to go from parking position and back was measured to be ~1.3sec. Trigger time must be less than this. A trigger time of around half a second would probably be sufficient. Keep in mind, however, that time interval between wipes is affected by wiper trigger time.

And here's the final firmware to drive the micrcontroller. Compiler used is the Hi -Tech C Lite v9.80. As I mentioned a few days ago the 10F222 include file of v9.81 doesn't define TRIS and so will fail to compile the following.

/*

Variable intermittent wiper control for the Toyota Innova, 2008, E-variant
June 2011

Processor = PIC 10F222 
Compiler = Hi Tech C v.9.80

Description: User adjusts a potentiometer to desired interval between wipes.

*/


#include <htc.h>
#include <et_include.h>

__CONFIG (OSC_4MHZ & MCPUDIS & WDTEN & UNPROTECT & MCLRDIS);        // for Hi-Tech C v9.80
// __CONFIG (IOSCFS_4MHZ & MCPU_OFF & WDT_OFF & CP_OFF & MCLRE_OFF); // for Hi-Tech C v9.81

#define   wiper              GP2       // switches 2N7000 MOSFET transistor which then switches relay which switches wiper
#define   wipertrigtime      20        // amount of time to power up wiper. time is in terms of number of timer0 overflows
#define   t0_init            61        // initial value of timer0. with prescaler = 1:256, overflow occurs every ~50ms 
// #define  _XTAL_FREQ       4000000 



// potentiometer setting is converted to 5-bit digital value
// 10F222 ADC has 8bit resolution, therefore ADC value is right shifted three places
// After right shifting, add 1 so that with ADC value of zero (potentiometer at zero ohms) the minimum time interval is 1sec.
// Since max ADC value for 5-bit is 31, max time interval = 31 + 1 = 32sec
int8 ADC()          
{
  GODONE = 1;                          // start ADC conversion
  while(GODONE);                       // wait till GODONE bit has been cleared, signifying completion of conversion 
  return ((ADRES >> 3) + 1);     // degrade to 5 bits, and force min time interval = 1
}


// wiper lo speed is triggered (switched on) for a brief moment, determined by constant "wipertrigtime" 
// after triggering, parking system on wiper motor will take over powering the motor until it reaches parking position 
// when wiper reaches parking position, motor stops automatically 
// NOTE: WDT must be cleared within 18ms (no prescaler assigned to it)
void WIPE()
{
  int8 i;
  wiper = on;
  for (i=0; i<wipertrigtime; i++)
  {
    TMR0 = t0_init;
    while(TMR0 != 0xFF)      // for yet unknown reason conditional doesn't work with "TMR0 != 0x0"
      CLRWDT();
  }
  wiper = off;  
}


// NOTE: WDT must be cleared within 18ms (no prescaler is assigned to it)
void main()
{
  static int16 TIME = 40;    // number of timer0 overflows (every 50ms) between wiper sweeps. initialize to minimum time interval betwen wipes (2sec. which is equivalent to 40 timer0 overflows) 
  static int16 COUNTER = 0;  // stores the number of times timer0 has overflowed

  TRIS = 0b1;                // pot is connected to AN0/GP0
  OPTION = 0b11000111;       // wake up pin change disabled, pull ups disabled, timer0 uses internal clock, timer0 prescale = 1:256 
  WIPE();                    // have wiper sweep windshield once upon power up
  TMR0 = t0_init;
  ADCON0 = 0b10000001;       // GP0/AN0 is analog, GP1 is digital, channel 0 selected, ADC on
  
  while(1)
  {
    while(TMR0 != 0xFF)      // poll TMR0 because there is no timer0 interrupt flag. for yet unknown reason conditional doesn't work with "TMR0 != 0x0"  
      CLRWDT();              // WDT must be cleared within 18ms (no prescaler assigned to it)

    if (COUNTER++ >= TIME)
    {
      WIPE();
      COUNTER = 0;           
    }
    TMR0 = t0_init;
    
    TIME = (ADC())*20;       // Each value of the 5-bit ADC reading is equivalent to number of seconds. 
                             // This is then multiplied by 20 since timer0 overflows every 50ms and 1sec/0.050sec = 20
                             // if new TIME < previous TIME and current COUNTER value exceeds new TIME then a wipe will occur right after the next TMR0 overflow
                             // if new TIME > previous TIME then whatever COUNTER is, the next wipe will occur at a later time.   

  } // while(1) 
} // void main()



I field tested the circuit to check if everything works. It does! Here are a couple of pics of that test process. The breadboard is in the translucent plastic box while the relays are mounted on a DIN rail. REL1 and REL2 are both Telemecanique RXM2AB2JD relays. In the PCB version I will be using a small PCB mounted relay for REL2.


There's another shot of this setup in which something very interesting inadvertently appeared.


June 12 edit: A Part 4 just appeared. And because of new developments so will a Part 5.

No comments:

Post a Comment