Thursday, November 26, 2009

Converting BMW temperature sensor resistance to degrees Celsius with an IC

The BMW E36 on-board computer uses a temperature sensor mounted in the front bumper.

The temperature sensor is actually a thermistor with a negative thermal coefficient (NTC thermistor = negistor), meaning that as the temperature rises, its resistance falls.

The sensor was found to be equal to a K164NK004.7 thermistor. The resistances of this thermistor for different temperatures according to the datasheet are:



When using an IC such as the Atmega168 on Arduino, you cannot measure resistance directly. You add a pull-up resistor to the temperature sensor, which creates a voltage divider and then use the IC to measure the resultant voltage.




The value dependence between the thermistor resistance and the resulting voltage is not linear and neither is the dependence between the resistance and the actual ambient temperature in degrees Celsius.




My goal was to determine the best value of the pull-up resistor to create a linear (or at least uniform) dependency between the ambient temperature and the output of the voltage divider.

I picked several common resistor values and calculated the voltages for different temperatures.



Let's put the values on a graph and see which resistor gives the most linear output



The graphs seem very similar, so let's graph the relation between a temperature change and a voltage change.



This graph clearly shows that no matter what resistance we use, we will never get a flat line. The next best thing is the 12K resistor - it is flat around zero degrees and uniform on both sides.

So let's use a 12K resistor and see how closely we can approximate its graph with a linear function. We want to calculate the temperature from the voltage, so the graph will be reversed. It is not hard to see that a good approximation function is

temperature = 20 * voltage - 45



That's not bad for such a simple function, but it still needs some fine-tuning - the biggest difference is almost 5 degrees Celsius.
After some test and error time, I came up with

temperature = (400 * voltage - 888) * (140 + |voltage|) / 3500

which gives acceptable results.



So let's sum up - if you connect the BMW E36 ambient temperature sensor to an IC and pull it up to 5V with a 12K resistor, you can then convert the voltage measured by the IC to actual temperature using the formula stated above.

Labels: , , ,

Monday, November 23, 2009

Automatic route & drill width in Eagle PCB layout editor

If you look up "the right way to change route widths in Eagle", you will find that you need to

- set up different "net classes" in the schematics editor
Edit -> Net classes

- set the right class for each net in the schematics editor
Right click -> Properties or Change tool -> Class

- route the nets in the Layout editor

The problem with this approach is that it does not work :) or at least not when you route manually. The layout editor will not automatically change route widths based on the assigned net classes.

What you need to do is go to Options -> Set -> Misc and check the Auto set route width and drill option.

Why this is not the default setting is beyond me.

Labels: , , ,

Wednesday, September 30, 2009

Install a 32-bit driver on 64-bit Windows

Yesterday a found out that my super cheap Chinese PCMCIA-SERIAL adapter didn't come with a driver for x64 based systems. The adapter uses a CH352 chip and the manufacturer of the chip (www.wch.cn) doesn't even have any drivers on the website, let alone provide 64-bit versions.

Surprisingly, Microsoft had the answer this time.

http://www.microsoft.com/whdc/driver/install/64INF_reqs.mspx#E1G

You can install a driver not marked as 64-bit compatible if you create the following DWORD key in the registry and set the value to 1 (or anything but zero)

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup\DisableDecoratedModelsRequirement

I didn't even have to restart the computer and it worked like a charm.

Of course, you do this and any other modification of the registry at your own risk. It is only recommended for testing purposes.

Labels: , ,

Saturday, August 1, 2009

"Binding" to ListBoxItem's IsSelected property from its template in Silverlight

It is not really a binding, but it does the trick:

<ListBox Name="MyListBox" ItemContainerStyle="{StaticResource MyListBoxItemStyle}" >

<Style x:Key="MyListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border" Padding="2" Loaded="Template_Loaded">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

private void Template_Loaded(object sender, RoutedEventArgs e)
{
Border border = (Border)sender;
ListBoxItem listBoxItem = (ListBoxItem)VisualTreeHelper.GetParent(border);

MyListBox.SelectionChanged +=
// this will be executed for every item whenever selection changes
delegate(object s1, SelectionChangedEventArgs e1)
{
if (listBoxItem.IsSelected)
{
// do stuff to "border" or "listBoxItem"
}
else
{
...
}
};
}

Labels: , , ,

Tuesday, July 28, 2009

Focus a Silverlight control on startup

I found two solutions to this problem on the web and neither of them worked for me. I finally combined both of them to make it work:

In the aspx page, include

<script type="text/javascript">
window.onload = function()
{
setTimeout(function() { document.getElementById('Xaml1').focus(); }, 1);
}
</script>

And then in Page.cs class as a response to Loaded event:

Dispatcher.BeginInvoke(delegate{myControl.Focus();});

Labels: ,

Sunday, July 5, 2009

Double quotes problem in Windows 7

EDIT: Due to big popularity of this post, let me put the solution on top:

If you have a problem with quotes in Windows 7, try to switch the keyboard layout from "United States - International" to "US"
After changing the keyboard layout, you may need to restart your programs or the computer.

ORIGINAL POST:

After installing Windows 7 and Visual Studio 2008, I discovered the following behavior in the code editor:
Pressing the double-quote (") key once would have no effect.
Pressing any key after that would produce both the double quote character and the next character.

The problem was not caused by Visual Studio, but by regional settings - I solved it by switching from "United States - International" to "US" keyboard layout.

Labels: , ,

Tuesday, March 17, 2009

BMW E36 multi-function steering wheel retrofit

The leather on my old steering wheel looked really worn, so I started looking for a new wheel. New leather would be an option if the steering wheel looked better, but an old 4-spoke without the BMW badge is not something very aesthetic...



On the other hand, for some reason I don't really like 3-spoke wheels, which left me with a single option - a 4-spoke wheel from a newer E36.



I started searching on e-bay and several other auction sites and I found out, that e39 and e38 had a very similar steering wheel, except it had buttons. I began a long search for a DIY on retrofitting a multifunction steering wheel to an E36.



As it turns out, not many people attempted to do this. I found a Slovenian guy Vlakci at bimmerforums.com, who retrofitted the wheel to his E36, but he used a very different approach than what I was hoping for - he used an OEM head unit and cruise control from the E39 - these can communicate with the steering wheel almost without modification. This solution did not seem ideal, as my head unit is better than factory and a I spent about two months finding and retrofitting the cruise control - I decided to do it my own way.

The steering wheel was produced in 1995, which means that the buttons are not connected directly to the I-bus (which my E36 doesn't have at all), but the signal is first sent to an intermediate "MFL unit", where it is transcoded for the I-bus and for the cruise control unit. I was hoping that the communication between the buttons and the MFL unit was analogue, based on different buttons having different resistances, but I was wrong.

I had to disassemble the buttons and look inside. I found an electronic circuit with several basic components and a microcontroller labeled U-6050B. I spent some time googling and found out that it is a multiplexer made by Temic and that its purpose is to encode a status of up to 8 buttons and send it over a single line. I studied the spec.

http://www.datasheetcatalog.org/datasheet/Temic/mXyzurtr.pdf

According to the specification, there has to be a U-6052B demultiplexer on the other side of the line that reads the status of the buttons and controls relays - one for each button. This was a very positive information, because in E36, all communication between components (except for the diagnostic connector) is realized this way - nothing is digital, only different voltages on every line. Additionally, according to the spec, it is possible to connect two multiplexers in series and read up to 16 buttons - this is exactly how the steering wheel handles two rows of buttons.

Getting the demultiplexer U-6052B is not very easy these days - it's been discontinued some 15 years ago. I decided that I didn't really need the MFL unit which contains a pair of those demultiplexers. I downloaded Eagle, made a schema according to the specification and had a local guy print the circuit board for me.



One of my friends then helped me desolder the tiny demultiplexers from the MFL unit and solder them to my custom circuit board.



Then I soldered some additional resistors and capacitors and after three days of bug fixing, the circuit started working - whenever I press a button on the steering wheel, one of the outputs of the circuit board is connected to ground.







Next I had to deal with controlling the E36 cruise control. At first I thought it would be trivial, because the cruise control switch works by connecting different pins of the cruise control unit to ground, but as it turned out, it is the other way around - the CC switch needs to connect CC unit pins to +12V. How do you "convert" GND to +12V? The easiest solution would be to use relays, but I wanted something without moving parts. I read about transistors on Wikipedia and I found a way to use them instead of the relays.

http://www.rason.org/Projects/transwit/transwit.htm

Another complication was that one of the pins of the CC unit works differently - it needs to be under voltage at all times and interrupting this connection causes the CC unit to disengage. I experimented a little bit with two transistors in series, but then I decided to use the relay for this purpose, because I never use the CC switch to turn the cruise control off, so the relay will almost never be used and I don't care if it has moving parts or not. Plus my experiments with the transistors didn't work :D



Apart from the buttons, I had to deal with airbag and horn connectors and buy a new steering wheel switch holder, which is fortunately very cheap.







Currently, the wheel is in the car, it looks great, it feels good (although it is a little bigger than the previous one), the turn signals work, the horn works, the button lighting works (along with the interior lighting intensity regulator) and the right-side buttons work. I also use the bottom-right button for switching OBC functions, because I don't have the OBC-enabled turn signal switch.



The next step will be to use the left side buttons for controlling the head unit. My Clarion has a jack for "OEM steering wheel controls", but I cannot find any specification for this input. A company called PAC makes universal adapters and Clarion makes one itself, but they are both expensive. My best bet now is that the head unit is controlled by a resistance ladder between the two contacts on the jack - I will have to try and see. If you have any experience with this input, please let me know.

Labels: , , , , ,