18F Hall Effect Sensor

Developed with the
Swordfish
compiler
Hall Effect sensors allow
the detection of a magnetic field. They can be extremely small, and very
accurate, and often used in applications that require some sort of speed/RPM
feedback. For example, you wanted to make a digital speedometer for your car,
and don't want to impede on the pre-existing circuit, you could use a Hall
Effect sensor to determine how many revolutions/second your wheel is doing, and
calculate your speed from there.
In this example, the
A1102 made by Allegro is used.
Other models (A110x) allow for different sensitivities and hysteresis
properties. Hysteresis is important as you don't want false readings from
ambient magnetic fields, as the devices react very quickly (400nS switching
time).
The
A1102 is a
Unipolar Hall-Effect Digital Switch, this means that the device can detect a
south polarized magnetic field when its perpendicular to the face of the device.
As shown on the
device list, the
A1102 has an open collector output, this means when the device detects a
southern magnetic field, the output is tied to earth through a transistor. We
will need to add a pull-up
resistor to bring the output up to 5V when it
the transistor is off, perhaps the circuit diagram will explain it more,
Note the PIC's power supply/oscillator are not shown

The
A1102 is grossly
oversized compared to real life in the circuit diagram - its just an
representation of the curved edges on the front that I was trying to portray.
Its actually smaller than the picture displayed at the top of the topic.
Now for our program. I
thought an RPM type display would be ideal for this device. There's no way you
would sample for a whole minute to determine what the RPM of a device is (well
you could - but simply wouldn't). So instead its much more efficient to sample
over a known time period and then scale the result back up. The sample register
is also known as a PreScaler.
For my example, I will
sample for 500mS, and then scale it too RPM. The longer you sample for, the more
accurate your results - but the slower the refresh rate. It's a trade off, but I
have found 500mS to be a happy median.
Device = 18F452
Clock = 20
// some LCD options...
#option LCD_DATA = PORTB.4
#option LCD_RS = PORTB.2
#option LCD_EN = PORTB.3
// import LCD library...
Include "LCD.bas"
Include "utils.bas"
Include "ISRTimer.bas"
Include "convert.bas"
Const Timer1 = 0
Dim
Hall_Sensor As PORTA.0,
PreScaler As Word
// Start Of Program...
SetAllDigital
ADCON1 = %00000110
Timer.Initialize // Activate the timer module
Timer.Items(Timer1).Interval = 500 // Set the Timer for 500ms
Timer.Start // Start processing all timers
Input(Hall_Sensor) // Make the Hall-Effect sensor pin an input
DelayMS(150) // Allow the LCD to warm up
Cls // Clear the LCD, and display
WriteAt(1,1,"RPM Meter") // default information
While 1 = 1 // Create an infinite loop
PreScaler = 0 // Reset PreScaler register
Timer.Items(Timer1).Enabled = True // Enable Timer1 event
Repeat
Repeat // Wait for a rising edge
Until Hall_Sensor = 1 Or Not Timer.Items(Timer1).Enabled
Repeat // Wait for a falling edge
Until Hall_Sensor = 0 Or Not Timer.Items(Timer1).Enabled
If Timer.Items(Timer1).Enabled Then // If Timer1 is still enabled,
PreScaler = PreScaler + 1 // then increment PreScaler
If PreScaler = 84 Then // If PreScaler = 84, then
Break // leave the Repeat Until loop
EndIf // as 84 * 2 * 60 = 10080
EndIf
Until Not Timer.Items(Timer1).Enabled // Keep looping until Timer1 times out (500mS)
Timer.Items(Timer1).Enabled = False // Disable Timer1, as it may have left early
PreScaler = PreScaler * 2 * 60 // * 2 = RPS, * 60 = RPM
If PreScaler > 9999 Then // If the output is over 9999
PreScaler = 9999 // then display 9999 by default
EndIf
WriteAt(2,1,DecToStr(PreScaler, 4)) // Display the variable on the LCD (always show 4 digits)
Wend
Notice that I cap the value of
PreScaler to 84, this is to ensure that my
program leaves the loop if the RPM > 10000, as 84 * 2 * 60 = 10080. The value of
PreScaler does not need to be capped, however if it rolls over 65535
during any math routine then your result/accuracy goes out the window. An easy
fix would be defining PreScaler as a different variable type (such as
LongInt for values up to
2,147,483,647).
Just to go one bit further on sample times, I have used 500mS (1/2 a second), so
the slowest recordable rate = 1 sample, which equals 1 * 2 * 60 (RPS to RPM) =
120. That is also my error rate (120 RPM), as I could miss one
sample each loop. If my sample time was 100mS, then my slowest sample speed
would be 1 * 10 * 60 (RPS to RPM) = 600. As you can see, the
error
rate increases as the sample time decreases... but its a matter of how fast
you need the data/want to display it that accounts for what sample speed your
happy with.
Where you can get the components;

 | Site Tutorial Index |
|  | 16F PIC Examples |
|  | 18F PIC Examples |
| |  | 7 Segment Displays |
| |  | 7 Segment Displays |
| |  | RS232 and UART |
| |  | Code Snippets |
|  | Handy Tips |