Professional Documents
Culture Documents
Introduction
The goal of our project was to build a device to measure distance based around
the OUSB board using the ATMEGA32, programming the device using assembler.
To achieve this we decided use the parallax ping sensor which is able to measure
distances between 2cm and 3m, and using a serial LCD or the LEDs built onto
the OUSB board to display the distance measured.
The device operation is split into 4 main sections, the device initialisation, the
ping sensor operation subroutine, the display routine and delays. The general
device operation is given in Figure 1.
Figure 1
Operation:
In device initialisation the program sets up any required registers and peripherals
used. For this project it sets the stack pointer to RAMEND allowing the use of
subroutine calls in the code allowing separation of code, then registers R0 and
R1 are set to 0 and 1 respectively so they can be used for 0 and 1. Port B is then
set as an output as this port is used to write to the serial LCD or to drive the
LEDs based on which display routine is selected. Followed by a call to
PingTimerSetup which sets up the 8-bit timer used when communicating with the
ping sensor.
The Ping sensor operation subroutine is the first subroutine call in the main loop
of the program, this subroutine is responsible for controlling the ping sensor and
reading in the value representing the distance measured. The communication
with the sensor occurs over a single pin, with the protocol used defined in the
datasheet. To begin a measurement a single pulse is sent over the line, the
microcontroller must then listen on this line (setting it as an input) waiting for the
response. The response sent by the sensor is a single pulse, with the width of the
pulse representing the distance measured. Our project uses the built in 8-bit
hardware timer to measure the width of this pulse. Once the pulse width has
been measured, the communication line is then reset back to an output and the
value representing the distance is read from the timer and stored in a general
purpose register. Timing of the communication with the sensor required that the
device be able to meet the timing requirements with the sensor. These values
are given in the datasheet shown in figure 1.
Figure 2
The display subroutine uses the value given by the ping subroutine and uses it to
display the distance. For out project there are two methods available to be used
to display the distance though they are unable to be used at the same time. The
first uses the LEDs built onto the OUSB board, lighting up one of the eight LEDs
depending on the distance measured, with shorter distances being represented
by one of the leftmost LEDs being lit up, and longer distances represented by
one of the rightmost LEDs being lit up. To display the distance on the LEDs we
split each LED into representing distances of the maximum distance able to be
measured by the sensor divided by the number of LEDs, resulting in each LED
representing a distance of approximately 37cm. For example if the 4 th LED from
the left was lit up, that would mean a distance between 112cm and 150cm.
The second method for displaying the measured distance using the serial LCD
uses part of the example code given to drive it. This code sends one character at
a time to the LCD using one pin on port b as the output. This required converting
the value read from the ping sensor into ASCII characters that can be displayed
on the LCD. To do this we multiplied the ping sensor value by 145, which is the
distance that a single tick of the timer represents. To then convert that value into
ASCII characters we subtract whichever unit of measurement we are attempting
to display, until the value is less than that unit. For example, if after the
multiplication the sensor value is 234, we subtract 100 from the value in a loop
incrementing a counter each time until the value is less than 100. So at the end
of the 100s loop, we would end up with the counter being 2. We can then add
this to the ASCII value of 0 to determine the ASCII value for 2, which we then
output to the LCD. Repeating this process for 10s and 1s.
The final subroutine in the main loop is one that simply acts as a delay, this
allows time for the ping sensor to get ready for the next measurement and to
slow down the loop somewhat. This delay is equal to approximately 5ms and is
implemented using a nested loop that increments two registers from 0 to 255.
To test and develop our program we primarily used VMLab, checking that our
registers displayed the values we were expecting, though to check timing
required testing the device with the sensor.
One special feature of our program is that is uses one of the hardware timers to
measure the width of the pulse received from the ping sensor. This simply allows
us to start the timer at the rising edge of the pulse and stop the timer at the
falling edge of the pulse. To ensure that the timer was able to measure the entire
pulse width required setting the timer prescaler. For the 8-bit timer to be able to
measure from the rising edge to the falling edge (t IN-MAX in figure 1) a prescaler of
1024 was used. One of the problems with this approach is that the distance will
be measured using 8-bit resolution, meaning the measurement will be within one
of the 255 values available. But this is not entirely correct as t IN-MAX does not
represent the same time as the maximum time for the timer. t IN-MAX actually
occurs when the timer is at 217. Meaning 3m is represented by a value of 217,
and any intermediate value a fraction of that (1.5m would be represented by a
timer value of 108). This gives our device a measurement resolution of 1.3cm,
which for displaying the distance in centimeters is just acceptable for out
purposes. To make this more accurate there are two options, the first is to use a
16-bit timer as opposed to the 8-bit. This would allow for a lower prescaler as
well as more bits representing the distance. With 65536 values for the 16-bit
timer, and tIN-MAX corresponding with a value of approximately 27777, each tick
would represent a distance of about 0.1mm. The second possible method is a
loop that increments a counter in the subroutine itself, this has the benefit of not
requiring the hardware counter, but requires more programming within the
subroutine to make the loops and requires accurate knowledge of the amount of
time each loop represents. Another added benefit of using the 8-bit timer is that
it mostly avoids 16-bit values which can increase code complexity.
Improvements
At the start of the project we thought that such system would be easy to design
and implement but as we got closer to develop the code and looked at more
small details we realised that its much more complicated due to having an LCD
in the system but using ATMEGA 32 was a really good option due to it having
enough memory of 32K.
Ghannt chart
Refection:
William O'Connell
Terrisa Pro Forma
-
Your mark 3
I have not marked it as one more difficult because there were only a
couple of times when I had difficulty in getting a portion of the program
working as I wanted it to.
No change
To become more confident with a similar task I will need to become more
familiar with coding in assembler and how to use two or more registers
when calculating larger numbers (such as needing to multiply a 16-bit or
larger number).
I personally found the most difficult part of this project to be using the provided
code for the serial LCD. Initially I had some difficulty getting the example working
and converting the sensor reading to ASCII codes to display, though this was
overcome with some trial and error. I initially thought that the most difficult part
would be communicating with the ping sensor, but the timing restrictions on the
device were easier to meet than I expected making it easy to design code that
could meet the requirements.
If I were doing this as part of a paid project, I would be more concerned about the
accuracy of the timing (using the 16-bit timer instead of the 8-bit) and possibly
attempt to move the measuring of the input pulse from the timer from simply
polling the pin to watch for the rising and falling edge, to attaching the sensor to
a pin that is able to trigger interrupts on the rising and falling edges, and using
those interrupts to control the timer. Allowing for more processing time for other
parts of the program (assuming additional functions are added, as its not really
required for this project as is).
Familiarizing our team with the code associated with the LCD module and
ATMega32.
Before Evaluation:
Evaluate the complexity of this project:
4
Write down the reasons why you have not evaluated the question as
one level less difficult:
Our team has yet to familiarize ourselves with the components being used for
the project.
Appendix:
Appendix 1 Program code
.include "C:\VMLAB\include\m32def.inc"
; Addr $01
reti
; Addr $02
reti
; Addr $03
reti
; Addr $04
reti
; Addr $05
reti
; Addr $06
reti
; Addr $07
reti
; Addr $08
reti
; Addr $09
reti
; Addr $0A
reti
; Addr $0B
reti
; Addr $0C
reti
; Addr $0D
reti
; Addr $0E
reti
; Addr $0F
reti
; Addr $10
forever:
CALL Ping
;CALL Display ; Display the distance on the LEDs, cannot be used at the same
time as the LCD
CALL DisplayLCD ; Displays the distance on the LCD in centimeters
CALL Delay ; delay for ~5Ms
rjmp forever
;;
;; Converts the value stored in temp to thermometer LED display
;;
Display:
; If Temp < 27 Light LED 1
RET
Higher4:
RET
; End Display
;
; Sets up timer 1 for the Ping function
;
PingTimerSetup:
; Set Timer0 to normal mode
; TCCR0 &= ~(1<<WGM01 | 1<<WGM00)
; Clock select
; Ensure clock is stopped
; TCCR0 &= ~(1<<CS02 | 1<<CS01 | 1<<CS00)
CLR Temp
OUT TCNT0, Temp
;
; Uses the ping sensor to find the distance.
;
Ping:
; Set sig as output
SBI DDRC, PC7
pingWait2:
SBIS PINC, PC7
RJMP pingWait2
; Timer/counter
; Set time to start at 0
CLR Temp
OUT TCNT0, Temp
; Stop timer
IN Temp, TCCR0
ANDI Temp, ~(1<<CS02 | 1<<CS01 | 1<<CS00)
OUT TCCR0, Temp
Delay:
clr r20
clr r21
end_delay:
RET
;---------------Convert binary distance value to decimal--------------------; requires multilplying the distance by 145 (representing 1.45mm)
; by the number of timer ticks that occurred (value in Temp)
; Output will be a 16-bit value, to then be converted into decimal
DisplayLCD:
; Set LCD cursor to start
LDI SER_REG, 0x0C
CALL Delay
CALL serial_out
CALL serial_out
CLR Temp3
OnesLoop:
INC Temp3
; Temp:Temp2 - 0:Temp4
SUBI Temp, 100 ; subtract low byte
SBCI Temp2, 0
CALL serial_out
;'m'
;----------------sends byte to port on bit at a time -------------------; emulates rs232 serial output
; assumes we're connected to PB7
serial_out:
clr SER_REG1
out PORTB, Zero ; start bit
call B_DELAY
ror SER_REG
ror SER_REG1
;output B4
ror SER_REG
ror SER_REG1
;output B5
call B_DELAY
ror SER_REG
ror SER_REG1
ror SER_REG1
;output B7
call B_DELAY
; out PORTB, zero
; call B_DELAY
out PORTB, one
call B_DELAY
call B_DELAY
ret
; Start at 0xFF
brne BD_0
; Start at 0xFF
brne BD_1
ret
; 4 cycles
SD_0:
dec DELAYL
; Start at 0xFF
brne SD_0
ret
; 4 cycles
;
L_DELAY:
; ret
clr DELAYM
clr DELAYL
D_0:
dec DELAYL
brne D_0
dec DELAYM
brne D_0
; Start at 0xFF
; inner loop 3 cycles.
;
; middle loop
dec DELAYH
brne D_0
;outer loop.
ret
;
;
DELAY_96:
; ret
clr DELAYL
ldi DELAYH, 5
D_96:
dec DELAYL
; Start at 0xFF
brne D_96
dec DELAYH
brne D_0
ret
;outer loop.