electromagnetic tether robot

Essay by HaliluluUniversity, Bachelor'sA, August 2014

download word file, 21 pages 0.0

Downloaded 1 times

1

Electromagnetic Tether Robot

EECE-281: Electrical and Computer Engineering laboratory

Professor: Dr. Jesus Calvino-Fraga, P.Eng.

L2C - CA

Sizhe Gao 12009122

Xiaoqing Li 18508127

Jingwen Lu 49019110

Le Ruan 35789122

Henry Xia 36270114

Lichen Yan 10645125

Date of Submission: Monday, April 7, 2014

2

Table of contents

1. Introduction……………………………………………………………………… ………...3

2. Investigation ……………………………………………………………………………….6

a. Idea Generation……………………………………………………………….…..6

b. Investigation Design………………………………………………………….…...6

c. Data Collection……………………………………………………………………6

d. Data Synthesis…………………………………………………………………….7

e. Analysis of Results………………………………………………………………..8

3. Design ………………………………………………………………………………………..8

a. Use of Process…………………………………………………………….……….8

b. Need and Constraint Identification……………………………………..…….......9

c. Problem Specification…………………………………………………..…………9

d. Solution Generation……………………………………………………...………10

e. Solution Evaluation………………………………………………………...…….12

f. Detailed Design………………………………………………………..………...13

g. Solution Assessment……………………………………………………………..18

4. Live-long learning……………………………………………………………………...…19

5. Conclusion………………………………………………………………………………….20

6. Reference……………………………………………………………………..…………….20

7. Bibliography………………………………………………………………..……...………21

8. Appendices…………………………………………………………………………………22

3

1. Introduction

1.a. Design Objective

For the second project of EECE 281, the team was asked to design, build, program, and test a

small autonomous robot in which the robot must be battery operated and controlled using a

microcontroller system. The robot must keep a fixed distance from an electromagnetic beacon. If

the beacon changes position, the robot must adjust its position to keep a constant distance from

the beacon. There should have at least four pieces of command from the transmitter: move closer,

move farther, turn 180 degree, and parallel parking, which the robot should follow.

1.b. Design Specifications

There were three major parts in designing this autonomous robot: the beacon, receiver and the

motor. In order to make these parts work as a whole, programs were written separately for the

beacon: - the data transmission program, and for the receiver located on the chassis. The

software programming on the microprocessors (AT89LP828 Microcontroller chip) was

implemented using C programming language.

The microprocessor on the beacon generated two square wave signals in different phases that

produced a strong magnetic wave using an LC circuit. There were also four buttons on the

microprocessor that sent signal to make the robot move forward and backward, turn 180 degree,

and parallel parking. There was another button on the transmitter to turn on/off the sensing mode

of the robot.

Another microcontroller system was used for the receiver that read the signal using two inductive

4

sensors and then determined the distance and direction from the beacon. The robot can sense the

signal from the transmitter at a minimum distance of 40cm. The furthest distance the car could

reach was 110 cm away from the beacon. The standard chassis was designed and distributed as a

part of a toolkit for the project.

1.c. Design Approach

1.c.1. Hardware Design Overview

5

1.c.2. Software Design Overview

6

2. Investigation

2.a. Idea Generation

Before the group started working on the project, there were two meetings discussing about the

general requirements of the project, as well as gathering ideas from each group member.

Different part was assigned to each member to carry on individual research. Then for the third

meeting, everyone came prepared with their researches and hypotheses. Each possible hypothesis

was discussed together as a team and chose the most efficient plan.

Based on the previous labs, basic functioning blocks such as peak detector, amplifier, H-bridge, motor

and ADC can be easily implemented into this project. Hence, the next step need to be considered is how

to connect those blocks together and how to implement LC circuit for signal transmission.

2.b. Investigation Design

By reading through the PDF files on Connect thoroughly, the group had the initial understanding

about the requirements and basic components for the project. In order to gain deeper

comprehension about the functionalities of every functioning block, each previous lab was

studied again within the group. Some research was done about how to create magnetic fields

using inductors, as well as how to enhance the fields using amplifiers. Therefore, the group came

up with a list of components that would be needed, together with a sketch of the general circuits

for both transmitter and receiver.

2.c. Data Collection

7

Essentially the resonance frequency of the transmitter was calculated using equation (f =

)

[1] and was compared with the resonance frequency of the simple LC circuit, as shown in

Figure.4, measured by the oscilloscope to see whether they match or not. The resulted resonance

frequency is approximately 14.8 kHz by both calculation and measurement. Hence, the

transmitter circuit was assembled and coded using its resonance frequency as 14.8 kHz. The

functionality of the transmitter was tested using a detector composed of an inductor, a capacitor,

and a LED in parallel, as shown in Figure.5. However, in order to light up the LED, it required a

very significant magnetic field. Eventually, a more precise range of magnetic field was measured

by replacing the LED light with an oscilloscope.

2.d. Data Synthesis

8

The measured data was analyzed by comparing with calculated results, as well as by comparing

with other groups' to reach appropriate conclusion. Also, it was confirmed with the teaching

assistance about the correctness of the data before moving on to the next stage.

On the other hand, in order to magnify the signal received by the receiver, it was necessary to

attach two amplifiers to the inductors before the signals go through peak detectors. LM 324 was

used as amplifiers. Since the gain = R2/R1 and a gain of 100 is required, R2 is chosen to be 1000

kΩ and R1 is chosen to be 10 kΩ. The schematics of amplifier are shown in Section 3.f.2 Figure

11.

2.e. Analysis of Results

Since the circuits were simulated successfully before assembling on the breadboard, the degrees

of error that can occur was limited. However, when there were errors occurred, they were

resolved by analyzing the correctness of each signal generated in the circuits.

Also, after testing the received voltage from the receiver inductors, a gain of 100 was proved to

be suitable for magnifying the voltage before going through peak detectors. Further adjustment

was done through the process of design and testing.

3. Design

3.a. Use of Process

The knowledge for the basic components was from the previous EECE 281 labs. Those basic

functioning blocks were built and tested before. Hence, the design was started based on those

existing circuits and was expanded from there. Then the design and the circuit were built and

9

simulated using Multisim before assembling the actual circuits onto the breadboards. Some

adjustments were made to the design until they were successfully simulated by Multisim. The

actual circuits were analyzed by comparing the outputs generated by oscilloscope with the

simulated results from Multisim to make sure they were reasonable. Sometimes consulting with

other groups and teaching assistances can be extremely helpful as well.

3.b. Need and Constraint Identification

One possible group of customers of this project are young children between age five and ten who

like playing around with toy cars. However, in order to reach safety requirements of children's

toys, every circuit needs to be put into a sealed chassis to prevent children from coming in

contact with any wires or chips. More importantly, the inductors need to be properly covered by

materials that neither conduct heat nor block signals, to protect children from burning themselves.

Also, in order to make the car look desirable, the chassis can be upgraded to look like a race car

instead of the ordinary features.

The product can also be used by police forces or militaries to scout unknown areas or packages

by adding a live camera on top of the car which transmits the footage wirelessly onto a remote

screen. Also, the transmitter can be connected to the receiver with a robotic arm so that its length

can be adjusted remotely. This design can then protect police and soldiers from walking into any

unknown situations which can risk their lives.

3.c. Problem Specification

One big challenge faced by the group was serial data transmission. Although the partial code for

serial data transmission was given by the instructor, the group decided to use a self-produced but

10

similar way to transmit data. However, it was really struggling that ADC could not get serial data

although peak detectors were able to give the correct voltage.

Also, in the code for receiver, two peak values from two inductors were read and saved into two

float variables, voltage_l for the left inductor and voltage_r for the right inductor. The magnitude

changed from 0 to approximately 3.7V. The group decided to work with this voltage because

these values can give a straight-forward examination on whether those basic blocks work

properly or not.

Having obtained the values, the group then had to choose the comparing standard for the sensing

mode. It has to be carefully decided since it will affect the sensitiveness of the robot in sensing

mode. Many adjustments have been done and a final solution has been reached.

3.d. Solution Generation

The main requirement for this project is to use microcontroller system to send signals from

transmitter. Then the receiver has to receive the signal and send commands to motors so that the

robot can react accordingly. The designed transmitter generates a strong magnetic field and the

receiver can receive signals within a range of 40cm to 110cm. The robot can also follow the

signal from the transmitter and move to wherever the transmitter points to, and at the same time,

keep a fixed distance of 40cm away from it. This distance can be adjusted by either changing the

preset distance in the code or adjusting the resistance of the variable resistor. In addition, there

are five buttons to control the movement of the robot: moving forward, moving backward,

turning 180 degrees, parallel parking, and deactivating the sensing mode.

11

After consulting with other groups, it was realized that the processing time of ADC has also to be

taken into consider. Therefore, there would be a delay on received serial data. Hence, the serial

data transmitted should be longer and the ADC timing need to be calibrated. Through many

adjustments and tests, it was found that the reacting time of ADC is approximately 0.4s.

Therefore the bit time was set to 0.2s and extra two zeros were sent after the start bit before the

actual serial data.

Also, after many adjustments and tests, it was decided that a ratio (voltage_l/voltage_r) of 1.1

and 0.9 is suitable for controlling the car from turning and a difference of 0.3V from the preset

distance ( equivalent voltage is 2V) is suitable for controlling the distance between the car and

transmitter. Therefore, as shown in Figure 6, if the voltage ratio (voltage_l/voltage_r) is greater

than 1.1 and smaller than 9, the car will turn right and if the voltage ratio is greater than 0.1 and

smaller than 0.9, the car will turn left. At the same time, if the detected average voltage is smaller

than the preset distance (2V) -0.3V, the car will move backward, and forward for an average

voltage greater than (preset distance+0.3V). If none of the conditions above applies, the car will

stay at its position without any movement.

12

3.e. Solution Evaluation

In the group's design, each section of the electromagnetically tethered vehicle and its

corresponding beacon was designed to meet the criteria given in the project instruction. The

beacon and receiver pair, for example, which was possibly the most critical part of the vehicle,

reliable sent signals up to a distance of 110cm, and the receiver side could accurately determine

the relative location of the beacon and thus react respectively. However, when the beacon was

shifted very quickly, the receiver sometimes became confused. This was the result of a trade-off

between micro-scale accuracy and macro-scale accuracy (if the motor speed was increased, the

vehicle could follow the beacon faster, but may have become inaccurate in smaller scales). The

13

serial data transmitter works by sending logic 0 and logic 1 signals. The receiver will wait for a

delayed time and then read the received signals. This design was chosen over others because it

was faster than others and worked with all the criteria; it was the most efficient option. The

motor system worked with pwm signals from the microcontroller, to an optoisolator, into two H-

bridges of MOSFETs to control the movement of the two DC motors. The motor ran at 60%

power, in order to have stable movements, as well as turning accuracy.

3.f. Detailed Design

3.f.1. Transmitter Design

a) Voltage Regulator (LM7805C) [2]

This chip is used for converting 9V input to 5V output. The detailed connection is shown in

Figure 7. The input channel is connected to 9V battery and the output channel is connected to the

Vcc port of the microcontroller.

b) H-Bridge

The H-Bridge changes the DC voltage to a square wave. The detailed circuit is shown in Figure 8.

14

The circuit uses 2* P12PF06 and 2*P16NF06. The resistor in the bridge has chosen to be 10k

and the two ports stating "signal from controller" are connected to P2.5 and P2.6 in the

microcontroller.

c) LC Circuit

The LC circuit has already been shown above in section 2.c Figure 4. The power is now replaced

by the output from the H-Bridge and the frequency is adjusted to its resonance frequency 14.7

kHz in the code. The inductor then will generate a strong magnetic field which will then be

detected by the receiver circuit.

d) Push Button

Figure 14 shows how to connect a push button into a circuit. In this project, 5 push buttons are

used, four for the basic requirement from the instruction, and one for activating/deactivating the

sensing mode of the robot.

15

3.f.2 Receiver Design

a) LC Circuit

The LC circuit in receiver has already been shown in Section 2.c Figure 5. The test LED is

removed and now becomes the input to the amplifier.

b) Amplifier (LM324)

Figure 10 shows the pin allocation of LM324 and Figure 11 shows the circuit connection of

LM324 used as an amplifier. The resistors chosen are 1000k and 10k as discussed before to give

16

a gain of 100. In the group's circuit, the outputs from the LC circuit are connected into channel 1

and channel 4 of the op-amp, being amplified 100 times, and then go into channel 2 and channel

3 of the op-amp, which are now used as peak detectors.

b) Peak Detector

This circuit is implemented twice for the two inductor circuits. The resistor used here is 10k and

the capacitor used is 220uF. The op-amp used is LM324. The power input is replaced by the

output from the amplifier channel and the output is measured across the RC parallel part.

d) ADC (MCP3004) [3]

17

Figure 12 shows the pin connection of the ADC (MCP3004). The CH0 and CH1 are connected

to the output of peak detectors. Hence by selecting channels, each peak value can be read directly

from ADC and then being compared by microcontroller.

e) DC Motors

Figure 13 shows the connection for DC motors, which uses 2* P12PF06 as P-MOSFET,

2*P16NF06 as N-MOSFET, LTV-847 as optoisolator, 47k as RT, and 1k as R0. It receives the

pwm input from microcontroller, and hence controls the speed and direction of the motors. Two

sets of DC motor circuits are required since the robot has two wheels.

3.f.3. Software Design

a) Code for Transmitter

The frequency of the transmitted signal is adjusted by changing the execution time of "wait0s"

function in the code. The longer the execution time, the smaller the frequency. After that, by

alternating P2.5 and P2.6, it can send a logic 1 signal and by making both of them 0, it can send a

logic 0 signal. Different states have different serial data transmitted: 1111 for activating sensing

18

mode, 0000 for moving forward, 0001 for moving backward, 0010 for turning 180 degrees, 0011

for parallel parking, and 0100 for deactivating sensing mode.

b) Code for Receiver

The logic block diagram for receiver sensing mode has been shown in the Section 1.c.2. Figure 3.

The basic logic blocks for receiver are GetSerialData, GetVoltage, commands to control the

movement of motor, and functions for each state.

Without any serial data transmitted (i.e. 1111), the microcontroller will first get the voltage from

ADC using GetVoltage, compare the voltages and decide which way to move in the sensing

mode. Once there is serial data received by GetSerialData, it will jump to each state respectively

(i.e. 0000 for model_1, 0001 for model_2, 0010 for model_3, 0011 for model_4, 0100 for

complement the variable "comp" and then proceed to deactivate sensing mode ). In each state,

there have different commands to control the movement of motors, for which will send different

pwm values to control the speed and directions.

3.g. Solution Assessment

The vehicle and beacon worked together well, the transmitter sending instructions to the vehicle,

and the vehicle receiving instructions and maintaining preset distances from the transmitter. The

vehicle also correctly determined if the beacon was to the left or right and moved to face it. With

a maximum working distance of 110 cm from the beacon, the vehicle could switch among 5

preset distances and kept those distances by moving with the beacon.

This design's strengths included the ability to move among 5 preset distances, and its maximum

distance of 110 cm, which was 60 cm more than the required maximum distance. The detection

19

of the relative horizontal displacement was accurate, up to a speed of about 45 degrees/second of

the beacon. Rather than the addition of extra features, our vehicle incorporated well-working

base features and the minimization of errors and glitches.

This design's weaknesses included the inability to detect sudden and large changes in horizontal

positions of the beacon, and sometimes executed unexpected movements during such occasions.

4. Live-long Learning

When we first started designing the project, we had obtained some knowledge about the

individual components from previous lab modules. However, it was still challenging to assemble

the whole circuit together. The greatest challenge that we had encountered was to pass the

correct signal to the robot from the transmitter using inductors. At first the idea of transmitting a

signal seemed to be vague, but as we learned more and more material from our other course

EECE 253, we were able to understand how MOSFET and LC circuit operated. Beside technical

skills, we also learned some important transferable skills including communication and problem

solving skills.

Communicating between group members is extremely important. Since it is difficult to gather all

of the members together, we created a facebook group to keep everybody in touch. Any changes

of the code or any new idea toward the project would be uploaded so every member will be on

the same page. When a dispute between ideas arises, effectively solve a problem and making

sure that there is consensus between the parties that are in conflict.

Beside communication skills, we also learned some important problem solving skills.

Throughout the design process of this project, from the initial brainstorming to prototyping,

20

many problems occurred. One of the biggest problems that we ran into was the microcontroller

ceasing to function. Through some testing, and also hints from the professors, we were able to

isolate the causes of the problem (such as the frying of the IC due to static electricity, or the

wrong connection of pins of the MOSFET bridge).

5. Conclusion

The robot car designed and created by our group chases the beacon from the standard distance of

50cm. The signal created by the С code logic and programmed into the microprocessor is

generated on the beacon, in our case it is a sinusoidal wave produced by turning the mosfets of

the "H" bridge on and off consecutively.

There is a lot of room for improvement. The whole circuit seems to be inefficient in terms of

current driven. As a result, a whole bunch of batteries had to be recharged and went to buy fresh

new battery just before the demo period. This is the part to be analyzeD and work on in order to

achieve better results for efficiency.

6. Reference

[1] Dr. Jesús Calviño-Fraga P.Eng, "EECE281/EECE282 Project 2: Electromagnetic

Tether Robot", January 27, 2014. Retrieved from:

https://connect.ubc.ca/bbcswebdav/pid-1931076-dt-content-rid-

7469216_1/courses/CL.UBC.EECE.281.201.2013W2.23944/EECE281_Project2_2014.pdf

21

[2]Texas Instruments, "LM78XX Series Voltage Regulators", May 2000 (Revised April 2013)

Retrieved from: http://www.ti.com.cn/cn/lit/ds/symlink/lm7805c.pdf

[3] Microchip, "2.7V 4-Channel/8-Channel 10-Bit A/D Converters with SPI™ Serial Interface",

2007

Retrieved from: http://ww1.microchip.com/downloads/en/DeviceDoc/21295C.pdf

[4] Ruan Lourens, "Low Frequency Transmitter" , 2008

Retrieved from: http://ww1.microchip.com/downloads/en/AppNotes/00232B.pdf>

7. Bibliography

"8051 Programming in C." Hanel, Web.

<http://xa.yimg.com/kq/groups/21447185/1325886378/name/08>.

"AT89LP828 Datasheet." Atmel, Web. <http://www.atmel.com/Images/doc3654A.pdf>.

Huang, H.W.(2000). Using the MCS51 Microcontroller. New York: Oxford University Press.

"LM2904,LM358/LM358A,LM258/ LM258A." Datasheet Catalog. Fairchild Semiconductor,

Web.. <http://www.datasheetcatalog.org/datasheet/fairchild/LM358.pdf>.

22

"LTV-817 Datasheet." Octopart,

<http://datasheet.octopart.com/LTV-817-Lite-On-datasheet-124899.pdf>.

8. Appendices

8.1. Transmitter Code

#include <stdio.h>

#include <at89lp51rd2.h>

// ~C51~

#define CLK 22118400L

#define BAUD 115200L

#define BRG_VAL (0x100-(CLK/(32L*BAUD)))

//We want timer 0 to interrupt every 100 microseconds ((1/10000Hz)=100 us)

#define FREQ 10000L

#define TIMER0_RELOAD_VALUE (65536L-(CLK/(12L*FREQ)))

//These variables are used in the ISR

volatile unsigned char pwmcount;

volatile unsigned char pwm1;

long int a=0;

unsigned char _c51_external_startup(void)

{

// Configure ports as a bidirectional with internal pull-ups.

P0M0=0; P0M1=0;

P1M0=0; P1M1=0;

P2M0=0; P2M1=0;

P3M0=0; P3M1=0;

P2M0 &= 0B_1111_1110;

P2M1 |= 0B_0000_0001;

AUXR=0B_0001_0001; // 1152 bytes of internal XDATA, P4.4 is a general purpose I/O

P4M0=0; P4M1=0;

// Initialize the serial port and baud rate generator

PCON|=0x80;

SCON = 0x52;

BDRCON=0;

BRL=BRG_VAL;

BDRCON=BRR|TBCK|RBCK|SPD;

// Initialize timer 0 for ISR 'pwmcounter()' below

TR0=0; // Stop timer 0

TMOD=0x01; // 16-bit timer

// Use the autoreload feature available in the AT89LP51RB2

// WARNING: There was an error in at89lp51rd2.h that prevents the

// autoreload feature to work. Please download a newer at89lp51rd2.h

// file and copy it to the crosside\call51\include folder.

TH0=RH0=TIMER0_RELOAD_VALUE/0x100;

TL0=RL0=TIMER0_RELOAD_VALUE%0x100;

TR0=1; // Start timer 0 (bit 4 in TCON)

ET0=1; // Enable timer 0 interrupt

EA=1; // Enable global interrupts

23

return 0;

}

void wait100ms ()//wait 100ms

{

_asm

;For a 22.1184MHz crystal one machine cycle

;takes 12/22.1184MHz=0.5425347us

mov R2, #4

L3: mov R1, #210

L2: mov R0, #184

L1: djnz R0, L1 ; 2 machine cycles-> 2*0.5425347us*184=200us

djnz R1, L2 ; 200us*250=0.05s

djnz R2, L3 ; 0.05s*20=1s

ret

_endasm;

return;

}

void wait0s(void)

{

_asm

;For a 22.1184MHz crystal one machine cycle

;takes 12/22.1184MHz=0.5425347us

mov R2, #1

L6: mov R1, #1

L5: mov R0, #16

L4: djnz R0, L4 ; 2 machine cycles-> 2*0.5425347us*184=200us

djnz R1, L5 ; 200us*250=0.05s

djnz R2, L6 ; 0.05s*5=0.25s

ret

_endasm;

return;

}

void waitxs(void)

{

_asm

;For a 22.1184MHz crystal one machine cycle

;takes 12/22.1184MHz=0.5425347us

mov R2, #1

L9: mov R1, #1

L8: mov R0, #12

L7: djnz R0, L7 ; 2 machine cycles-> 2*0.5425347us*184=200us

djnz R1, L8 ; 200us*250=0.05s

djnz R2, L9 ; 0.05s*5=0.25s

ret

_endasm;

return;

}

void sendsignal( )

{

if(P2_5==1)

{

P2_5=0;

P2_6=1;

}

else

{

P2_5=1;

P2_6=0;

}

wait0s();

return;

}

void sendsignal_long( )

{

for(a=5000;a>0;a--)

24

{

if(P2_5==1)

{

P2_5=0;

P2_6=1;

}

else

{

P2_5=1;

P2_6=0;

}

waitxs();

}

return;

}

void main (void)

{

_c51_external_startup();

P2_5=1;P2_6=0;

while(1)

{

// sendsignal( );

if(P2_1 == 0)

{

P2_5=0;//star bit 0// 0 000 000 00

P2_6=0;

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//stop bit 0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

}

else if(P2_2 == 0)

{

P2_5=0;

P2_6=0;//0 start bit// 0 000 001 00

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

25

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

sendsignal_long();//1

P2_5=0;

P2_6=0;//stop bit 0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

// P2_2=1;

}

else if(P2_3 == 0)

{

P2_5=0;

P2_6=0;// 0 start bit// 0 000 010 00

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

sendsignal_long();//1

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//stop bit 0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

}

else if(P2_4 == 0)

{

P2_5=0;

P2_6=0;// 0 start bit//0 000 011 00

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

26

sendsignal_long();//1

sendsignal_long();//1

P2_5=0;

P2_6=0;//stop bit 0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

}

else if (P2_7 == 0)

{

P2_5=0;

P2_6=0;// 0 start bit//0 000 100 00

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

sendsignal_long();//1

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

P2_5=0;

P2_6=0;//stop bit 0

wait100ms();

P2_5=0;

P2_6=0;//0

wait100ms();

}

else

{

sendsignal();

}

}//while

}

8.2. Receiver Code

// This program shows how to connect and access the MCP3004 ADC

// to the LP51B board.

//

// (c) Jesus Calvino-Fraga 2014

// Not to be copied, used, or revised without explicit written

// permission from the copyright owner.

//

#include <math.h>

#include <stdio.h>

#include <at89lp51rd2.h>

#include <stdlib.h>

#include <time.h>

27

// ~C51~

#define CLK 22118400L

#define BAUD 115200L

#define BRG_VAL (0x100-(CLK/(32L*BAUD)))

//We want timer 0 to interrupt every 100 microseconds ((1/10000Hz)=100 us)

#define FREQ 10000L

#define TIMER0_RELOAD_VALUE (65536L-(CLK/(12L*FREQ)))

volatile unsigned char pwmcount=0;

volatile unsigned char pwm1;

volatile unsigned char pwm2;

volatile unsigned char pwm3;

volatile unsigned char pwm4;

unsigned int mode=0;

unsigned int direction=0;

float distance=2;

unsigned char _c51_external_startup(void);

void wait100ms (void);

void wait50ms (void);

void wait45degree (void);

void SPIWrite(unsigned char);

unsigned int GetADC(unsigned char);

float GetVoltage (unsigned char);

//void pwmcounter (void) interrupt 1;

void leftwheelforward(void);

void leftwheelbackward(void);

void rightwheelforward(void);

void rightwheelbackward(void);

void leftwheelstop(void);

void rightwheelstop(void);

unsigned char model_0(float, float, int);

unsigned char model_1(void);

unsigned char model_2(void);

unsigned char model_3(void);

unsigned char model_4(void);

int GetSerialMode (float);

int complement(int);

unsigned char _c51_external_startup(void)

{

// Configure ports as a bidirectional with internal pull-ups.

P0M0=0; P0M1=0;

P1M0=0; P1M1=0;

P2M0=0; P2M1=0;

P3M0=0; P3M1=0;

P2M0 &= 0B_1100_0000;

P2M1 |= 0B_0011_1111;

P3M0 &= 0B_0011_1111;

P3M1 |= 0B_1100_0000;

AUXR=0B_0001_0001; // 1152 bytes of internal XDATA, P4.4 is a general purpose I/O

P4M0=0; P4M1=0;

// Instead of using a timer to generate the clock for the serial

// port, use the built-in baud rate generator.

PCON|=0x80;

SCON = 0x52;

BDRCON=0;

BRL=BRG_VAL;

BDRCON=BRR|TBCK|RBCK|SPD;

TR0=0; // Stop timer 0

TMOD=0x01; // 16-bit timer

// Use the autoreload feature available in the AT89LP51RB2

// WARNING: There was an error in at89lp51rd2.h that prevents the

// autoreload feature to work. Please download a newer at89lp51rd2.h

// file and copy it to the crosside\call51\include folder.

TH0=RH0=TIMER0_RELOAD_VALUE/0x100;

28

TL0=RL0=TIMER0_RELOAD_VALUE%0x100;

TR0=1; // Start timer 0 (bit 4 in TCON)

ET0=1; // Enable timer 0 interrupt

EA=1; // Enable global interrupts

pwmcount=0;

return 0;

}

// Interrupt 1 is for timer 0. This function is executed every time

// timer 0 overflows: 100 us.

void pwmcounter (void) interrupt 1

{

if(++pwmcount>99)

pwmcount=0;

P2_0=(pwm1>pwmcount)?1:0;// left wheel

P2_1=(pwm2>pwmcount)?1:0;// left wheel

P2_2=(pwm3>pwmcount)?1:0;// right wheel

P2_3=(pwm4>pwmcount)?1:0;// right wheel

}

void main (void)

{

float voltage_l=0;//left sesnsor voltage

float voltage_r=0;//right sensor voltage

float voltage_ratio=voltage_l/voltage_r;

float voltage_ave= (voltage_l+voltage_r)/2;

int val=1111;

int comp = 0;

P2_4 = 0;

P2_5 = 0;

P3_6 = 0;

P3_7 = 0; //initialize LED

// float distance=2;

_c51_external_startup();

while(1)

{

voltage_l = GetVoltage(0);

voltage_r = GetVoltage(1);

voltage_ratio = voltage_l/voltage_r;

voltage_ave = (voltage_l+voltage_r)/2;

leftwheelstop();

rightwheelstop();

P3_6 = comp;

if(voltage_l <(distance*0.4))//start bit received

{

val=GetSerialMode(distance);

}

if (val==110)

{

comp = complement(comp);

}

else if (comp==0)

{

if (val==1111)

{

leftwheelstop();

rightwheelstop();

29

model_0(voltage_ratio, voltage_ave, direction);//sensing mode

voltage_l = GetVoltage(0);

voltage_r = GetVoltage(1);

voltage_ratio = voltage_l/voltage_r;

voltage_ave = (voltage_l+voltage_r)/2;

}

if (val==0)

{

model_1();//move forward

distance = GetVoltage(0);

val=1111;

}

if (val==1)

{

model_2();//move backward

distance = GetVoltage(0);

val = 1111;

}

if (val==10)

{

model_3();//180

leftwheelstop();

rightwheelstop();

if (direction==0)

{

direction = 1;

}

else

{

direction = 0;

}

distance = GetVoltage(0);

val = 1111;

}

if (val==11)

{

model_4();//parallel parking

leftwheelstop();

rightwheelstop();

distance = GetVoltage(0);

val = 1111;

}

else

{

val=1111;

}

}

else if (comp==1)

{

if (val==1111) //stop

{

leftwheelstop();

rightwheelstop();

}

if (val==0) //forward

{

leftwheelforward();

rightwheelforward();

wait100ms();

wait100ms();

30

wait100ms();

wait100ms();

wait100ms();

wait100ms();

wait100ms();

wait100ms();

leftwheelstop();

rightwheelstop();

val=1111;

}

if (val==1) //backward

{

P2_4 = 1;

leftwheelbackward();

rightwheelbackward();

wait100ms();

wait100ms();

wait100ms();

wait100ms();

wait100ms();

wait100ms();

wait100ms();

wait100ms();

leftwheelstop();

rightwheelstop();

val=1111;

P2_4 = 0;

}

if (val==10) //left turn

{

leftwheelforward();

rightwheelbackward();

P2_5 = 1;

wait45degree();

wait45degree();

P2_5 = 0;

leftwheelstop();

rightwheelstop();

val=1111;

}

if (val==11) //right turn

{

leftwheelbackward();

rightwheelforward();

P3_7 = 1;

wait45degree();

P3_7 = 0;

leftwheelstop();

rightwheelstop();

}

else

{

val=1111;

}

}

}

}

int GetSerialMode (float distance_1)

{

float voltage_l_1 = 0;

int j;

int x=0;

wait100ms();

for(j=0;j<4;j++)

31

{

x=x*10;//shift x left

voltage_l_1 = GetVoltage(0);

if(voltage_l_1 > (0.5*distance_1) )

{

x++;

}

wait100ms();

}

if(x==0)

{

P0_0 = 0;

}

else if(x==10)

{

P0_2 = 0;

}

else if(x==11)

{

P0_3 = 0;

}

return x;

}

void wait100ms (void) // wait 200ms

{

_asm

;For a 22.1184MHz crystal one machine cycle

;takes 12/22.1184MHz=0.5425347us

mov R2, #4

L3: mov R1, #248

L2: mov R0, #184

L1: djnz R0, L1 ; 2 machine cycles-> 2*0.5425347us*184=200us

djnz R1, L2 ; 200us*250=0.05s

djnz R2, L3 ; 0.05s*20=1s

ret

_endasm;

return;

}

void wait50ms (void) // wait 50ms

{

_asm

;For a 22.1184MHz crystal one machine cycle

;takes 12/22.1184MHz=0.5425347us

mov R2, #2

L9: mov R1, #239

L8: mov R0, #184

L7: djnz R0, L7 ; 2 machine cycles-> 2*0.5425347us*184=200us

djnz R1, L8 ; 200us*250=0.05s

djnz R2, L9 ; 0.05s*20=1s

ret

_endasm;

return;

}

void wait45degree (void) // wait 45

{

_asm

;For a 22.1184MHz crystal one machine cycle

;takes 12/22.1184MHz=0.5425347us

mov R2, #26

L6: mov R1, #80

L5: mov R0, #184

L4: djnz R0, L4 ; 2 machine cycles-> 2*0.5425347us*184=200us

djnz R1, L5 ; 200us*250=0.05s

32

djnz R2, L6 ; 0.05s*20=1s

ret

_endasm;

return;

}

void SPIWrite(unsigned char value)

{

SPSTA&=(~SPIF); // Clear the SPIF flag in SPSTA

SPDAT=value;

while((SPSTA & SPIF)!=SPIF); //Wait for transmission to end

}

// Read 10 bits from the MCP3004 ADC converter

unsigned int GetADC(unsigned char channel)

{

unsigned int adc;

// initialize the SPI port to read the MCP3004 ADC attached to it.

SPCON&=(~SPEN); // Disable SPI

SPCON=MSTR|CPOL|CPHA|SPR1|SPR0|SSDIS;

SPCON|=SPEN; // Enable SPI

P1_4=0; // Activate the MCP3004 ADC.

SPIWrite(channel|0x18); // Send start bit, single/diff* bit, D2, D1, and D0 bits.

for(adc=0; adc<10; adc++); // Wait for S/H to setup

SPIWrite(0x55); // Read bits 9 down to 4

adc=((SPDAT&0x3f)*0x100);

SPIWrite(0x55);// Read bits 3 down to 0

P1_4=1; // Deactivate the MCP3004 ADC.

adc+=(SPDAT&0xf0); // SPDR contains the low part of the result.

adc>>=4;

return adc;

}

float GetVoltage (unsigned char channel)// geting the voltage of the leftside of the car

{

return ( (GetADC(channel)*5.8)/(1023.0)); // VCC=4.84V (measured)

}

unsigned char model_0(float voltage_ratio_0, float voltage_ave_0, int direction_0)//sensing mode

{

if(voltage_ratio_0>1.1 && voltage_ratio_0<9)//go right

{

P3_7 = 1;

P2_5 = 0;

if(direction_0==0)

{

leftwheelforward();

rightwheelbackward();

}

else

{

leftwheelbackward();

rightwheelforward();

}

}

else if( voltage_ratio_0<0.9 && voltage_ratio_0>0.1)//go left

{

33

P2_5 = 1;

P3_7 = 0;

if(direction_0==0)

{

rightwheelforward();

leftwheelbackward();

}

else

{

rightwheelbackward();

leftwheelforward();

}

}

else if( voltage_ratio_0>9 || voltage_ratio_0<0.1)

{

leftwheelstop();//stop

rightwheelstop();

P2_5 = 0;

P3_7 = 0;

}

else

{

leftwheelstop();//stop

rightwheelstop();

P2_4 = 0;

P2_5 = 0;

P3_7 = 0;

if (voltage_ave_0< (distance-0.3))//go

{

P2_4 = 0;

if(direction_0==0)

{

leftwheelforward();

rightwheelforward();

}

else

{

leftwheelbackward();

rightwheelbackward();

}

}

else if(voltage_ave_0> (distance+0.3))//back

{

P2_4 = 1;

if(direction_0==0)

{

rightwheelbackward();

leftwheelbackward();

}

else

{

rightwheelforward();

leftwheelforward();

}

}

else

{

P2_4 = 0;

leftwheelstop();//stop

rightwheelstop();

}

}//else

return 0;

}

unsigned char model_1(void)/// small car follow remote in short distance.

{

leftwheelforward();

34

rightwheelforward();

wait100ms();

wait100ms();

wait100ms();

wait100ms();

leftwheelstop();//stop

rightwheelstop();

return 0;

}

unsigned char model_2(void)/// small car follow remote in longer distance

{

leftwheelbackward();

rightwheelbackward();

P2_4 = 1;

wait100ms();

wait100ms();

wait100ms();

wait100ms();

leftwheelstop();//stop

rightwheelstop();

P2_4 = 0;

return 0;

}

unsigned char model_3(void) // in this model the car will rotate 180 degree and after 2 seconds

in will turn back again;

{

leftwheelforward();

rightwheelbackward();

P2_5 = 1;

wait45degree();

wait45degree();

wait45degree();

wait45degree();

leftwheelstop();//stop

rightwheelstop();

P2_5 = 0;

return 0;

}

unsigned char model_4(void)// parallel parking model

{

P2_4 = 1;

leftwheelforward();

rightwheelbackward();

wait45degree();

leftwheelbackward();

rightwheelbackward();

wait45degree();

wait45degree();

wait45degree();

wait45degree();

wait45degree();

leftwheelbackward();

rightwheelforward();

wait45degree();

leftwheelstop();//stop

rightwheelstop();

P2_4 = 0;

return 0;

35

}

void leftwheelforward(void) // leftwheel go forward

{

pwm1=60;

pwm2=0;

return;

}

void leftwheelbackward(void) // leftwheel go backward

{

pwm1=0;

pwm2=60;

return;

}

void rightwheelforward(void) // rightwheel go forward

{

pwm3=55;

pwm4=0;

return;

}

void rightwheelbackward(void) // rightwheel go backward

{

pwm3=0;

pwm4=55;

return;

}

void leftwheelstop(void)

{

pwm1=0;

pwm2=0;

return;

}

void rightwheelstop(void)

{

pwm3=0;

pwm4=0;

return;

}

int complement(int comp_1)

{

if (comp_1 == 1)

{

comp_1 = 0;

}

else if (comp_1 == 0)

{

comp_1 = 1;

}

return comp_1;

}