SECTION 1 Hardware *

Chapter 1 *

Introduction *

The Master plan *

Getting the Act together *

What is a microcontroller ? and Which microcontroller? *

Which PIC language? *

The Software Shopping List *

The Tutor *

Text Editor *

MicroChip’s MPLAB *

The program to get our program into the PIC *

Starter Kit *

Defining the Computer *

Sensors *

The PIC’s 18 pins *

Where to find the Starter Kit *

Chapter 2 *

The PCB *

The PCB Shopping List *

The Theoretical Circuit *

Component List *

The Electrical circuit Diagram *

The PCB track Layout process *

PCB layout program *

I Boob… No, two boobs *

The Print process. *

Calibrating the Scale *

Other print problems *

More Boobs… ExpressPCB was right ! *

Other print process problems? *

WARNING WARNING WARNING *

Waste elimination *

Chapter 3 *

Photographic Stuff *

Photographic shopping list *

The Photo frame *

The Chemicals *

Mixing the Chemicals *

The Test strip *

Exposing the PCB Tracks *

Here we go this is real *

Drilling the board *

CHAPTER 4 *

Inserting and Soldering the Components *

Colour code *

The PIC programmer *

Final shopping List *

Component List *

SECTION 2 Writing Code for the PIC *

CHAPTER 5 *

Introduction *

The First attempt to define the bike computer *

Start of my original notes *

End of my original notes *

The First Steps after pseudo code *

Making Firstest Work *

What to do with the HEX file *

Setting up ICPROG *

Summing up *

CHAPTER 6 *

A simple Hex to Decimal routine *

Debugging " myh2dec.asm" with MPASM *

The Watch Window *

The F5, F6, F7 and ( control + F9 ) keys *

The StopWatch Window *

Debug Break settings *

The Stack window *

Summing up using MPASM *

The Basic Windows *

The Menus we have used till now *

CHAPTER 7 *

MPLAB Number Formats *

Letter Case conventions *

More on generating code *

The hex2dec Time problem with Big number *

CHAPTER 8 *

The Bike Computer Flow diagram, simple version *

The Flow-Chart *

Resolution Available *

Back to the Flow Chart *

The Automatic menu *

The Complete Loop Execution Time *

Compromises *

CHAPTER 9 *

Nuts and Bolts *

Math routines *

LOGIC routines *

Conversion routines *

HEX to DECIMAL *

HEX FRACTIONS to DECIMAL FRACTIONS *

NUMBER SCALING *

LCD Setup, Signalling and data transfer routines *

Automatic menu (2) *

Bike3.asm *

The END Product the HEX file *

Appendix 1 Updated diagrams *

PCB of Bike computer and test accessories. *

The Theoretical diag. +component layout *

 

 

SECTION 1 Hardware

Chapter 1

Introduction

There are so many embedded controller products in the house these days that many of us feel we ought to know a little more about how they work. They’re the brains inside things like the washing machine and so many other present day domestic appliances.

My first personal microchip contact was a friend’s radio controlled car which "died" and was brought to me for repair I being his resident radio expert.

The opened toy had very little inside, a small receiver, ( it was ok) and a small chip beside it, controlling the motors to the wheels. The chip was a PIC. I was out of my depth, best learn how….!!!

The reason for the PIC being there was obvious to me as an engineer. The printed circuit board was surprisingly empty. That meant the PIC program was replacing a lot of the traditional circuit’s resistors diodes and other hardware.

I decided I wanted to do something similar . Learn how to program was a priority in my mind, but not as a theoretical exercise, no, I like to get something useful at the end of any project.

Bathroom Scales? No, nor a toaster, nor the water heater. They all involved a lot of hardware, with unfamiliar thermistor sensors. My thoughts turned to my bike. It had a computer, very small and the sensor input was minimal. Yes, that was it, a Bike Computer project….. and so it started.

 

The Master plan

There are many ways to plan a project. But often, the steps we know don’t even figure because they are so obvious….This can cause enormous headaches for us beginners. So we will try and follow a logical sequence by spelling out everything that has to be done . There are two big areas to cover, the hardware and it’s construction, then the software and it’s application. The hardware is generally said to be the easiest part of the two so lets start there

Getting the Act together

The initial project outline was supposed to show the major activities and thus the equipment needed. The "equipment" including physical things like PCB and program things like the micro and language. The "idea" diagram is very bare and cryptic, but gets filled in as the project progresses. So we start with.

fig1 .Start

 

 

It was very clear from the start that ( for me ) the hardware box was easy to define and make, whereas the software box was full of unknowns. So let’s look at the Software questions.

 

What is a microcontroller ? and Which microcontroller?

I had found out by then that microcontroller is not just another word for microprocessor, no indeed. A micro controller is a stand-alone system that can calculate and connect itself with minimum peripherals directly to the outside world. The microprocessor also can calculate but needs a lot of interfacing to get the results to a screen or to a display.

 

Which microcontroller was harder to get to grips with. After going through an initial list it became all too clear that the abundant choice was aimed at experts, it was not for a beginner. That narrowed things down. The PIC , my first contact, caught my eye time and again, because of the many articles on offer on the internet and more important, explaining how to make things with it.

So I read more; specifically about PICs to find the really basic stuff. The PICLIST was a great starting point, as it talked about activities I had never even thought about. Especially, how do you test what you are proposing to make, some sort of simulation was an obvious must. This narrowed the field down further to things like the 16C84, now slightly obsolete.

 

Which PIC language?

My searching had uncovered a company called Microchip, which had from the goodness of it’s heart provided a program to check that the code you were writing was correct. It had a site that offered data sheets on it’s products, and almost all the net sites that talked about PIC’s directed you there.

What nobody actually said was which language was better,

ASSEMBLER OR C ( OR C++, OR ???).

As I know a little about C it initially attracted me, but somehow I began to get the feeling it was an overkill and that the routines were a bit unwieldy. Also it seemed to be an additional buffer between you and the microcontroller. During my search someone had commented in an article that correctly written assembler was very compact and made best use of the "scarce" memory.

So I decided on Assembler. But what was exactly assembler? I thought assembler code was universal, but it comes in many flavours. PIC assembler is not the same as that of Intel nor Motorola to cite some of the more important names., but PIC was widely used. Not a very logical way to arrive at a conclusion, but it happened that way.

 

The Software Shopping List

We now had a starting point and the needed bits and pieces began to become clear.

  1. Find a tutor which explained the PIC
  2. Find out how to use MPASM
  3. Find out about MPLAB
  4. Find out how to get the code into the PIC

 

The Tutor

There are so many. However one caught my eye as it was big, illustrated and FREE. After working through it steadily for a couple of days, it pointed me towards two important areas for getting started.

After a week of reading the tutor I found I could not put off any longer doing something about getting a suitable editor and an emulator. They had to be obtained.

 

Text Editor

When I’m not writing with a word processor, I use a smaller freeware program called EditPad . The big word processing programs use a lot of control characters which the PIC doesn’t want, (nor does it know what to do with them).

EditPad light is FREE, and also adds nothing to give the PIC indigestion. However any small Text Editor designed specifically for writing programs should be fine.

 

MicroChip’s MPLAB

This is a big big program…. Why chose it ? Well ….

  1. It is the recommended PIC maker’s program.
  2. It has lot’s of bolt-on goodies for when we are more advanced or well-heeled.
  3. It can interface, input and output, with other programs,
  4. It accepts C as well as assembler or a mix of both
  5. It is not too hard to use though telling it what you want to do has to be exact.
  6. It can handle the basic 16C84 as well as it’s bigger brothers
  7. It is FREE.

 

The program to get our program into the PIC

The MPLAB after checking that the code written can run error free finally produces a compiled file with the extension xxxx.HEX.

This .hex file is what the real world PIC needs to get up and running.

But to get the HEX file into the PIC we need a program that can check the PIC , we need a program that can read the contents of the PIC and write the code INTO it, burn it.

I personally like a nice little program that does this called ICPROG. The name I think says it all. It is a program to program your IC, your integrated circuit, your PIC!!!

It also caters for many different PICs.

ICPROG is easy to use and is , yes you guessed, it is FREE.

 

 

 

 

 

Starter Kit

So where can we find all these programs? On the internet of course! If you search with the names above you will find several sites, some of which will be the nearest to your location.

If you don’t find any of them, then try the list at the end of the chapter which is hopefully not out of date. These sites will let you download the needed programs. Try it at night, because some programs are VERY BIG. I’m referring specifically to MPLAB.

We still have one very important item to add to our shopping list…..the data sheet for the PIC.

Which one?

Well the 16F84A is a bit bigger memory wise than the original 16C84 and is still not classed as "obsolete. It is limited as far as built in goodies are concerned.

E.g. you don’t get on-board voltage references, nor UARTS nor ADCs, it is a little slower, but this is good for us learners because it is simpler to learn with. The bigger chips tend to have so many trees that it gets hard to see the forest.

To sum up , we need :-

Item

Source

What it does

16F84A data sheet

Microchip Site and others

Explains about the PIC

Text Editor

EditPad Site

For writing no-frills Text

MPLAB

Microchip Site and others

Test drive your code

PIC tutor

Mikroelektronika

Tells you How the PIC works

ICPROG

Icprog site

Stuffs the PIC

LCD data sheet 2x16

Hitachi 44780 controller

displays speed, time dist.

Up to here the total cost is your telephone Net connection Bill

 

Once we have these items we can start to get to grips with the bicycle itself. So let’s see what the computer needs to get up and running. We will talk about the program later.

 

Defining the Computer

Here I can use a bit of hind-sight and point out things that are to be avoided. All bike computers have at least one input from a sensor, most will have this sensor plus a couple of buttons for changing menus. But the essential part is the sensor which sends a pulse to the PIC.

Sensors

The sensor could be mechanical and every time the bike wheel turns it closes a switch, or it could be optical and every time the wheel goes round a photocell detects ( or loses) a light beam.

The mechanical contact on a mud covered mountain bike would be pretty unreliable, not only because of mud blocking the contacts but the bumps and leaps would give false readings.

The optical systems are very reliable in general, but not in the mountain bike situation. A piece of mud covering the detectors eye would happen so frequently that it would make the detecting system useless.

What’s left? Many systems. Just to give an idea of what is possible at the exotic end, you can carry a GPS terminal. Gives you all the travel data you want including the names of the place and country you are in, but a bit pricey. Besides we want to make it ourselves and write the program all at a very low cost. So is there a low cost reliable sensor?

Well the magnet on the wheel type is almost universal. It is cheap, very reliable and vibration proof for 20 years or so. ( Theoretically, the bike’s vibration, the flexing of the spokes, all will cause it eventually to demagnetise itself).

Another thing is that I don’t know anyone who has a 5yr old bike computer as we all tend to buy something more up market or simply get bored with our present one and buy another.

Getting back to the wheel magnet. It is fixed to a spoke, and usually on one side of the fork there is a detector. The magnet is aligned to pass this detector at a distance of not more than 1 to 3 mm every time the wheel rotates. (Less might be too close as the spoke flexes when the mountain bike lands, and magnet and detector could become entwined in each other with bad karma for the bike rider.

The magnetic detector can have many forms. It can be a many turn encapsulated coil, it can be a HALL EFFECT device proper, or it can be an MR ( magnetoresistive) device, or a Weigand sensor.

But let’s stick with the crowd and use a Hall effect sensor. It has a few drawbacks, but we can always change it later if we want to experiment.

So we want a detector which changes it’s output( goes high) every time the magnetic field gets close, and reverts to its low state when the magnet goes away. This is usually called a UNIPOLAR Hall effect device.

We want one with all the trimmings, (we don’t want to get involved in additional hardware design). That is , we want a sensor output with the correct level and good signal conditioning which gives clean, bounce free, and cmos level, HIGH and LOW states. There are quite a few to choose from. Melexis, Micronas, Allegro, Siemens… etc etc. So now for our first drawing of the computer below, + fig.2

 

 

fig. 2

 

Well fig.2 needs to be padded out a bit with things like what pin goes where, the connections between pins, and the power supply. To make things easier for those of us who have never seen a PIC before, lets just look at a bit of the complete theoretical drawing to comment the components and functional blocks involved.

Note if 2 wires cross with no dot, they don’t touch, if they have a dot where they cross , then they do touch, i.e., they make contact with each other.

 

fig.3

On the LEFT we have an integrated circuit ( between the two capacitors) which needs a minimum i/p of +7V to guarantee a stabilized output voltage of +5V, On the bike of course this would be a battery.

The next important point is the wire with the legend "Wheel pulse i/p. On the bike, this is where the sensor sends its output pulses to. Here testing, we have no bike, instead we generate pulses with another circuit ( a555). We will talk about the 555 later, it is nothing special, but clutters our initial view of the Bike computer.

The original project started with a PIC 16F84, but began to run out of memory. Fortunately it has a big brother, the 16F84A , with the same pin connections and accepts nearly the same code.

Just to the right of the PIC is the 4MHz xtal oscillator, composed of a 4MHz xtal and two 22pF capacitors. At such a low frequency the crystal is not very fussy, providing it is sited near the chip and we have short connections to the earth plane of the PCB.

Just beside the Xtal block, there is a 100k potentiometer. It adjusts the contrast of the LCD display. This pot is also non-critical, once adjusted, you will probably forget about it. So why have a pot there?

The problem is the display contrast. If your display gets fried and needs to be changed, then it is almost a certainty that you will have to readjust the pot to get the display contrast back to the "optimum viewing position".

In fact my original display would only become visible with a NEGATIVE voltage applied. Still lets hope there aren’t many of those left on the components suppliers shelves.

The last block is the display itself. There is an LCD standard, a 2 line by 16 character unit, which is show on top of the introduction on page 1. The display is the Hitachi type,

( there are many clones), but the important thing is that it has a 44780 controller on board. This is essential as all that follows presupposes that we are dealing with a 44780 controller to get our information to the display.

The PIC’s 18 pins

Lets look at the previous diagram again, focusing on the various pins of the PIC.

fig3b

Vss goes to ground and Vdd as well as the reset MCLR to the positive +5V rail. The osc1 and Osc2 pins were mentioned previously from the point of view of their physical position. The oscillator itself needs two external capacitors to function correctly. We have chosen a capacitor value of 22pF , which should be valid for most xtals. ( Here valid means that the xtal will see a suitable load and will oscillate correctly). The RA pins and the RB pins can be used as either input or outputs. The trick is to make the unused port pins OUTPUTS. Why not inputs? Well this is cmos and you would be wise to tie them to a reference, probably best, to ground. But then if you want to use the unused inputs later , this would mean track cutting. However an unused output can be left free. A reprogram can change it into an input, with no knife work involved. We mentioned above that there are RA pins, five of them, for PORTA. Only 2 RA pins are used to connect to the RS and E pins on the LCD , the other three are programmed as outputs and are not used. The two RA pins used (PORTA), essentially handshake the data transfer and indicate we are doing this in the half-byte or nibble mode of operation of the LCD.

The actual data is sent from PORTB to the LCD. It has to enter the LCD on pins D7-D4 for the half byte mode of operation. The remaining LCD data input lines are not used and to be safe, they are tied to earth as we talked about before. So D0-D3 are connected to ground directly. The data transfer from the PIC has a restriction, the high nibble always has to be sent first to the LCD, then the low nibble.

Is that about it? Well almost. The PORTB has 8 pins and any of them could be programmed as outputs or inputs. But there is another consideration. Later we will need to use some of these PORTB pins as inputs. Now only pins B4-B7 will give an interrupt signal asking for service. This means that the data out to the LCD can only be on pins B0-B3.

As an example, the wheel pulse INPUT SIGNAL ( having chosen PORTB), has got to go to one of the B4-B7 group as an input. It is seen to go to pin B4. Later we will use the other pins for buttons and LEDS during debugging .

This is an initial hardware justification, not complete but enough for the moment to enable us to get to the next stage which is mounting the PIC on a board to be able to program it.

Where to find the Starter Kit

  1. The MPLAB, the 16F84A datasheet , direct from the microchip site. http://www.microchip.com/
  2. The text editor Edit pad from
  3. http://www.editpadlite.com/ (The tutor from http://www.mikroelektronika.com/)

  4. The programmer program Icprog from
  5. http://www.ic-prog.com/

  6. The LCD data sheet from

http://semiconductor.hitachi.com/products/pdf/99rtd006d2.pdf

 

 

Chapter 2

 

The PCB

The last component is of course the printed circuit board..

There are various ways to build the circuit which can be divided roughly into two classes, solder and non-solder The " no soldering " techniques are attractive initially but are really misleading for us starters as it can lead to intermittent contacts. Of course if we are a bit masochistic then we may spend a pleasant evening wondering which wire has fallen out or worse, which one is in it’s hole but not making contact, or worst of all which wire is in a hole where it shouldn’t be. Our main goal is making a working bike computer, not messing about with the connections.

Let’s take the PCB route where everything has the connection planned and secure. Then we forget about that physical side of things and get on with the project.

The PCB Shopping List

To start making the PCB we need a few programs to get the project literally onto paper.

 

The Theoretical Circuit

There are many very good schematic capture circuits, which number your components, adjust your drawing, anticipate the next stage which is the pcb layout…but they are also rather expensive.

We need something simpler which gives us the basic features, a program that allows us to draw the electrical circuit and number the components.

I used TinyCad. It is simple to learn but produces an excellent circuit diagram

The components are numbered and a list of materials generated, a parts list. As before, the program can be found on the internet and is FREE.

Below as an example our complete bike circuit and a list of the circuit components, generated by TinyCad.

Component List

====+ Parts List for Bk3.dsn +====

C1,C7 2 100n

C2,C3,C8 3 1uF

C4,C5 2 22p

C6 1 3uF

D2 1 IN4148

D1 1 LED

R1 1 100k

R3,R4 2 1k

R5 1 2k7

R2 1 300k

R6 1 390

S1,S2,S3 3

U1 1 VOLTREG

X1 1 XTAL 4 MHz

The Electrical circuit Diagram

  fig 5 the theoretical circuit

The PCB track Layout process

We now need to make a physical circuit from the theoretical circuit of the Bike computer

Let’s examine and talk about the layout below, and the step to make the PCB physically.

 

Fig.4 the pcb

The twin towers and the IC between them is the stabilized power supply. The long thin yellow IC outline is the PIC itself. Above the middle of the PIC, a rounded yellow rectangle is the 4Mhz xtal flanked by it’s capacitors. To the left of the PIC, slightly down, a yellow square, the contrast potentiometer-. Finally occupying much of the bottom of the board, a large yellow rectangle with foursquare red fixing holes. The right most part which we will leave for later is the pulse generator, a 555.

For those of us who haven’t seen a PCB , printed circuit board, it is a sheet of plastic covered with copper on one or on both sides. We are looking at the side with copper. It is coloured green. The other side has no copper. Each red dot represents a drill hole. Once all the little dots have been drilled. We can insert the components like the PIC into the top side, the side which is NOT green. Look at the PIC yellow outline. It has a V shape on the left edge., a big notch. This is to tell us where pin one of the integrated circuit is.

Pin1 is the first dot above the V ,the first dot in the top row of PIC pins. We count the pins CLOCKWISE from one, going right to nine, then we jump across to the other line of pins, still going clockwise and go left along the lower line of pins till we come to 18 at the top of the V once more, but now on it’s bottom side. It is very important to understand this convention, so as to stick the components correctly into the waiting holes for soldering. Note if you look at the pins from the TOP side, they will now be numbered in an anti-clockwise direction, Think about this slowly and carefully.

The PCB TRACKS have been made as thick as possible. There are two reasons.

Thick tracks and wide earth zones mean good RF performance and heavy currents can be handled. Also soldering can be more ham-fisted before the tracks melt away.

 

PCB layout program

The above PCB layout has been generated by a PCB program. This class of program can be very very expensive . Why? Well, it must be capable of producing a physical layout for the components, that reproduces all the dimensions to a fraction of a millimetre.

If this were not so, then automatic machinery which insert, or place components on the printed circuit board would probably place them with an offset. Then the next step, the flow solder bath, would solder the wrongly placed components with disastrous results. There would be many shorts between tracks and components.

We are not ( this time round) using SMD components. So our needs are not so stringent. But even so we need to be able to create the pads on the boards with sufficient accuracy to be able to insert the components without problems.

So? Well this time we are lucky as some PCB manufacturers give you a FREE professional program to design your PCB. They then manufacture it for you. There are standard prototype board sizes e.g. , 3.5 x 2.5 inch or 6 x 4 inch… many sizes. But for our project, this is not important,, we will use one of the smaller size boards.

This company which offers you the PCB generating program is called ExpressPCB. The program itself is called ExpressPCB The present version is V2.4 , but earlier ones will cover our needs perfectly . Most important, ExpressPCB. Exe is FREE.

 

Well using the program itself is very simple. But at this point we have to sit and study the controls. Once we have mastered the program we need to do the following.

We go to the component library and choose the component outlines of the components in the parts list generated with the TinyCad program. I used discrete resistors and capacitors . We can’t expect to find a PIC in the library, but yes, there is an outline for an 18 pin DIP . This defines an IC with two rows of pin holes. The pins spaced 0.1" apart and the rows spaced 0.3" apart. I placed this about the middle of the board as the starting point. Of course as the other components are placed , we might find we are having to squeeze things together in one place, while in another the board is empty.

On an up market PCB program, you simply move the offending components, and the connecting tracks reroute themselves. In other words the tracks you have drawn to connect the components are not broken. Also these better class programs will advise you if your layout is wrong. What does wrong mean?

Many things, but at the simplest level say the theoretical diagram shows the junction of R3 and C1 connected to pin 3 of the PIC, but we have counted down the line of pins wrongly and connected to Pin5. . The sophisticated program will tell you it is wrong.

Of course at an even more sophisticated level, the PCB program will place all the components inside the board size you specify, generate all the interconnecting tracks and use as many layers as needed if it is possible.

But those programs are very expensive. We get no warning that R2 should be connected to PIN 7 instead of pin17. But we can make our own checks. We can take a copy of the theoretical circuit and starting, for example with the PIC, we CAN create the tracks which connect to the LCD. Below we have a cut out a chunk of the full PCB and have written the pin names on the connecting tracks for the DATA between the PIC and the LCD. You should look at this carefully and check it is correct against the theoretical circuit diagram. Check that each track joins the correct pin number of the 16F84A to the corresponding LCD pin number. Once all pins have been checked, then we are ready to go to the next stage

In the process of making the PCB . fig4b track connection detail

For Each track that you draw on the PCB…. Mark it’s beginning and end on the theoretical electrical drawing with a fluorescent marker pen.

When you have finished creating all the tracks on the PCB, there MUST NOT be any unmarked lines on the schematic drawing. They must coincide, all lines must have the corresponding PCB track, otherwise there are errors.

 

I Boob… No, two boobs

Before leaving the pcb layout ( made with the Expresspcb program). Go back to fig4 the complete PCB layout drawing. There are two things wrong. Can you spot them?

Well the first thing would be fatal unless we know how to handle it. We have drawn the connections with the PIC pins numbered in an anticlockwise direction. We said earlier that this is the copper side of the board, and here you count the pins in a clockwise direction. Well maybe this is all a bit much to reason quickly, you need good special vision. But no panic. We carry on to the next stage where we will be transferring this image onto a clear acetate sheet. The program we will use, can FLIP the image so that we have the mirror image of fig4. This means that the bottom side pins are once again correctly positioned and go clockwise. Don’t believe me? Look at fig.4 on your monitor. Then look at it’s reflection in a mirror. I hope that convinces.

Why bother if it easy to solve? Well it would be so easy as well to overlook this little quirk of the Expresspcb program. Maybe there is a submenu command somewhere to flip the circuit , but I haven’t found it.

The second thing is a typical chicken and egg situation. For one of a myriad of reasons modifications to the original design meant that the pcb was cut and chopped and hacked…( Note. this is possible because our PCB circuit has very wide tracks and they can take a lot of punishment)… and pin connections reassigned. So the working circuit now does not agree with the theoretical diagram. Which one is right?

Here I am to blame. It is quick and easy to update the modifications to a circuit diagram, not so quick and easy to generate a new PCB layout. Compare the PCB fig.4 with the electrical diagram fig.3 and locate the differences. They are all associated with the port connections to the PIC and the output from the pulse generator.

The main reason for the changes was that ( as we will see later) that a green LED is a great help in confirming not only that the wheel pulses are getting to the PIC, but that the PIC is processing them and is looping correctly.

Later we will come to a NEW version of the PCB that corresponds to the theoretical electrical drawing, line for line, track for track.

 

The Print process.

We are now in a position to actually make the PCB.

A word on the print process itself. We have to get our PCB track drawing onto a piece of clear acetate sheet. It will look like a large photographic negative, because it will be exactly scaled 1:1.

We go through the following basic steps to achieve this.

  1. Export the drawing from ExpressPCB to a drawing program say Photoshop.
  2. Use Photoshop to FLIP the drawing so that the pins go round clockwise,
  3. Use Photoshop print preview controls to adjust the pcb layout size to 1:1.
  4. Insert into your printer a clear DIN A4, or equivalent , clear THIN, acetate sheet
  5. Print the PCB drawing onto the acetate sheet. Let the printed ink dry for maybe two or three hours. ( paper dries immediately, but the acetate doesn’t)

That is it, we are ready for the next step after a few words on what we have just done.

 

Calibrating the Scale

It is too much to expect that the PCB dimensions after passing between two programs and then onto a printer … It doesn’t have to be laser, I use an HP710C … will come out exact first time. As the acetate sheet is rather expensive in my neck of the woods, I simply print the first trial run onto plain paper. Next I measure the length of the rows of pins where the PIC will go, to see that they are spaced exactly 0.1 " apart. We don’t even need a ruler., because we can place the PIC chip itself on our paper print out.

The first time we try this, probably the pins and marks won’t coincide.. The first two or three pins will, but then we may notice that the pins are gradually separating from their marks the further along the row we go, landing on the spaces between the outline’s pin marks. So we go back to step 3 above and adjust in the direction that is needed. How much adjustment? Well I sometimes have to scale up to 103% to get a printout where the pins coincide with the marks.

When the pins coincide exactly with the chip’s paper outline, then we can do the next print on the acetate sheet.

Other print problems

Any other problem? Yes, the acetate sheet itself! It should be thin, not those thick chunky ones. Can we use a thick sheet? Yes, but if your printer is like mine, the sheet goes into the printer , over a roller and does a U turn , and comes out the front again. Some thick sheets won’t bend.

Thick sheets have another problem. If we have managed to get the PCB tracks correctly onto them, then when we place the sheet over the photo sensitive plate to expose it, the lines will be fuzzy. This does not happen to the same extent with a thin sheet of acetate.

 

More Boobs… ExpressPCB was right !

Do I hear you say but it does happen.! Indeed sir, you are correct. We would have to turn the track drawing over so that is against the photosensitive plate.

You say again, but if we turn the sheet over, the pins will be the wrong way round, anticlockwise.

Yes sir that is correct … a pause as we gradually realise that the anticlockwise output from the ExpressPCB program was exactly what we needed. Our apologies to the wise men in ExpressPCB.

So we need to go back to point two above and remove the word FLIP.

 

Other print process problems?

Nothing serious, except that ExpressPCB does not let you produce an image file suitable for a drawing program to handle. There is no bmp nor jpg, nor tiff nor similar outputs. Just a native format for processing the drawing in their factory, logically.

I get round this by printing to the printer, but not the HP printer a fax driver .

The fax program lets you preview before sending. And HERE you can save the preview as a bmp, tif, dcx image format any will do. The fax route is nice because it gets rid of the colours and turns everything into black and white, which is what we need for the acetate sheet.

So MY complete process to get the tracks on to acetate sheet , yours maybe similar or better, has the following steps:

  1. Export the drawing from ExpressPCB to a fax printer driver
  2. Re-export a bmp image to the drawing program, IrfanView
  3. Use IrfanView to get rid of speckle dots ( PCB grid )
  4. Use IrfanView print controls for setting 1:1 scale (100)
  5. Do trial print on paper.
  6. Place PIC on it’s outline. Compensate if necessary
  7. Print onto acetate sheet. Let dry 3 hours
  8. Turn the acetate sheet over so that the ink is directly against the photosensitive plate.

That is it. Well I sneaked in a program called IrfanView. It has all the bells and whistles we need, and….. yes it is FREE. Find it on the internet, using the program name IrfanView. It is not too big and downloads quickly

 

WARNING WARNING WARNING

The chemicals we are going to use are CAUSTIC and AT ALL TIMES YOU MUST KEEP THEM AWAY FROM THE CHILDREN.

Caustic soda is not poisonous but it’s great affinity for water can cause serious burns in contact with the skin. or being swallowed

If it gets into your eye, IMMEDIATELY wash you eye with abundant water for at least 5 minutes then get medical attention to check for damage. The prompt treatment is essential, to avoid permanent injury.

If in spite of the WARNING above, the kids get hold of it and swallow it, then YOU are really in trouble. You must take immediate action. Do the following.

Explain if they have swallowed crystals or the dilute solution we are going to use

Describe the symptoms and act immediately on instructions.

If it is not possible to get to a doctor or hospital then you must determine if the crystals or the dilute solution has been swallowed.

CRYSTALS: See if there are burn marks round the MOUTH. Administer 15cc/kg body weight of water or milk if possible. Rinse the mouth with abundant cold water, GET MEDICAL HELP AS SOON AS POSSIBLE

DILUTE SOLUTION we use A 0.7gm/liter. Solution. This is not so bad as the crystals when swallowed, but it needs IMMEDIATE treatment.

As before immediately drink water or milk , 15cc/kg body weight , and rinse mouth abundantly with water Even though this is a dilute solution it is caustic and the child should GET MEDICAL HELP AS SOON AS POSSIBLE.

Ferric Chloride

This at first sight is worse as it eats away many metals. But it has an awful taste , a foul smell and it is most unlikely that a child would swallow the stuff. The main danger then is that it is CORROSIVE and it will stain your clothes, your skin a brownish yellow colour. The skin stain will go away after a few days, but the clothing is usually ready for the dustbin.

If it gets in your eyes, or hands wash with abundant water for at least five minutes then get immediate medical help

 

Waste elimination

There are many legislations locally in force for chemical disposal. You should consult before flushing these or any chemical down the toilet.

 

Chapter 3

Photographic Stuff

Having pointed out what can go wrong, lets concentrate on the positive side in the making of a PCB-

The exposure process is simple and largely non-critical.

Note . Buy the smallest possible quantities of the chemicals, as a little last a long time.

 

Photographic shopping list

We need the following:

 

The Photo frame

To keep our acetate sheet pressed hard against the photosensitised copper clad board, in such a fashion to allow the light to shine *through it, we need something where the top layer is glass, hence the photo frame, or photo holder… call it what you will.

Here the dirt cheap type is better than an up-market jobbie with gold beaded edges. We need a bit of clear glass, a firm hard to bend back beneath the glass, and a no frills clamping system to hold the photo in place.

*Note. If later when you are exposing, the plate doesn’t seem to expose or takes a very long long time, then check that the glass is really glass. Sometimes the front is clear plastic. This may or may not be good. Many plastics are excellent UV blockers. They don’t let the UV part of the spectrum pass even though visible light does.

 

 

Returning to describing the photo holder. This is all a bit hard to describe in words so lets look at the images below which help better to see how it all works.

 

 

 

 

 

The back of the paste board frame has four springy metal clips in grooves. The clips curl over to the front and hold the glass firmly.

This particular model is easy to open and remove the glass. The dimensions are far bigger than what we need, but if in the future you decide on a bigger and better circuit, this will hold them all!

Dimensions 18 x 24 cm

Fig . 6 backside of the photo holder

 

Now lets look at the glass-side of the holder.

I put the glass on a bit badly so that you can see it at the edges.

The clips are holding the glass against the base, and sandwiching the track layout. I DIDN’T put the photosensitive copper clad board under the track layout as it was also black and the contrast was very bad.

The white tags are the sticky tapes used to fix the track sheet to the photosensitive board. Pull them tight before sticking to avoid wrinkles.

I cut the board to the track sheet size with kitchen scissors, then tape on the backside of the copper board.

Fig . 7

I hope the description is clear, ah and also…Obviously you can use anything that holds the acetate sheet tight against the copper clad photo sensitised board below it.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The Chemicals

Mixing the Chemicals

When mixing solid chemicals wear glasses if you have never done it before.

The reason is that most chemicals in crystal form that are used in reactions release heat on dissolving. If you pour water onto a crystal of that kind, it could literally heat up and explode in your face. So always add small quantities of the above crystals to water.

We are going to add the chemicals to water. Normally there are no fumes from both, BUT, this depends on the purity of what you have bought, so do not mix in a closed room. Have some form of ventilation, an open window for example.

Prepare 1 litre of tap water for the NaOH and 0.25litre of tap water for the FeCL3.

Note. if you have furred kettles in your area, maybe best buy some natural water from the supermarket.

Caustic Soda solution ( NaOH)…The developer

Pour one litre of water into the plastic tray ( check that it is big enough o hols 1 lt.)

Having weighed before hand the 0.7gm of NaOH, slowly add it to the water , stirring with the plastic rod.

When the solution is clear, use the funnel and pour into the bottle labelled Caustic Soda

Wash both tray and the funnel with abundant water.

 

 

Ferric Chloride solution the etchant

Pour a ¼ litre of water into the plastic tray ( check that it is big enough o hold .)

Open with care the 100gm plastic container of the Ferric Chloride crystals. slowly add the crystals to the water , stirring to aid the dissolving of the crystals with the plastic rod.

When the solution is a clear brownish yellow with no lumps on the bottom of the tray, use the funnel and pour into the bottle labelled Ferric Chloride

Wash both tray and the funnel with abundant water.

 

DON’T HEAT THE WATER

There is no need to heat either product to help dissolve. A normal temperature of 12 to 20 ºC for the tap water is sufficient. The colder water will take a little more time but apart from that the crystals will dissolve completely. Another reason for NOT heating is that the ferric chloride may begin to release fumes. This will not happen at normal temperatures.

 

The Test strip

The single sided copper clad board we have bought has a POSITIVE photo sensitive layer on top of the copper which responds to ultraviolet light. Now we are going to use normal sunlight which contains enough UV to expose the Copper clad board.

How long ? could be impossible to answer, but fortunately the test strip shown below solves this problem. The sun between 10a.m and 3 pm. Is not critical

 

The test strip is simply a piece of clear acetate sheet with numbers drawn on it, say 1 to 10. Use your kitchen scissors, the type that the TV advertises as being able to cut through steel). Cut a strip off the copper clad board about the same size. Mine were 10cm long by 2 cm wide. Dim the lights or draw the curtains. Peel off the protective covering of the copper clad board. Tape at the ends , the numbered acetate sheet onto the SENSITIVE side of the board ( the side you have just peeled)

Get your watch ready and a piece of cardboard big enough to cover the whole test strip .

Is it sunny? Good move the strip into the sunlight but still covered. Move the cardboard covering the test strip taped to the sensitised copper clad board and uncover ONLY the number ten for 30 seconds.

Then slide the cardboard a little more to uncover NINE for 30 seconds, then 8 for 30 seconds . Keep on uncovering each number for 30 seconds till you are at the end that is ONE is uncovered, then remove the test strip from the sunlight. Slightly cover the window to shut out direct sunlight.

 

Look at the test strip and the exposed copper below. You should soon see something like it.

fig.8 test strips

Number 8 has had 30 x 8 seconds exposure about 4 minutes

Number 7 has had 30 x 7 seconds exposure about 3mim 30 sec

Number 3 has had 30 x 3 seconds exposure about 1min 30 sec … not useable

Number 2 has had 30 x 2 seconds exposure about 1min … not useable

Number 1 is completely under exposed and can’t be seen

So 5, 6, 7, 8 look OK. (I used 7). The strip also indicates that the material is not critical, an exposure varied from 2.5 to 4 min makes little difference.

Getting back to the test strip you have just exposed. Peel off the acetate sheet with the numbers and submerge the test strip in the tray with the caustic soda. The correctly exposed numbers will appear within SECONDS in a slightly greyish form ( the top drawing) and the other numbers more slowly . Move the solution in the tray for a minute more or less. Then remove the copper clad board holding by the edges, from the tray and place the copper clad board under a running tap to wash off the traces of caustic soda.

Finally place the copper clad board in the tray with ferric chloride, the etchant. This is slower, it can take up to 30 minutes. But within half a minute the correctly exposed numbers will be visible, a different colour from the salmon coloured copper that is being eaten away by the ferric chloride. .

Keep on stirring once a minute or rock the board in the solution. The parts of the copper NOT covered by the numbers is gradually eaten away leaving the fibre glass board visible.

Why is there copper at each end? I had tape there and the sun didn’t get to the board..

As before wash under running water for at least 5 minutes, watch your eyes and clothes.

Finally put the chemicals back into their labelled bottles. Wash everything and put the bottles out of reach of children.

Well that is the initial preparation for making the PCB. We now know how long to expose the sensitive board for.

 

 

 

Exposing the PCB Tracks

We need to prepare for the big moment, our first PCB. A semi darkened room, sunlight behind the curtains and the photo holder, unfastened . Peel off the protective covering and place the PCB Track acetate against the board, with the printed side in intimate contact with the board.. Tape the edged of the acetate to the board, don’t cover the track area with tape. You must tape the acetate FLAT against the Copper clad board as ripples will cause fuzz and loss of definition.

Place the Taped combination in the photo holder., so that the sun will shine on it. Cover the combination with the glass. Clip the glass firmly to the back of the frame so sandwiching the copper clad board and acetate sheet in the middle. Looks flat?

 

Here we go this is real

Congratulations!!! You now have your first PCB

 

Drilling the board

Now is the time to use those DIY skills hidden inside of us. Most of us already have an electric drill for filling the house with holes- But in my case I had a problem . My drill would not hold well the small drill we need to make the holes in the PCB.

There was also an added difficulty in trying to make such fine holes on a closely defined area and at the same time hold steady a heavy machine and at the same time again, NOT break the very thin drill shank.

Most hobby shops sell a small hand held battery operated machine which is much easier to handle.

Here we can see my hobby machine stowed into its plastic blister with the drills and cable.

fig . 10 the box label

.

I just added the back label, not to sell this brand, but simply to show the size of the drill machine

 

 

Fig. 9 the complete package, machine and a set of drills.

 

 

The drill itself is very small compared to a normal household "wall hole maker". We need a size that will take all most standard resistor, capacitor, integrated circuit, leads and pins, to pass through the board for soldering . I think a 0.8mm drill is about right for the job , but you decide when you come to this stage, maybe you would prefer a 0.5mm. Either way they are small drills.

Now if we look at the tracks on the copper PCB carefully we see that the points we are going to drill have a round mark ( the future holes for inserting a component lead or an IC pin ), also called a pad.

When we hold the drill machine over the pad to drill through it , the drill will probably skid. To avoid the skidding and breaking the drill, get a small hammer and a nail.

Place the nail over the centre of the pad and hit its head lightly with the hammer to produce a DENT, not a HOLE in the centre of the pad.

Dent all the pads to be drilled on the board, not long, a five minute job as it is a small board.

The final problem is clamping the board . I place a piece of wood o slightly bigger than the PCB. I place it at one edge of the table and after placing the PCB on this piece of wood, screw the clamp down (protect the contact area with a doubled and then doubled again sheet of paper) to hold the paper, the PCB and the wood, firm on the table . The piece of wood is to avoid making drill holes on your table so it should be thick enough, say 1cm.

Now we can drill hold the machine and guide the drill into the first pad’s dent. Try and keep the machine vertical. Drill… you don’t need pressure, it slides through the PCB like butter. Very little pressure ( think of your table below). You now , with a bit of practice, have perfectly centred holes in each pad and we are ready for the next and final stage.

 

CHAPTER 4

 

Inserting and Soldering the Components

We probably have all the tools needed already but let’s make a small shopping list just in case.

 

Now how to solder well, is a big topic. The gentleman below has said it all, far better than I could. If you are not sure and don’t want to destroy our laboriously created PCB, or fry a transistor, then you should consult a web site like this one…

Basic Soldering & Desoldering Guide

by Alan Winstanley

http://www.epemag.wimborne.co.uk/solderfaq.htm

Fine, now we know all the precautions and things to do to make a good solder joint. One very practical detail is inserting the smaller components first. The reason is we insert from the top then we turn over the board to solder.

Now the components tend to slide out when not soldered. So you hold them in place with a fireproof finger. If the big components have already been soldered and the little one lies between them, then you can get your finger to hold the small component. What should be a two second job can become very difficult .

Don’t cut off the lead wires before soldering as bent slightly outwards they help to hold the component in place till we solder the leads. After cut them of as close as possible to the joins. This can avoid some nasty cuts if you accidentally slide your fingers across the underside of the board. Some of the cut leads are razor sharp, hence cut at low as possible. I once used to resolder after cutting to cover the lead edges but that is not a good idea as it reheats components.

Just a final word about the integrated circuits, especially the PIC. It must be mounted in a socket for an 18pin DIP as it will be removed to program and then reinserted many times before we are satisfied with the bike computer. Any special type of socket? No not really. I use a normal IC socket and it lasts a long time, indefinitely if you insert slowly pushing in alternately each end of the PIC.

For Taking the PIC out of the socket, I gently slide a small screwdriver blade between the PIC and its socket and lever up slightly , then I go to the other end and lever up slightly.

After a little with practice you can do this with no damage or strain to either the PIC or the IC socket..

Colour code

Resistor Colour Code

Colours used

band 1 and 2

Colour used

as a number

Colour as a decimal

multiplier

BLACK

0

X1

BROWN

1

X10

RED

2

X100

ORANGE

3

X1,000 or 1K

YELLOW

4

X10,000 or 10K

GREEN

5

X100,000 or 100K

BLUE

6

X1,000,000 or 1M

VIOLET

7

Silver / 100

GRAY

8

Gold /10

WHITE

9

Tolerances

Gold= 5%

Silver=10%

None=20

Going back a little to before we insert the components in the PCB. Do we need to learn the way components are marked, or maybe we already know. Here is a table with the basic information.

 

 

 

 

Believe it or not we are almost ready to talk about the programming of the PIC

 

The PIC programmer

There are really so many programmers available for the PIC, that we couldn’t possibly discuss the pros and the cons of them here. I would suggest we use a really simple cheap one, just in case we later need something better. But here cheap means reliable and one that does the job.

Any other condition? Yes, it has to be compatible with one of the types of board recognised by the ICPROG program we listed in chapter one as a FREE program.

Below we have a Picture of my own ( built from a kit) programmer. This is a com port model of the type called JDM ( I think JDM invented it). It uses the RS232 interface and has NO power supply. I t powers off the COM port output directly. As you can see from the photo, most of the components are diodes that either rectify the incoming signal or level shift signals.

The 9 pin D connector shows how small the whole thing is. The 18pin dip is empty but that is where we plug in the PIC for programming.

Just one word of warning. The socket has a V end and is mounted so that the V corresponds with the silk-screened white V. We MUST insert our PIC so that it’s V or mark also corresponds and is at this end. If we put it in the other way round, it is probably ( not guaranteed) the end of the PIC. RIP…. = $$$$$

 

 

 

 

 

 

 

 

 

Final shopping List

Here we have come to the end of the steps to be able to program a PIC , not all PICs but quite a lot of them. Just to sum up we will reproduce the principal items from the various lists so that we can do a final check to see if there is anything we may have skipped.

 

Item

Source

What it does

16F84A data sheet

Microchip Site and others

Explains about the PIC

Text Editor

EditPad Site

For writing no-frills Text

MPLAB

Microchip Site and others

Test drive your code

PIC tutor

Mikroelektronika

Tells you How the PIC works

ICPROG

Icprog site

Stuffs the PIC

LCD data sheet 2x16

Hitachi 44780 controller

displays speed, time dist.

Up to here the total cost is your telephone Net connection Bill

 

Component List

====+ Parts List for Bk3.dsn +====

C1,C7 2 100n

C2,C3,C8 3 1uF

C4,C5 2 22p

C6 1 3uF

D2 1 IN4148

D1 1 LED

R1 1 100k

R3,R4 2 1k

R5 1 2k7

R2 1 300k

R6 1 390

S1,S2,S3 3

U1 1 VOLTREG

X1 1 XTAL 4 MHz

 

 

Photographic list

 

Inserting and Soldering the Components

DeSolder wick

And the last item was a

I must have forgotten something…….. ah yes a

This is the end of the Hardware chapters the next section will deal with the programming of the PIC

 

 

SECTION 2 Writing Code for the PIC

 

CHAPTER 5

 

Introduction

I wanted to build a bike computer as an exercise to learn how to program in Assembly language as I explained in Chapter 1.

As always I start out by making a flow chart which is empty. Of course if I had known what to put into it then, well I wouldn’t have needed to learn how to write the PIC code.

Let’s say at this stage the flow charts are either very empty or meaningless. Best leave them till the end of the project. They look nice.

So a good starting point is do a little theoretical exercise where we speak about what features a bike computer should have, do the maths of each feature and try and define further at each step, the bike computer itself. Really we are identifying functional blocks which then, if feasible, can be turned into PIC code.

*Part of Fred’s original notes………………..

* What follows is very large, in that the bike modules identified are many, maths, speed , distance, time HP, calories, Angle, friction, wind speed….. these are all possible, and the PIC has enough input ports to handle the sensors. There is one basic problem.

The resulting PROGRAM IS TOO BIG FOR THE PIC 16F84A. So the original notes stop at the point where we have identified the basic features of the bike computer.

Within this limiting of the features, YES, the PIC can handle the resultant size of the program.. ( I haven’t got a crystal ball, I ran into the problem and there is no getting round the code-too-big for the chip memory limitation).

I have no doubt that optimising the code ( it becomes very illegible when optimised ) we could squeeze in the wind function. But when we arrive at the situation that we are at a memory limit and that we are running out of variable space, it would be better to move upwards to a bigger PIC, compatible as far as possible with the code we will write.

 

The First attempt to define the bike computer

Sorry if the way it is written rambles… but at this point there was just an idea and questions about how to give it form…. So please bear with me and don’t laugh as the original mistakes have been kept in. For example, the wheel distance for one revolution s taken as 4m when it should be 2m. Anyone spot the mistake?

Start of my original notes

…. the operations , data and the constants needed for the complete bike program.

THE INITIAL STARTING CALCULATIONS AND DATA INPUTS

Wheel circumference= Radius*2pi (for a 26" wheel circ=26*2*PI*2.54/100 = 4.14m)

constant for diam. to distance is 4.14/26 =0.156. So this is a START calculation and is stored

in DATA memory as a the wheel circumference.

DATA memory will also need to have in kg

The rider weight =wrid and the bicycle weight = wbike. So total weight wrid+wbike = wtot

wtot for example calculations =85kg +15kg =100kg

Wind resistance can be calculated as a function of bike speed, more later.

Road friction can also be calculated when the bike type ( road or mountain) is entered and the

appropriate equation selected..

But maybe there is a better way, the "flat road time to come to rest measurement"

 

THE WHEEL

Wheel circumference is an initial constant which by now has been entered for a given bicycle.

In the EXAMPLE a 26 inch wheel has a circumference of 4.14 m. So as explained above circ=4.14

and is needed,, to calculate ALL OF the following a)... e) .

a) Trip total dist. sum of wheel pulses

b) Average speed dist / time

c) instantaneous speed dist / 1 sec

d) peak speed. highest recorded value of c)

If we sum a) to the previous total of distances from previous trips,, this gives the

e) Total kms the bike has covered since the computer was installed.

DISTANCE

Each circumference travelled is one wheel revolution. So the magnetic sensor

will generate a pulse per revolution. In this case 1 pulse every 4.14m. and thus the wheel constant

is 4.14m =circ

So to calculate a) we need to store the total of wheel pulses and multiply by 4.14. Store in

the Wheel Pulse Register

The result in meters is usefully displayed as km to two decimals. This means that we can view the

trip distance to within 10m. A 5 digit display gives a maximum trip distance 999.99 km,, so we will need

a five digit LCD display.

TIME & STANDARDS

To calculate b) we need to know the time that has elapsed. The STANDARD that generates

the time,, our local CLOCK has to have sufficient accuracy for this task How accurate?

We have three available standards for the PIC. Xtal,, ceramic resonator,, and RC.

Consider the RC. Well a one second a hour error at 15km/hr means a distance error of 4.14m

or in 100km 414m error, about half a km....an error of 0.5%.

This is probably a practical measurement limit,, tyre pressure,, skids,, bumps,, wind, slope.... will all

tend to produce worse errors. If we want real DISTANCE ACCURACY we can use GPS measurements

So at first sight any standard will do,, we could use the RC network.

The 4MHz xtals are very stable and theoretically will allow in the same circumstances at 15km/hr an error in

dist /time measurement to be only a cm and time a fraction of a second.

But the other uncertainties mean that in practice you can't use the accuracy. If we want the time STANDARD as a WATCH. days, hours minutes seconds... we may have to come back to this.. .

Lets look at the third option.

A ceramic resonator is small and offers a 1in 10000 precision and also a low frequency, say 32000Hz

We divide by four to get the machine cycle. We get two bonus points

The error is OK for a TRIP display,, 1 second error in 3 hours.

This is also very good for reducing the power consumption of the PIC and peripherals.

However it may be too slow as it limits the PIC to 8000 machine cycles /per sec!!!

We will use for the timing example 8000Hz = 0.125msec per cycle.

PIC System clock is 0.125 millisecond

On starting the computer we need a time elapsed counter for total trip time.

 

 

 

What could a maximum trip time be? Let's say 24 hours.

24 hours in seconds is = 86400 seconds

24 hours in machine cycles is =691,, 200,,000 Can the PIC manage this quantity?

Note find timer example on the internet.

Of course we limit the count to one hour =28,,800,,000 and increment a register in steps of 1. This

would be the hour register.

We can now calculate b) Average speed from Wheel pulse Register / hour register

To calculate c). Instantaneous speed we need to measure the time between consecutive

pulses from the wheel,, by reading the number of clock pulses before the 2nd pulse is detected.

An example could be that the second wheel pulse arrives 6000 clock cycles after the first.

So we can calculate the instantaneous speed as :-

8000/6000*4.14*3.6 = 19.872 km/hr at that moment.

Store the value in the instantaneous speed register

We have to do Two things with the Instantaneous speed . Let's look first at the easiest....

The instantaneous speed value is displayed and also internally this value is compared with the

previous value stored in the max speed register. This will give us d) peak speed

The condition is "If greater than stored value,, replace with actual value."

The second thing is a know problem because the speed display is constantly dancing

and visually this is annoying. So we need another routine to sum the last five seconds and

show the average instantaneous speed. This means we need to reserve a chain of

FIVE instantaneous speed registers. This routine will have to sum reg1,, 2,, 3,, 4,, 5 and

divide by five. The result is then displayed as instantaneous speed. It will also mean a shift

routine to keep the data moving, always losing the oldest reading.

There remains d) total km since installed. FROMDAY1 register should probably be

increased by 1 for every measured km covered during the trip which is in progress.

(I say probably because maybe

there is an easier way of showing bike's total km????)

 

wake up

On wake up you have last trip data still available.

If you wish to retain previous trip data .....do nothing with button B.

Note. You may want this to sum total km in a day after stopping to eat.

If you wish to start afresh.....

Reset to zero, distance, time, average speed, maximum speed, Calories burned… by holding down button B for five seconds.

Display 1 will show Speed and Trip distance to nearest 10m.

Pulse A

Display 2 will show Average speed and Trip time. to a maximum of 24 hours

Pulse A

Display 3 will show Top Speed and sum of all trips distances to a maximum of 99,999 km

Pulse A

Display 4 will show present HP and kCal/km at present rate.

Pulse A

Display 5 will show Peak HP and integrated trip kCal burned.

Pulse A

Display 1 will show Speed and Trip distance to nearest 10m.

 

End of my original notes

We now move on using the above description to try and create the needed modules.

 

The First Steps after pseudo code

The above shows how idea has been captured my style, and translated into Maths equations.

We are going to change the rough outline and the equations into code blocks, but first we need to answer some basic questions as to what instructions exist and also to get our tools working.

So let’s sort out the initial problems and get started with the code.

Our program to run the PIC code and then send it to the 16F84A is MPLAB, but if we have never seen it before we may have problems in setting up the initial options. MPLAB presuppose that you have done some programming, but this is not necessarily true. I hadn’t, and I floundered for a bit till I discovered that MPLAB need to basic inputs to work.

I didn’t see this at first. If you haven’t created a project, them the assembler code can’t be run. And of course the other way round. If you have created a project but have no code written , then there is also nothing to run. In both cases MPLAB waits…

So out project is called Bike3.pjt (MPLAB adds the extension). But so that we can see the essential screens lets briefly open a NEW project. A reasonable name would be Firsttest.prj ( MPLAB will toss the name out as it has more than eight letters, but Firstest is OK as it is inside the maximum. Try both.. Ah before I forget, we will put this firstest.prj in my PICproj directory, which starts empty so that we can see the files that MPLAB is generating for us. So run MPLAB and go to the second menu Project, select New and we have an invitation to name the project.

Fig.20

We enter the wrong name firsttest and get the message, "too long"

We enter again but with one "t" less. MPLAB accepts and opens the next window below fig.200 We can see that firstest.hex has been written in two `places by MPLAB. Fine, we will come to that a little later. The essential thing that MPLAB need to know is what kind of Chip are we going to use and what features will we employ. . These details have already been chosen by me as we see IN WINDOWS MPLAB SIM PIC16f84A and also LANGUAGE TOOL SUITE has been chosen as MICROCHIP fig. 200

How did I do it? Well if we look a little further down fig.200 we see a button labelled Change..

Pressing it takes us to the next menu in fig.201.

 

Fig.201 asks for details such as the ones we have just mentioned and more. We click the tags

We enter XT and 4.000000, not forgetting to tick MHz as well.

Configuration tag next. Enter watch dog timer none and postscale 1. Processor mode, microcontroller-

Break tag. Clear, global, freeze. Finish with APPLY . Now here MPLAB warns something about a hex file which at this moment doesn’t seem to make sense. If you know what is going on fine, but if you don’t it is a bit mysterious and you may feel you hit the wrong key to leave the menu fig. 201 No you did it OK. MPLAB is worried because it has no assembler file, ( it is looking for a file called firstest.asm, which we haven’t yet entered) and from that reason it tells you that it can’t go on..

 

 

 

Fig.201

So we return to fig.200 to clear up this problem that MPLAB has. How?

Well please remember all this is dummy, so that we can play a little with the menus.

We can create another dummy firstest. asm

And see what happens.

To do this we go to the top menu again

and open FILE, New.

Write anything in it, I wrote "First time."

Then save in the PICproj directory as firstest.asm. We then go back to the project menu and see what MPLAB thinks about the Firstest.asm file we are going to offer it. Here goes. We change to the project menu and at the top we see that firstest .prj is still open. Good. ( But if it wasn’t? Then use Open Project from the dropdown menu or simply click it from the list at the bottom.)

So we have our project open but as yet no Firstest.asm to feed to MPLAB. The only button not "Greyed Out" and which we haven’t touched is Add Node. This is MPLAB_speak for "find me an assembler file to play with".

So we press Add Node and enter from the PICproj directory firstest.asm.

( If MPLAB offers you a different directory in the previous step, change with the browse button. Somewhere I read that the project and it’s xxxx.asm files have got to be together)

Yes , fine MPLAB accepts our dummy firstest.asm file. And adds it to the project window.

Note I’m playing about with capital and small letters for the file names. Be careful. In some places MPLAB doesn’t care a hoot, in others it gets really shirty.

So we seem to have deceived MPLAB giving it a dud asm file. Well not really, but up to here it has enabled us to test the main buttons and set up MPLAB.

We have achieved our aim and have a file which MPLAB can do something with. It can run the code we have written in the dummy file firstest.asm ( remember we wrote " First Time") . Well to get MPLAB to attempt to do something with it , in the project menu, we try another button called "BUILD ALL"

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Yes indeed something happens , MPLAB spits out the following

Building FIRSTEST.HEX...

Compiling FIRSTEST.ASM:

Command line: "C:\ARCHIV~1\MPLAB\MPASMWIN.EXE /e+ /l+ /x- /c+ /p16F84A /q C:\PICPROJ\FIRSTEST.ASM"

Error[122] C:\PICPROJ\FIRSTEST.ASM 1 : Illegal opcode (time.)

Error[125] C:\PICPROJ\FIRSTEST.ASM 2 : Illegal condition (EOF encountered before END or conditional end directive)

MPLAB is unable to find output file "FIRSTEST.HEX".

Build failed.

The last line says it all, "build failed." But it doesn’t matter. We have set up MPLAB for a PIC 126F84A, running at 4MHz and it is attempting to compile.

From here on, we can forget about setting up MPLAB and concentrate on writing code. There are lots of other things it will do but we are over the major hurdle in getting the MPLAB program started.

If all this is boring you stiff, skip the next bit, but as this is written for beginners like myself who get stuck on the most obvious things initially, we will try and explain all that is needed to make MPLAB happy with our dummy asm file.

Making Firstest Work

Well MPLAB replied to our first compile attempt with "build all" ….and blew us a raspberry.

But it also gives clues to where it is wrong, or things missing.

The last line seems worried about the end do we need to add and end? Yes. Well let’s add the word end.

How? Well there is a window open showing our Firstest.asm file. If you haven’t got that window open. , go to the file menu and open it.

Then simply write the word end at the end to see if MPLAB feels a little happier. Compile with Build all in the project menu once more. We now get.

Building FIRSTEST.HEX...

Compiling FIRSTEST.ASM:

Command line: "C:\ARCHIV~1\MPLAB\MPASMWIN.EXE /e+ /l+ /x- /c+ /p16F84A /q C:\PICPROJ\FIRSTEST.ASM"

Error[122] C:\PICPROJ\FIRSTEST.ASM 1 : Illegal opcode (time.)

Warning[205] C:\PICPROJ\FIRSTEST.ASM 2 : Found directive in column 1. (end)

MPLAB is unable to find output file "FIRSTEST.HEX".

Build failed.

Still grumbles about end but something changed, it doesn’t like it in column one. So move it to column two ( shift key or simply spaces).

Compile again with build it….

Building FIRSTEST.HEX...

Compiling FIRSTEST.ASM:

Command line: "C:\ARCHIV~1\MPLAB\MPASMWIN.EXE /e+ /l+ /x- /c+ /p16F84A /q C:\PICPROJ\FIRSTEST.ASM"

Error[122] C:\PICPROJ\FIRSTEST.ASM 1 : Illegal opcode (time.)

MPLAB is unable to find output file "FIRSTEST.HEX".

Build failed.

Eureka!!!, the error message about the end has gone. Next thing is our text which is not an instruction… maybe we could recycle it as a comment. to the right of ; comments are ignored. (A comment begins with a semicolon).

Try it, compile again…..

Building FIRSTEST.HEX...

Compiling FIRSTEST.ASM:

Command line: "C:\ARCHIV~1\MPLAB\MPASMWIN.EXE /e+ /l+ /x- /c+ /p16F84A /q C:\PICPROJ\FIRSTEST.ASM"

Build completed successfully.

We are there. MPLAB gave us the green light. Also the message at the end

MPLAB is unable to find output file "FIRSTEST.HEX".

about "can’t find the hex file" has gone. Why? Well it must be MPLAB’s diplomatic way of saying, "I’m not going to produce a HEX file with that load of rubbish code", when it finds syntax errors.

Just before we forget , save the project for next time using "save project" then "close project" ( project menu). We can now examine a little further, we were saying….

On the other hand we have compiled an absolutely useless piece of code. How is this possible? We agree it is useless, but MPLAB accepts it because it doesn’t break any rules. …. There are no syntax errors.

You mean that you can compile something that is wrong? Well normally not something so absurd as out little asm file, but how do we define the word wrong?

Someone told me a long time ago….

A computer does what you tell it to do,

Not what you thought you told it to do

It is still true today. Providing what you write meets the rules, it’s fine by MPLAB and by extension we have something to pass on to the PIC. Useless? No, we are trying to test all our tools.

 

 

In our PICproj directory, we see…

firstest cod 3.072 11/03/02 13:28 FIRSTEST.COD

firstest err 0 11/03/02 13:28 FIRSTEST.ERR

firstest lst 680 11/03/02 13:28 FIRSTEST.LST

firstest pjt 1.482 11/03/02 13:51 firstest.pjt

firstest asm 20 11/03/02 13:28 firstest.asm

firstest $$$ 19 11/03/02 13:21 FIRSTEST.$$$

firstest hex 13 11/03/02 13:28 FIRSTEST.HEX

7 archivos 5.286 bytes

MPLAB has indeed been working, three of the seven we recognise immediately maybe above all the firstest ,hex file which is what we need to run the PIC.

 

 

What to do with the HEX file

Before going on, let’s open up the project again and press the Project then, project Edit buttons. The bottom button in the window that opens is called Node Properties, but is greyed out. Click on firstest.hex and the Node properties become alive. Click on it and here we have a whole host of things to fiddle with.

Leave them alone for the moment as they are the default settings established by what we have entered earlier and in part by what MPLAB thinks is "Normal"

Look at the HEX FORMAT row. We are offered three possible formats. We haven’t chosen any of them. Can we leave it like that? Well the short answer is yes. But be aware that extension. HEX is not universal and comes in different flavours.

In our case we are going to use ICPROG next, to get the hex file into the PIC, and fortunately we find that ICprog is happy with the default output of the PIC.

But if you use something other than ICprog, this may not be the case.

Setting up ICPROG

Icprog want to know above fig.21

all what kind of test card is holding the PIC and you tell it which by choosing from the list options shown in the settings, hardware settings menu that is open in fig 21.

The other options that a different programmer could need to have changed are listed on the right under the heading communications.

In my case I selected the JDM programmer from the list, and COM2 The list also is useful in that it is a list of programmers that will work with Icprog.

 

So having set up ICPROG to work with our programming card, we then open the Hex file in PICproj directory.. Now as this is just a comment, we will not program a PIC, but we will exercise the COMMAND menu..

First we load from the PICproj directory "firstest.hex", then as supposedly we have a PIC 16F84A inserted in the programmer card, we check that it is blank. . press Blank check.

After a few seconds we should see confirmed blank, OR, that it has data stored in the 16F84A. ( In real life , maybe we used the PIC before for another version or program).

If the PIC is found not to be blank, then we need to wipe it. With ERASE ALL option in the command menu.

Here there are only two possibilities, it gets wiped or data remains. How can this be if we have just the ERASE ALL command? Yes, good question. If you program the PIC more than about the minimum 1000 times, well it is possible that the Flash programming stops responding in some cells. Then what? Best find another PIC.

In the other normal case, we get the message " Device is blank". Then we can move our hex file into the PIC clicking the COMMAND, PROGRAM ALL buttons.

Icprog then programs the PIC and does a verify at the end to make sure that what is in the PIC is the same as the hex file.

However we sometimes are not sure which hex file we have in the PIC at that moment. So we can do a recheck.

 

Summing up

The dummy program Firstest.asm has enabled us to use many menus in the chain that takes us from untested code to compiled code and putting it into the PIC . In other words, we have tested a complete chain. So now we will test a simple module to learn a little more about what the PIC expects

 

 

CHAPTER 6

 

A simple Hex to Decimal routine

In my snippets box, I have pulled out one of the partial routines or code blocks which I had to invent as the bike project developed. It is called myh2dec.asm.

In the first lines of the program I write it’s purpose and the date. I see I also commented on routines on offer in the internet, which simply didn’t work.

The routine itself is very straight forward and it’s purpose clear. The main program does all it’s calculations in Hexadecimal, but when we need to show the results on a Liquid Crystal Display, an LCD then we must change the hex into decimal.

For example, suppose the speed module calculates the present speed is 0xD.

Ah , 0x is the way we say that the following number is hexadecimal, so 0xD is 13.

If we don’t change to decimal, the LCD will show maybe Speed D km/hr

Not very useful, How about Speed 1A km/hr, ( 26km/hr I hope)

Lets comment the program to change the hex to dec. I use it extensively. It is slow but works fine.

I’ll add new comments useful to us for study, in a different font letter style

 

 

 

 

 

 

;-----------------------------------------------------------------

; myh2dec.asm version 1 Sept 01 written by Fred

;-----------------------------------------------------------------

;

; MY HEX TO DECIMAL FOR LCD

; The ones from the internet simply didn't work, this is slower ; ;but incorporated into bike asm works fine.

; All of the lines above begin with ; and are just comments, they are useful for the ;information they contain, especially the date and version +My grumbles on wasted ;time

; the next three lines tell the compiler what microcontroller we are using. , Include

; has standard definitions, and _CONFIG is shorthand for no code protection, no

; watchdog timer, the oscillator type is an XT crystal and power up delay active

LIST P=16F84A ; 16F84A Runs at 4.000 MHz

INCLUDE "p16f84A.inc"

__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON

 

; the error level comments are clear enough

ERRORLEVEL -224 ; supress annoying message because of tris

ERRORLEVEL -302 ; supress message because of page change

; The cblock is where the variables are defined. Note the starting address is given 0x0C

cblock 0x0C

ones

tens

hex

count

ENDC

; There is no interrupt routine ( jump to ORG 4) so not here but it is in the main prog.

ORG 0 ; start at location 0

GOTO Main ; jump over to main routine

 

; Here the program proper starts. Note that the Labels ( ending ":") are in the first line.

; Yet when you use it in a command, don’t write the ":" e.g. GOTO Main

; also if main and Main are written differently( case sensitive) ;then, we get an error ;message ( not found or not defined) .

Main:

clrw

movwf count

movwf hex

movwf ones

movwf tens

movlw 0xF

movwf hex

; put all variables to zero just in case they have been used else where and have ;a number inside them

; The conversion to decimal is very simple. A counter COUNT which initially is ; set to 0, is compared to the HEX number that is to be changed into decimal.

; if they are different, the counter increases by one. At the same time the ;variable "ones" also is increased by one, so they are the same. However

;when count increases from 9 to 10 (0xA), ONES is reset to 0 and TENS by+1.

; This means that for ever 10steps, units go to zero and decades increases by 1 ; Put another way we have converted to decimal and can now send the HEX

; equivalent as two decimal digits to the LCD

;The process stops when the xor test sets the STATUS, Z flag. When HEX and

; COUNT are NOT the same, the btfsc command skips and the conversion ; continues.

; When they finally are the same the xor gives 0 and so the btfsc test does not ;skip letting the GOTO Decout instruction be executed and we exit the ;conversion. This system can easily be extended to hundreds, thousands….

 

 

 

H2d: ;change hex into dec, start all zero

movf count,w

xorwf hex,w

btfsc STATUS,2

GOTO Decout ; they are equal

incf count,f ; count < hex

incf ones,f ; this may make one = 10 so test

movlw 0xA

xorwf ones,w

btfss STATUS,2

GOTO H2d ; ones is not 10

incf tens,f ; ones is ten, so add 1 to tens

clrf ones ; put ones to 0

GOTO H2d ;

Decout: ; now tens and ones hold decimal o/p

nop

GOTO Decout

end

;------------------------------------------------------------

; End of Hex to Dec routine

;------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

Debugging " myh2dec.asm" with MPASM

Well now that we have added more comments to the file and think it is all right, let’s see what new windows in MPASM we can use to test it.

So as not to change things too much, we will use the same picproj directory after removing the bits and pieces of firstest.asm.

Just let’s compare beforehand what we are going to do with the steps we had to follow before . This time there is no setting up needed. MPLAB will remember unless told otherwise, that we are debugging a program.

Recalling the things we did, we set up:-

Next the sequence to start a new project. This a little like putting the cart before the horse, but we will name the new project the same as the assembler file, myh2dec.prj

(This is very necessary when we start debugging lots of different routine modules. E.g. Test 22.asm is a bit meaningless and can be downright confusing, when a couple of days have passed and we are back tracking trying to remember the last module that worked before changing.)

The names themselves, can be different but you must always have the file in the same directory as the project. Otherwise MPLAB refuses to go on.

So we open MPLAB and follow use the following menus

  1. Click on Project
  2. click on new project
  3. name it as myh2dec.prj
  4. Careful here… MPLAB sometimes goes back to it’s root directory. So reselect the picproj directory before saving.
  5. The project window now needs a node Click Add node
  6. We have no program yet. Lets jump out of the list and make it
  7.  

    Select the text we have above for the hex to dec routine. Copy everything.

    We should have copied

    ;-----------------------------------------------------------------

    ; myh2dec.asm version 1 Sept 01 written by Fred

    ;-----------------------------------------------------------------

    ;

    ; MY HEX TO DECIMAL FOR LCD

    …………

    ……………..

    …………

    ……….

    end

    ;------------------------------------------------------------

    ; End of Hex to Dec routine

    ;------------------------------------------------------------

    In MPLAB click on File in the top Bar

    Select NEW

    An empty file window opens

    Use control V

    To fill the empty window with the text we have copied

    Save

    Name as myh2dec.asm

    We can go back to the PROJECT sequence, we were at point 6

  8. In case the project menu has closed.
  9. Click PROJECT
  10. Click Edit project
  11. Click Add node
  12. Now we can select myh2dec.asm
  13. Click OK
  14. Done.

 

The new project has been opened, named and connected to a file with the extension. Asm.

Now if we are lucky, when we click Build All in the project menu it will compile with no errors. But if it doesn’t look for items which have moved from their position because of moving the copy from the word. Doc, or comment ";" characters which have got lost.

Note When I did this text move I got the following warning messages.

Building MYH2DEC.HEX...

Compiling MYH2DEC.ASM:

Command line: "C:\ARCHIV~1\MPLAB\MPASMWIN.EXE /e+ /l+ /x- /c+ /p16F84A /q C:\PICPROJ\MYH2DEC.ASM"

Warning[205] C:\PICPROJ\MYH2DEC.ASM 21 : Found directive in column 1. (ERRORLEVEL)

Warning[205] C:\PICPROJ\MYH2DEC.ASM 22 : Found directive in column 1. (ERRORLEVEL)

Build completed successfully.

 

(The error level instructions had drifted to the left during the move.

So once moved away from column 1, the compile was then warning free.)

So once we have compiled the project error/warning free, we will start to debug and open some of the menus.

We press F5 and F6, we should see we have jumped to the start of the code.

So to start with we have the following view

. fig 23

Good. Now we can experiment advancing the program line by line to see where it goes during its execution. We SINGLE STEP pressing F7.

Try it. Return to the start, pressing F6

Now this is good, but we need to watch the values of the variables that we are using.

 

The Watch Window

We click on WINDOW, watch window, New Watch window.

Fig 24

We need to follow the changes in the four main variables of the hex to dec module. So we look in the list and select count, tens, ones, hex.

These then appear in the previously empty Watch Window. Their initial colour is black, but every time the project passes through a line where they are named, they will change to red if they change actual.

Let’s position the Watch window Fig.25

on the right and resize with the mouse.

Start stepping with F7. The values in the watch window will change colour and increase as the program advances. It will finalize when COUNT is equal to HEX. It will then stay trapped in a little loop the just repeats itself.

The snapshot on the right shows the variables when count has reached D and tens +ones show 1 + 3

Read together = 13

 

The F5, F6, F7 and ( control + F9 ) keys

We will introduce two more keys. F5 and F9.

 

F5 stops execution when the program is running

F6 resets to the beginning of the program

F7 allows single stepping.

F9 starts the program, but it goes so fast we can’t see much, just the time that is passing.

So we need an execution speed that is somewhere in between F7 and F9

Control + F9 is what we need, slow execution.

We can still see the variable changing as the program advances

We will stop, reset and start again

Please note that reset means jump back to the start. It does not put the variables to zero. Some code lines in your program will do this if you want it to. Other times you will want to leave the variables alone and hold their values till needed later.

So run the program a couple of times looking at the variables as they change. Also when we jump back to start with F6, the variables hold the last values.

 

Finally try to run using F9 by itself. It is so fast that we don’t see the variables changing. Use F5 to stop the program, then you can see if anything has changed.. No’

But it has changed, all the variables have been cleared and the program starts each time at the beginning when we press F6. The reason we don’t see the change with F9 is that it is going full speed and takes very little time to reach the .

We will open another window now to do some time measurements.

 

The StopWatch Window

 

This is very useful. It shows the time that an action takes, the action can be moving one line or cycling through the whole program.

Lets try timing how long the conversion of hex D to 13 takes. We will use the

Control F9 combination as F9 alone , is too fast. Right ,we see the program is at the end and in the do nothing loop, so stop and read the time taken, a little over 200usec.

If we watch, a few other things become clear. When we reset with F6, the time also goes to zero. If we don’t want this, untick the " clear on reset" button. It is also clear that the exact conversion time is difficult to gauge just looking at the variables and hitting the F5 stop button. So lets make the Decout label a break point

 

Debug Break settings

We get there from Debug, Break setting, Break point settings

Next click the start arrow and we are shown the avail points for setting a break. We select Decout and click Add then close.

Now when we run the program see how it stops when it gets to Decout.

Look at the time on the stopwatch, it is shorter than we thought, 182us.

The logical question that arises here is… is this a short time or a long time ? Well that depends on your application. In the bike application we have about 1 second between refreshes. Also the main calculations are done in a couple of milliseconds. That means we can spare some time to convert to decimal. Also the speed and the time and the Average velocity are all small numbers.

The distance is the exception, we measure up to 99999 …. ( good grief at first sight it will take more than a second. E.g. 99999 x 100us is 9.9999 secs….)

So as a little exercise lets add on a couple of more variables and expand the hex to dec routine to be able to measure up to 99999 . You do it . You just need to copy the loop adding new variables at the start. Lets call them hund, thou, tenthou… enough for 999999. Also we need more hex variables to hold the start number . The max for our variables is FF= 255. two variables in series would hold 65536 as FFFF.

But can you do this just like that?

Well yes and no, we need to program a bit more then?

Yes.

Ok to keep it easy we will stop at 255, making hex initially FF.

When we measure the time taken about 3 ms, a rough comparison gives that count to 15 ( subtracting the initial set up) takes about 165usec. So a count of 1 is around 13 to 14us. 255 x 13 = 3.3 ms. OK this scheme is linear. The bigger the number to convert , the longer it takes. You say then

"Well if it takes 10 sec to count to 99999, the bike is doing nothing when distance is a big number."

Fair comment, now think of a solution … an easy solution.

While we are doing all these modifications, have you noticed that just touching the asm file means we have to recompile all over again. That is, go to PROJECT menu and Click Build all. Get the message all correct and then run the new version.

This is inescapable. MPLAB has no way of knowing what has been changed. She simply knows that the file is different. So she won’t let you run the program until the program has been recompiled in a project rebuild

Another detail.

If at some point we stop to reset the Stopwatch to measure some lines of code. When we try and restart by pressing F7 or F9 or F9+control. It doesn’t start. The reason is when we have several visible windows, we need to have the program window active, or selected to make it respond to our key presses. Fair enough but not too obvious in the beginning

 

The Stack window

 

( This is for those of us who have never heard of a stack)

In the windows menu there is another option called stack. If we click on it we gat a new window simply called Stack window. It is blank initially with a cryptic message

"1 Return address"

This window shows you how many sub routines are being used at a given moment.

A little more information is necessary. It only tracks subroutines that are started with the CALL instruction, not with the GOTO instruction. You can jump about all over the program with GOTO instructions and the stack doesn’t care .

CALL is different. You go somewhere. OK, same as the GOTO. Yes but the GOTO doesn’t return to where you jumped from, the CALL instruction does.

When the CALL is finished, you expect to be able to carry on with what you are doing and so you have to store critical values before you go to the CALLED routine. There you will do something and could change the old value of the CALCULATION register, which we know by now is the W register. So we store it and some FLAGs, If these are changed or aren’t changed, we replace the old values anyway when we come back.

But can you call with in a call? Yes up to a value of seven calls. This is called nesting. The PIC has a stack depth of 7.

Not clear. OK, we’ll try and invent an example with a car computer. . We are cruising along at say 100km/hr. The computer get s an alarm that something is wrong with the engine.

We store speed in stack level 1 and call motor

Motor may have a couple of possible values but as this is an alarm we store checking water temp as Wtemp. In stack level 2

Motor checks the various processes and finds a flag in oil.

Checks oil and there is oil. Notes level =1 stack level 3

Oil module checks temperature and it is now normal, 180ºC Stack 4.

Sorry about the example it is not very good.

The only thing I want to say is we have to keep track simultaneously in the working register of 100, 2, 1, 180.

You can’t jump back with the value 180 as you were driving at 100. So you invert the process going back through the stack and restoring the values to each level.

Is seven levels enough? Depends how you program, but personally if I run into the situation I try and change the sequence of operations or change some CALLs into GOTOs. We have inserted these calls into the program and this is what we see when all the calls are active. Fig.28

The program does nothing for as each call routine has no operations except the last call. Then it see return followed by return, followed by return until we are back where we jumped from ready to accept the next instruction a GOTO. The GOTO also jumps but doesn’t return.

Please note that the last called, temperature is the top of the stack. So we can imagine if we try and call more times than the stack has levels, the first one called , Speed, will just vanish as it is pushed out of the bottom of the stack..

 

 

 

 

Summing up using MPASM

Here we can stop and take stock of the various new windows we are now using in MPASM. Of course there are more, but we have sufficient to do normal code development with the following windows SIMULTANEOUSLY in use ( i.e. opened for us to see what is happening).

The Basic Windows

  1. The main MPASM Window to have access to the button icons, in particular, for using the
    1. Project, Build all, Buttons and the
    2. Debug, Break settings, buttons.
  2. The Stack Window for sorting out CALL problems. To be honest in this application it is infrequently used, but in other CALL intensive applications STACK tracing will be very important.
  3. The StopWatch Window for timing the execution of everything in general; from humble code snippets through major functional blocks to complete programs.
  4. The FILE WINDOW. which displays a file xxxxxxx. asm , our program. This is perhaps the most important window as it allows us at all times to see where the program is executing. We follow at three different speed settings with
    1. F7 Single Step, slowest speed
    2. Control+F9, middle speed
    3. F9 alone , fastest speed

  5. The Watch Window. Also essential, because it complements directly the FILE WINDOW, showing us at all times the value of the variables at each step of the program execution.

 

The Menus we have used till now

The rest of the menus offer options that are needed but not essential at the moment.

As you get more hands on experience you will gradually open these menus to find features you hope exist in MPLAB. We will only mention specifically two of the menus.

HELP for example, offers TOO much and is complex, hard to use for a beginner.

EDIT, is simple but you may prefer to use your own favourite one.

EDIT takes us on to the next topic about getting started…

CHAPTER 7

MPLAB Number Formats

There are lots of little fiddly things about the way we WRITE the code itself. We notice that we can enter numbers in various formats, specifically in the beginning we are interested in Hexadecimal, Binary, and Decimal. Now MPLAB is very good in the sense that we can enter all three number formats providing we use the correct format designators. You know, give MPLAB a clue as to what you want to do.

The basic enter a number command is movlw

This is followed by the number. When I started this caused me a lot of confusion, especially the decimal form. The problem is that MPLAB accepts different ways of writing the same thing

Lets look at the ones I have found, ( there may be more).

A simple test is write them as a code fragment and use the MPLAB compile to see if it is accepted.

Copy the program and compile it.

Note. The CODE lines that DON’T work, or do something different are preceded by ;

Try removing some , compile and see the warning/error message. But put the

Comment ";" back , recompile then move on.

;-----------------------------------------------------------------

; numsysts.asm version 1 March 02 written by Fred

;-----------------------------------------------------------------

;

; A LOOK AT NUMBER FORMATS THAT MPLAB WILL ACCEPT

; We test various ways of presenting numbers to MPLAB

LIST P=16F84A ; 16F84A Runs at 4.000 MHz

INCLUDE "p16f84A.inc"

__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON

 

; the error level comments are clear enough

ERRORLEVEL -224 ; suppress annoying message because of tris

ERRORLEVEL -302 ; suppress message because of page change

; The cblock is where the variables are defined. Note the starting address is given 0x0C

CBLOCK 0x0C

temp ; to hold a number for operations that can't be done on w.

ENDC

; There is no interrupt routine ( jump to ORG 4) so not here but it is in the main prog.

ORG 0 ; start at location 0

goto Main ; jump over to main routine

 

; We use the constant entry command MOVLW to try out as many variants of

; the different number forms that we have found MPLAB accepts-

; Note the instruction movlw can be written with / without capital

; letters. But to give the code we write a coherent appearance we will

; always use SMALL letters

; open a watch window for temp and w

Main:

;Test entering number 0. MPLAB accepts all the combinations

;of UPPER and LOWER case letters.

clrf temp

movlw 0

MOVLW 0

Movlw 0

movlW 0

; We also have offered 0 with no format, just plain 0

; Let's repeat with formats to see what happens.

movlw 0x0 ; Hex

MOVLW b'0' ; binary

Movlw D'0' ; decimal

movlW h'0' ; hex

movlw 0H ; Hex

movlw 0h ; hex

; just too many hex forms, be prepared. I use 0x as the hex identifier.

; Maybe another number would get different

; treatment, try with 9

; Note we will leave in place a format combination with

; a fault and write in the line below the "good" version

movlw 9 ; none

movlw 09 ; none

movlw 0x9 ; Hex

;movlw b'9' bin nums are only 1's or 0's

movlw b'1001' ; this is OK

movlw D'9' ; decimal

movlw h'9' ; hex

;Lets play a little more with the binary line (make it 5 to

; stay inside the 8 bit max)

movlw b'0101' ; this is OK

;movlw 0101 ; 2

;movlw 0102 ; 3

; MPLAB accepts 2 and 3 but we start getting strange warnings

; about CBLOCK. 0101 and 0102 can also be decimal or hex.

; Note one 8bit byte can hold up to max

; B'11111111' or D '255' or H'FF'

; let's test what MPLAB THINKS THEY ARE.

 

movlw b'0101' ; this is OK

movwf temp

incf temp,w ; if binary will be hex 5

; if decimal will be 0102,

; if hex will be 66 hex

; that has clarified, the number after adding 1 is 6,

;MPLAB treats as binary

; and if we take away the ' ' ? It will object to the b.

;If we also remove the b? well lets test

 

; movlw 0101 ; getting dodgy, MPLAB sees as 1

; movwf temp

; incf temp,w ; w is now 2

;Last tests on the decimal format

clrf temp

clrw

;addlw D255 non starter MPLAB SEES A NEW VARIABLE D255

movlw d'255'

movlw D'255'

movlw .255

; These three are equivalent but the last is almost dangerous

; often I have missed or misinterpreted the point.

 

oot:

goto oot

end

; to be consistent I use the small letter forms

; b' 'and h ' ' and d' '

; though personally I prefer the 0x for hex

;------------------------------------------------------------

; End of Numsystems

;------------------------------------------------------------

 

Letter Case conventions

You can write the code in many ways, MPLAB is quite tolerant compared to other compiling programs. However it has some predefined words for variables/registers.

Where are they? Well after any compile when you have a watch window opened, the variables in your program become available for watching.

But you will also see a lot more that you didn’t add… often used ones,

with two forms like:-

Looking at the top one, the STATUS register, you need to add THE BIT NUMBER you want to observe , for example after doing an operation on a number, the result logically can be zero or not zero.

So we can bit test the status register to see if the zero flag is set with

the command 1 or z

btfss status ,1 BAD

btfss STATUS, 1 GOOD

btfss status, z BAD

btfss STATUS, z BAD

btfss status, Z BAD

btfss STATUS Z GOOD

 

 

Why only capitals? I don’t know, but MPLAB only will accept the upper case version for these registers. The important thing is to know what can happen and use the correct form of the word.

In the code I have written there are two groups. All MPLAB predefined names like those for STATUS, are in upper case.

My variables, my labels and all instructions are in lower case. Only the first letter of a label is in upper case. These helps me to see what is what in the code that is written.

But I insist, you can write the code anyway you want, providing you use the UPPER CASE where MPLAB seems to need it.

 

More on generating code

Most of us will have written code in other languages and have generated a few pet routines.

The practical difficulty with assembler is that it is so elemental that a lot of routines cannot be reused as the commands don’t exist.

Multiply, divide, subtract, add all need routines to be invented when we move away from simple bit operations.

Fortunately, many people have already sat down and sweated away forging these fundamental routines. Many of these routines and many of their inventors are to be found at PICLIST. COM on the web.

This is a huge very complete site on almost every aspect of code. To be more exact SOURCE CODE. There must be hundreds of examples classified under headings like math, lcd, … you name it.

We will lean very heavily on the site and refer to specific code routines already written

to get a second and probably better interpretation of how to do something.

 

 

The hex2dec Time problem with Big number

In the Debug Break settings paragraphs, we mentioned that the hex2dec module could have problems. We looked at the h2d routine, myh2dec.asm. It was fine for small numbers, with the conversions taking about 100usec…. But the big numbers like distance max, 99999m would on this basis take 9.999 seconds, too long.

There we were asked for a solution, a simple solution.

Well now for the answer.

Consider 99950 metres. Starting at zero and advancing one by one till we arrive at 99950, indeed would take a long time . But we can use the same routines for hex decimal conversions in a subtly different way. The variables instead of being recalculated can be INCREASED. So in the DISTANCE module we only have to e update every second the variables to show the INCREASE IN DISTANCE.

So the code instructions do not have to convert the whole number from scratch, but increase the numbers already held by ( 2 or 4 or 53 m), a small quickly executed increment.

This is a very different kettle of fish.

How long? We only ask the DISTANCE module to UPDATE the already calculated numbers by 2. The time required, once more drops to usecs.

We will see this soon in practice in the BIKE COMPUTER program

If you don’t see the difference immediately in the time involved, don’t worry, I didn’t see it either, until a lot of different ways were tested. But for the moment we accept that INCREASING the already calculated variables by 2m will take very little time,…. we have measured typical low number times of 60us and high number times of about 350usec.

CHAPTER 8

The Bike Computer Flow diagram, simple version

So we are about ready to do some practical programming. The BIKE COMPUTER will be our model. Not that it is a brilliant piece of code writing, far from it. Let’s say it is useful because it is a first attempt and the code is large and simplistic. But that is where it helps us, it is indeed simple to follow. The blocks are well defined and reuse of variables is minimal. Even so we have the advantage of being able to study a big program that works.

How does it work? As it is all written, we can use a flow chart to show the functional blocks. Lets make a simplified flow diagram of the bike computer. Here we see the main blocks only. The very necessary routines that do the calculations and respect the protocols for timing and data transfer to the LCD display are better described in the discussion of each module’s features and operation.

As we read through the program listing, we will describe/ discuss the main points of the operation of the Bike computer program’s modules.

These being:-

The Flow-Chart

At last we have a flowchart, which illustrates the major blocks of code within the bike3.asm program.

The diagram needs very little comment.

The action starts at the top left. There are a series of initiate routines, for registers, ports and LCD.

Once these have been completed we go to the top of the second column and are at MAIN. The firsts Label in main is Changesec. Changesec is the start of a cycle as it is the zero time reference for all the actions that follow.

It also implies that all that follows happens inside 1 second. This is true if the bike is moving faster than 6.4km/hr.

Resolution Available

We start as a new second occurs and lets us escape the CHANGESEC loop

We move on to the wheelpulse loop. How many pulses can we have in a second?

Well to get a feel for the real life quantities, 2pulses/sec =15km/hr,

4pulses/sec =30 km/hr. looking at this another way

Expressing these times in ms…

There are limits to this system. It tends to give a jumpy speed indication above 50km/hr and ideally we should integrate taking the mean of several readings.

On the other hand there are few cyclists capable of maintaining more than 30km/hr on a level road as the HP you are using means that the quantity of calories needed rises very quickly to keep you going at these speeds.

Another factor is the resolution. Well this system detects ¼ ms intervals. This means for example that we can divide the time difference for the km between 15 and 30km/hr into 250 x 4 steps = 1000. Therefore we can display in steps of (30-15)/1000 km.

This 0.015km/hr. We could have a display then, like 15.28km/hr. But in the real world we don’t need so much and would round to one decimal place 15.3 km/hr.

Back to the Flow Chart

We were talking about the Wheel pulse measurement limitations. Now the normal sequence will be measure the time between two pulses. This is a large routine but not very hard to understand reading the notes beside each piece of maths.

What are two pulses? They are the sensor output each time the magnet passes it.

They represent a distance of 2.0747m But we use two and compensate every so often adding the ignored 0.0747m.

So speed is obtained from Distance / Time, here = 2.0747/( Pul2 – Pul1 )

The transformation to km/hr is simple, multiply the result, m/s, by 3.6

Just a little aside . The same incoming pulses flash a Green LED briefly. This does two things which are useful for debugging, but doesn’t offer any other feature, except maybe at night, you could judge your speed from the cadence of the little green flashes.

The Automatic menu

The menu variable increases every second by 1

The top line of the LCD is always Elapsed Time

The Bottom line of the LCD changes according to the value of Menu

When menu is in the range 1 to 10 the LCD lower line displays Speed

The Chart arrows lead us to Distance:

When menu is in the range 11 to 20 the LCD lower line displays Distance

The Chart arrows lead us next to Average velocity:

When menu is in the range 21 to 30 the LCD lower line displays Average Speed

We then loop back and wait for a new second.

To sum up. Every second the menu loop calculates

  1. Speed
  2. Distance
  3. Average Speed

But only one of them starting with speed, is displayed during ten seconds before the display updates and shows the next parameter, Distance for ten seconds, then the next Average Speed for ten seconds.

30 seconds have passed and menu increases to 31. This triggers a reset.

Menu resets to zero and the cycle repeats, SPEED, DISTANCE, AVERAGE SPEED in an endless loop

 

The Complete Loop Execution Time

Well as we are confined to a 1second cycle for everything to be done. Are we in trouble trying to get everything done?

Well fortunately the instruction execution time is nominally 1 usec.

The SPEED DISTANCE and AVERAGE SPEED modules are complete within about 2msec each when the numbers get big. This is worst case.

What takes a bit more time is getting the data onto the LCD, about 20ms. ( don’t forget there are two lines).

So being really pessimistic we need 30ms to cycle the menu + 2 display lines

A second has 1000 ms. This means that we can only handle a maximum of 33 wheel pulses per second..

Is this enough? Well each pulse represents about 2m. If we con only handle 33 in a second, then the maximum speed we can measure is about 66m/sec

Or 237km/hr or 150mph. This would seem to be sufficient for all normal cyclists.

 

 

 

 

 

Compromises

We read of them in the introduction and in various parts of the following chapters. The initial project had more facilities, but at a certain point, it was discovered that we had run out of memory.

The variables you can have directly are 67, The cblock holds them in continuous space from 0Ch to 4Fh. There are many things you can do to get more memory.

But this is supposed to be a SIMPLE bike computer, and using sophisticated circuitry hardly helps to write a clear easy to understand article.

That is why it was decided to stop with a minimal , but functional block of code. One of the compromises was to complete all the actions inside the second. If something took long, well that could be accommodated in the next version.

Also in the previous paragraph we mentiones mph. This was to be another option of the computer, display in Miles or in kilometres. It too will have to wait.

 

 

CHAPTER 9

 

Nuts and Bolts

We have talked a lot about functional blocks, but there is a lot of reused code which is common to all modules, the nuts and bolts which make the program possible and hold it together!

We must include in these categories two areas about which we have said very little.

 

Math routines

All of the basic routines for hexadecimal maths

are freely available on the internet. They come in a multitude of shapes, 4 , 8, 16,24,32…bit.

There are just two little problems. Many of them aren’t what you want and, many of them are theoretical, and hard to put into assembler code ( a euphemism for maybe they never have worked).

Another more subtle problem is that some work with the example figures but not with others…. Gulp!!!

We need routines that work with all figures inside the bit range required.

So you can imagine that this was a long process narrowing down what was available and what was required.

Fortunately in the PICLIST. COM, you will find the routines that I have used and many others, which also work, but whose operation is a bit too subtle to be included in this SIMPLE first time code effort.

 

LOGIC routines

These have been kept to a minimum . Basically the Bike computer uses

An EQUAL TEST, which is the xorwf instruction. STATUS, Z

A less than equal =< coupled with greater than > test

Which use these instructions e.g. subwf dtothi,w followed by btfsc STATUS,C

These, AND MANY MORE, are well explained in the articles in PICLIST.COM.

 

Conversion routines

The three main types that had to be invented were converting

  1. HEX to DECIMAL
  2. HEX FRACTIONS to DECIMAL FRACTIONS
  3. NUMBER SCALING

 

 

HEX to DECIMAL

This we have already discussed h2d in previous paragraphs but the basic routine is used in the three calculation modules for, SPEED, DISTANCE and AVERAGE SPEED.

You should be able to follow the conversion routines after a little bit of study. The notes in each routine to say where you are in the process are abundant.

HEX FRACTIONS to DECIMAL FRACTIONS

This merely is an extension of the previous routines with a little bit of reasoning to change hex remainder and fractions into decimal fractions.

The fraction routines are needed because the pics don’t handle directly fractions, so they have to be changed into whole numbers by suitable multiplication.

 

NUMBER SCALING

We do a lot of multiplication and division in the three main calculations for Speed, Distance and Average Speed.

But we have a practical 16bit number limit. The numbers can’t be bigger than 65536.

If they are, then we need to add more registers, and probably bigger calculation routines able to handle more than 16bits. So I decided to try and stay as far as possible within the 16bit routines.

In some places you divide and the result of the division has to be multiplied by another number. For example 2000.

So you divide your first two numbers. The result is say ten.

Then the next operation has no problem because 10 x 2000 is 20000 which is< 65536.

However if the first division had given as a result 300, then we have a problem.

300 x 2000 = 600000 way above the limit of 65536 we need to scale somewhere.

The scale factor here would be about 20. But this is one of those things that is best seen following the steps the code takes , say in the SPEED block.

Basically the number is tested for size and divided down until its product with a reference number is smaller than 65536. But as we said above, follow the steps taken in the actual code block to see how the scaling is done to solve a specific application problem.

 

LCD Setup, Signalling and data transfer routines

The LCD itself has on board a complex controller chip whose job is to interface with a uController, in this case our 16F84A and steer the incoming data messages to the correct position for display.

There are two basic operation modes; 4 bit and 8 bit. Most applications seem to use the 4 bit mode as it will free 4 lines of a uController to do other things.

The data is strobed into the LCD using appropriate signals on the E and RS lines. The protocols are also time sensitive. They have to be as long as the minimum times quoted on the LCD data sheets. Here lies a problem.

The LCD chosen is very popular. It has many clones. SOME of the clones need EVEN longer times. This means that the typical DELAYS programmed could be insufficient.

Before anything can be displayed, the LCD needs to be initialised. This is a really slow process taking about 50 to 100ms. The number of times the routines are repeated during the initiation sequences seems a little exaggerated but it has to be that way to get the LCD up and running, it is exactly what the manufacturers spell out on their data sheets.

Each command or data interchange between the PIC and the LCD has it’s corresponding minimum time. These have all to be scrupulously observed or the process fails.

That is the reason why there are so many different time blocks within the delay module plus some additional ones for other tests.

All of the routines can be found on the PICLIST.COM site. I take my hat off to whoever sat down and worked them out first time round, a really heroic and Herculean task.

 

Automatic menu (2)

The operation of Automatic menu was explained previously under the heading of that name when we were looking at the Flow Chart.

However this was one of two possibilities in the original project, the other, manual function selection needed two push buttons plus the corresponding code so that was dropped as the PIC was running out of space.

There is nothing special about the way the menu presents the three main features. Their combinations features to the LCD can be changed if you prefer. For example, maybe you would like to see at once Average Speed and Total distance, or maybe Speed and total distance.

There are many combinations possible. Of course if you do change then don’t forget to follow through into each module that is being used to see that there is no other unwanted effects.

 

Bike3.asm

We can now study the complete program which is called bike3.asm

With the help of the previous Flow Chart which shows the sequence of major functional blocks of the program, and reading through the code below, it should now be possible to understand, hopefully fairly easily, how the code blocks have been cobbled together.

Made to implement the basic equation we started out with.

Speed = Distance /Time.

 

 

 

 

 

 

 

 

;----------------------------------------------------------------------;

; bike3.asm Combines: Time , Dist, Av velocity, Inst Vel

; Fred Maher 1st March 2002

; BASIC BICYCLE COMPUTER WITH THESE FUNCTIONS

;----------------------------------------------------------------------;

; 1 Trip Time HRS:MIN:SEC

; 2 Trip Dist 000km 00m

; 3 Trip AvSpd 00.00km/hr

; 4 Speed 00.00km/hr

 

 

;---------------------------------------------------------------------

;------- HEADER ----------

;---------------------------------------------------------------------

; LCD MESSAGES

; position at beginning of 1st line col 0 movlw H'80

; position at beginning of second line movlw H'C0'

LIST P=16F84 ; 16F84 Runs at 4.096 MHz

INCLUDE "p16f84A.inc"

__CONFIG _CP_OFF & _WDT_OFF & _XT_OSC & _PWRTE_ON

ERRORLEVEL -224 ; suppress annoying message because of tris

ERRORLEVEL -302 ; suppress message because of page change

; Define Information

#DEFINE RS PORTA, 2

#DEFINE E PORTA, 3

;#DEFINE TOGGLESW PORTB, 6 ; not used at the moment

;#DEFINE LED PORTB, 5

; Macro

;---------------------------------------------------------------

CBLOCK 0CH ; from 0C to 4F = 67

;---------------------------------------------------------------

; MATH ROUTINES

; 16 X16 Mult , --> 32

; mah mal x mbh mbl = mq4 mq3 mq2 mq1 ( mq4 highest)

mq4

mq3

mq2

mq1

mbh

mbl

mah

mal

; 16 / 16 Div --> 16

denlo

denhi

numlo

numhi

rmdrlo

rmdrhi

reshi

reslo

;temp also used in nybble

; Addition 16+16 out max 65536 (no carry)

; Subtraction q1_16-q2_16 out r_16; neg numbers not allowed

q1hi

q1lo

q2hi

q2lo

rhi

rlo

;------------ Distance -----------------------

dtotlo ; total trip distance in metres

dtothi ; dtothi/lo hold a max of 65km 536m,

dtothi2 ; with this added max now 16777km

dist54 ; corrects +2m every 54m (27x2.0747 =56)

dm

dm10

dm100

dm1000

dm10000

dm100000

;------------ Average velocity Vav -------------------

;vavhi

;vavlo

;divrat

;stemphi ;second info passed to stemphi/lo

;stemplo

;dtemphi ;dist info passed to dtemphi/lo

;dtemplo

m

m10

m100

m1000

;--------- Time and trip time --------------------

;

sectotlo ; total trip seconds

sectothi ; max 65536 = aprox 18hrs

sec ; seconds digit

sec10 ; 10's of second digit

min ; minutes digit

min10 ; 10's of minutes digit

hr ; hours digit

hr10 ; 10's of hours digit

oldsec ; holds last value of sec

cntmsec ; count ms

TMR18 ; TMR0 217* TMR18 18 = 1 SEC

;---- isr interrupt service routine push pop -------

w_temp ; W isr var

status_temp ; STATUS isr var

fsr_temp ; FSR isr var

; --------- Instantaneous Velocity Vin --------------------

vinhi

vinlo

sectemp

oldtemp

totmslo

totmshi

totms2lo

totms2hi

mshi

mslo

spdflg ; 1st pass =0 2nd pass =1, diff is time between pulses

;-------- Miscellaneous ------------------

temp ; a temporary used in divide and nybble

count

menu

ENDC ; end of definition block

;-------------------------------------------------------------------

ORG 0 ; start at location 0

goto main ; jump over to main routine

ORG 4

goto Isr ; jump to interrupt routine

 

;----------------------------------------------------------------------;

; The Main routine ;

;----------------------------------------------------------------------;

; -------- THE MAIN MODULES ---------

; Isr stores elapsed TRIP time and generates hr:min:sec

; Disptime TRIP time, to max 99:59:59

; Dist Calculates total TRIP distance

; Dispdist TRIP distance to a max of 999km 999m

; Velav Average velocity, Totdist/totsecs max 99km/hr

; Dispvav Average TRIP speed up to 99.99 km/hr

; Velocity Speed from 2m/(time diff of pulse2-pulse1)

; Dispd Speed up to 99.99km/hr

; NOTE. Speed is your calculated velocity every second

; -------- more to come??? NO, running out of space ---------

 

;-----------------------------------------------------------------------

; M A I N

;-----------------------------------------------------------------------

 

main:

call Init ; Initialize ports, set up timer

call Initlcd ; Initialize the LCD DUMMY

Initend:

;------------------------------------------------------------------

; Changesec Changewhlpulse wait for interrupts from newsec or newwheelpulse

; -----------------------------------------------------------------

clrf menu ; initially set to 0 menu loop

clrf spdflg ; Initially = 0 2nd = sub for time from zero

; every new sec, set to zero

; CHANGESEC LOOPS TILL SEC CHANGES

;clrw ;DUMMY

;xorwf sec,w ;DUMMY

;btfsc STATUS,2 ;DUMMY

;incf sec,f ;DUMMY

Changesec: ;loops checking new sec and new wheel pulse

movf oldsec, w

xorwf sec,w

; if equal, w= 0 and Z bit=1

btfsc STATUS,2 ; test Z bit

goto Changesec ; no change, loop

movf sec,w ; sec has increased, update

movwf oldsec ; sec and oldsec are = again

incf menu,f ; increases menu every sec

; Note1, sectotlo/hi are updated every sec in ISR module

; Note2, Decimal time also created in ISR module

; but time display for LCD controlled from

; the automatic menu below

call Disptime ;TRIP time, will appear on LCD top line

Changewhp: ; 1st detected wheelpulse starts menu sequence

clrf PORTB

bcf PORTB,5 ; start with green LED off

loop:

btfss PORTB, 4 ;(PUT BTFSC FOR TEST); i/p hi,?DUMMY

goto loop ; not yet

; i/p hi detected

;green LED flashes with every wheel pulse

bsf PORTB, 5 ; LED on

; wait a while to make sure switch has

; settled

movlw D'10' ; wait about 10 msec

call nmsec

btfsc PORTB, 4 ; will be lo (0) when finished

goto $ -1 ; still low

; now must wait a make sure bouncing stopped

movlw D'10' ; 10 milliseconds

call nmsec

; and check again

btfsc PORTB, 4 ; if set, not finished

goto $ -5 ; still hi start debounce wait again

Tp1: ; green LED ready for next wheel pulse

bcf PORTB,5 ; i.e. LED off

movf PORTB,w ; reading to clear

; AUTOMATIC MENU: (LCD Top line always time)

; --------------

; menu selects at 10sec intervals in rotation

; Speed menu 1 to 10

; Dist ance menu 11 to 20

; Velav Avg vel menu 21 to 30

; MENU 0 TO 10

; as speed ( Speed) is stand alone, no sense in calculating it

; if it is not going to be displayed when menu is >10.

; BUT if SPEED AVERAGING IS TO BE USED, kill off the lines below that bypass

; the SPEED calc module

Menucheck:

movlw 0x0A ;check menu > 10 (to meet >10 AND =<20)

subwf menu,w

btfss STATUS,C ;compare with 10

goto $+2 ;menucount =< 10 not yet got to 11 jump to Speed

goto Distblk

call Speed ; Calculates instant speed,(time between pulses)

movlw 0x0A ; DUMMY, was movlw 0xA

subwf menu,w

btfss STATUS,C ;compare with 10

call Spdflgcheck ;menucount =< 10 ; also see 0-1 spdflg

goto Distblk

Spdflgcheck:

clrw

xorwf spdflg,w

btfsc STATUS,Z

call Dispd ;menucount =< 10 AND spdflg =1

Return

Distblk:

call Dist ;menucount > 10 skip Dispd update Dist

 

; MENU 11 TO 20

movlw 0x0A ;check menu > 10 (to meet >10 AND =<20)

subwf menu,w

btfss STATUS,C ;compare with 10

goto $+5 ;menucount =< 10 not yet got to 11 jump to velav

movlw 0x14

subwf menu,w

btfss STATUS,C ;compare with 20

call Dispdist ;menucount =< 20

call Velav ;menucount > 20 skip dispdist update Velav

; MENU 20 TO 30

movlw 0x14 ;check menu > 20 (to meet >20 AND =<30)

subwf menu,w

btfss STATUS,C ;compare with 20

goto $+5 ;menucount =< 20 not yet got to 21 jump to NEXT

movlw 0x1E

subwf menu,w

btfss STATUS,C ;compare with 30

call Dispvav ;menucount =< 30

movlw 0x1F ;if it has reached 31 reset menu, before return

xorwf menu,w

btfss STATUS,Z

goto $ +2 ; not 31 goto changewhp1 direct

clrf menu ; is 31, reset menu before changewhp1

Menuend:

; before changewhp jump, check that sec has not updated

; if it has , jump back to changesec routine

movf oldsec, w

xorwf sec,w ; if equal, w= 0 and Z bit=1

btfsc STATUS,2 ; test Z bit

goto Changewhp ; no sec change, check whpulse change

goto Changesec ; a new sec starts measurements

; loop while NOT newsec

; ---------------------------------------------------------------

; End Main

; ----------------------------------------------------------------

 

 

 

;----------------------------------------------------------------------;

; ISR, increments TMR0 by 1 every 256 µsec. Basically just ;

; reset the INTCON and TMR0 bits. The FSR,w, STATUS push pop kept ;

;----------------------------------------------------------------------;

Isr:

movwf w_temp ; save W

swapf STATUS,W ; save status

movwf status_temp ; without changing flags

swapf FSR,W ; save FSR

movwf fsr_temp ; without changing flags

;256us * 217 * 18 = 0.999936 sec.

;1hr_err = 0.23sec or 1 sec in 4hr

;The time loop starts with TMR0 loaded with (256-217)=39 After 217

;steps interrupt is set, TMR0 rolls to zero and the TMR18 inc +1

movlw D'39' ;39 = 0x27

movwf TMR0

incf TMR18,f

movlw D'18' ; DUMMY18 = 0x12

xorwf TMR18,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto restore ; NOT 18 so pop stack and return to main

Firstsec:

clrf TMR18 ; is 18. set TMR18 to zero and INC sec

incf sec,f ; also inc sectot (eventually lo and hi)

incf sectotlo,f ; check sectot lo 00->inc hi

clrw

xorwf sectotlo,w ; if equal, w= 0 and Z bit=1

btfsc STATUS,2

incf sectothi,f ; increases every 256 x sectotlo

movlw 0xA ; check if =10

xorwf sec,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto restore ; NOT 10 so pop stack and return to main

clrf sec ; is 10. set sec to zero and inc sec10

incf sec10,f

movlw 0x6 ; = 0x6

xorwf sec10,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto restore ; NOT 6 so pop stack and return to main

 

clrf sec10 ; is 6. set sec10 to zero and INC min

incf min,f

movlw 0xA ; check if =10

xorwf min,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto restore ; NOT 10 so pop stack and return to main

clrf min ; is 10. set sec to zero and inc min10

incf min10,f

movlw 0x6 ;= 0x6

xorwf min10,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto restore ; NOT 6 so pop stack and return to main

clrf min10 ; is 6. set min10 to zero and INC hr

incf hr,f

movlw 0xA ;check if =10

xorwf hr,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto restore ; NOT 10 so pop stack and return to main

clrf hr ; is 10. set hr to zero and inc hr10

incf hr10,f

movlw 0xA ;= 10

xorwf hr10,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto restore ; NOT 10 so pop stack and return to main

clrf sec ; is ten (99hr 59min 59sec +1sec) we are at MAX

clrf sec10 ;all reset to zero and start again

clrf min

clrf min10

clrf hr

clrf hr10

clrf TMR18

clrf oldsec

goto restore

restore:

swapf status_temp,W ; get original status back

movwf STATUS ; into status register

swapf fsr_temp,W ; get original fsr back

movwf FSR ; into status register

swapf w_temp,f ; old no flags trick again

swapf w_temp,W ; to restore W

bcf INTCON,T0IF ; clear the TMR0 interrupt flag

retfie ; finished, reset GIE

;----------------------------------------------------------------------;

; Initialize the ports ;

;----------------------------------------------------------------------;

Init:

clrf PORTA

clrf PORTB

movlw B'00000000' ; Porta all outputs

tris PORTA

movlw B'01010000' ; 7o 6i-Wire 5o-LED 4i-multivib,

tris PORTB ; 0to3lcd

 

movlw B'00000111' ; opt pull-ups enabled

; opt prescaler assigned to TMR18

; opt prescaler set to 1:256

option ; opt rolls over each 125th second

movlw 0 ; zero out all registers

clrf m

clrf m10

clrf m100

clrf m1000

clrf dm

clrf dm10

clrf dm100

clrf dm1000

clrf dm10000

clrf dm100000

clrf totmshi

clrf totmslo

clrf totms2hi

clrf totms2lo

clrf dist54

clrf hr10

clrf hr

clrf min10

clrf min

clrf oldsec

clrf sec10

clrf sec

clrf sectotlo

clrf dtotlo

clrf dtothi

clrf sectotlo

clrf sectothi

clrf TMR18 ; when this reaches 18, 1 sec has elapsed

; TMR0 has to start at 256-217 :39, so that the first rollover

; with prescaler 256, happens in 217*256us =0.055552sec

; The TMR18 incs each roll and after 18 1 sec has elapsed

movlw 0x27 ; D39

movwf TMR0 ; set to D39 217 counts later 256,

; TMR0 resets and inc TMR18 in Isr loop

clrf INTCON ; START WITH ALL AT 0

; movlw B'10100000' ; GIE set T0IE set, T0IF cleared

movlw B'10100000' ; Set:GIE,T0IE,RBIE Clrd:T0IF,RBIF

movwf INTCON ; ready to detect interrupts in ISR

return

;----------------------------------------------------------------------;

; Initialize the LCD ;

;----------------------------------------------------------------------;

Initlcd:

movlw D'40'

call nmsec ; Wait 40 msecs before Reset

bcf RS ; send an 8 bit instruction

movlw 0x03 ; Reset Command

call NybbleOut ; Send the Nybble

call Dlay5 ; Wait 5 msecs before Sending Again

call EStrobe

call Dlay160 ; Wait 160 usecs before Sending 2nd Time

call EStrobe

call Dlay160 ; Wait 160 usecs before Sending 3rd Time

bcf RS ; send an 8 bit instruction

movlw 0x02 ; Set 4 Bit Mode

call NybbleOut

call Dlay160

movlw 0x028 ; 4 bit, 2 Line, 5x7 font

call SendINS

movlw 0x010 ; display shift off

call SendINS

movlw 0x001 ; Clear the Display RAM

call SendINS

call Dlay5 ; Note, Can take up to 4.1 msecs

movlw 0x006 ; increment cursor

call SendINS

movlw 0x00C ; display on cursor off

call SendINS

return

;----------------------------------------------------------------------;

; Send the character in W out to the LCD ;

;----------------------------------------------------------------------;

SendASCII

addlw '0' ; Send nbr as ASCII character

SendCHAR: ; Send the Character to the LCD

movwf temp ; Save the temporary Value

swapf temp, w ; Send the High Nybble

bsf RS ; RS = 1

call NybbleOut

movf temp, w ; Send the Low Nybble

bsf RS

call NybbleOut

return

;-------------------------------------------------------------

; ES strobe

;-------------------------------------------------------------

EStrobe: ; Strobe the "E" Bit

bsf E

bcf E

return

;----------------------------------------------------------------------;

; Send an instruction in W out to the LCD ;

;----------------------------------------------------------------------;

SendINS: ; Send the Instruction to the LCD

movwf temp ; Save w

swapf temp, w ; send Hi Nybble

bcf RS ; RS to 0

call NybbleOut

movf temp, w ; Send Lo Nybble

bcf RS

call NybbleOut

return

;----------------------------------------------------------------------;

; Send the nibble in W out to the LCD ;

;----------------------------------------------------------------------;

NybbleOut: ; Send a Nybble to the LCD

movwf PORTB

call EStrobe ; Strobe out the LCD Data

bsf E

call Dlay160 ; delay for 160 usec

return

;----------------------------------------------------------------------;

; Output the message on the LCD ;

;----------------------------------------------------------------------;

OutMessage1:

movwf FSR ; Point at first letter

OutLoop:

movf FSR, w ; Get pointer into W

incf FSR, f ; Set up for next letter

call Dispmsg1 ; Get character to output

iorlw 0 ; At the End of the Message?

btfsc STATUS, Z ; Skip if not at end

return ; Yes - Equal to Zero

call SendCHAR ; Output the ASCII Character

goto OutLoop ; Get the next character

;----------------------------------------------------------------------;

; Data for message to be output ;

;----------------------------------------------------------------------;

Dispmsg1: ; Message to Output

addwf PCL, f ; Output the Characters

dt "Bike Computer", 0

Dispmsg2: ; Message to Output

addwf PCL, f ; Output the Characters

dt "Dist", 0

Dispmsg3:

addwf PCL,f ; message to output

dt " Av speed:",0 ; output characters

;----------------------------------------------------------------------;

; time delay routines ;

;----------------------------------------------------------------------;

;Note . The original application needed precise times from the delay code that

; follows. But the Simple Bike application does NOT use the routines for

; any CRITICAL time measurement.

Dlay160:

movlw D'41' ; delay about 160 usec

micro4:

addlw H'FF' ; subtract 1 from 'W'

btfss STATUS,Z ; skip when you reach zero

goto micro4 ; more loops

return

Dlay5:

movlw 5 ; delay for 5 milliseconds

goto $ + 2

msec250:

movlw D'250' ; delay for 250 milliseconds

; --- N millisecond delay routine ---

nmsec:

movwf cntmsec ; delay for N (you put in W) millisec

msecloop:

movlw D'254' ; load takes .9765625 microsec

call micro4 ; by itself CALL takes ...

; about 1ms

nop ; 1usec

decfsz cntmsec, f ; .98 skip not taken, else 1.95

goto msecloop ; 1.95 here: total ~1000 / loop

return ; final time through ~999 to here

; overhead in and out ignored

; this block is functional for tests, but not used in bike

Dlay1sec: ; this is a marker routine to see where

call msec250 ; the prg is at.

; bsf LED

call msec250 ;flash led on portb pin6

;bcf LED

call msec250

; bsf LED

call msec250 ; finishes with green led lit

return

;----------------------------------------------------------------------;

; Display the Time ;

;----------------------------------------------------------------------;

Disptime:

movlw H'80' ; position at beginning of first line

call SendINS

movf hr10, W ; tens of hours

call SendASCII

movf hr, W ; hours

call SendASCII

movlw ":"

call SendCHAR

movf min10, W ; tens of minutes

call SendASCII

movf min, W ; minutes

call SendASCII

movlw ":"

call SendCHAR

movf sec10, W ; tens of seconds

call SendASCII

movf sec, W ; seconds

call SendASCII

movlw " "

call SendCHAR ; the h m s really not needed

movlw "h"

call SendCHAR

movlw "m"

call SendCHAR

movlw "s"

call SendCHAR

movlw " "

call SendCHAR

Dispend:

RETURN

;----------------------------------------------------

; End of display time

;----------------------------------------------------

 

;----------------------------------------------------------------------;

; Display the Distance , (trip distance at moment) ;

;----------------------------------------------------------------------;

Dispdist:

movlw H'C0' ; position at beginning of second line

call SendINS

movf dm100000, W ; 0 of 065km 536m

call SendASCII

movf dm10000, W ; 6 of 065km 536m

call SendASCII

movf dm1000, W ; 5 of 065km 536m

call SendASCII

movlw "k" ; k of 065km 536m

call SendCHAR

movlw "m" ; m of 065km 536m

call SendCHAR

movlw " " ; " " of 065km 536m

call SendCHAR

movf dm100,W ; 5 of 065km 536m

call SendASCII

movf dm10,W ; 3 of 065km 536m

call SendASCII

movf dm, W ; 6 of 065km 536m

call SendASCII

movlw "m" ; m of 065km 536m

call SendCHAR

movlw " " ; " "

call SendCHAR

movlw "D" ; "D "

call SendCHAR

movlw "i" ; " i"

call SendCHAR

movlw "s" ; "s "

call SendCHAR

movlw "t" ; " t"

call SendCHAR

movlw " " ; " " ( to wipe screen)

call SendCHAR

Distend:

RETURN

;

;---------------------------------------------------------------------*

; Multiplication 16x16 Out32

;---------------------------------------------------------------------*

Mult16x16:

clrf mq4

clrf mq3

clrf mq2

clrf mq1

bsf mq2, 7

Mu1:

rrf mah, f

rrf mal, f

skpc

goto Mu2

movf mbl, w

addwf mq3, f

movf mbh, w

skpnc

incfsz mbh, w

addwf mq4, f

Mu2:

rrf mq4, f

rrf mq3, f

rrf mq2, f

rrf mq1, f

skpc

goto Mu1

Endmult16:

clrf mbh

clrf mbl

clrf mah

clrf mal

Return

;---------------------------------------------------------------------*

; End Multiplication 16x16 Out32

;---------------------------------------------------------------------*

;---------------------------------------------------------------------*

; New routine Division 16/16 Out 16

; ---------------------------------------------------------------------*

; Finally:- Result 000AH in reshi/lo, remainder 0096H in rmdrhi/lo

; so, checking end of division A=10 and 96H/E1H= 150/225 =0.666 OK

Div:

call D_divS ; remainder in Rmdr.

Divend:

nop

return

D_divS:

call setup

clrf rmdrhi

clrf rmdrlo

dloop:

bcf STATUS,C

rlf reslo, f

rlf reshi, f

rlf rmdrlo, f

rlf rmdrhi, f

movf denhi,w

subwf rmdrhi,w ;check if a>c

btfss STATUS,Z

goto nochk

movf denlo,w

subwf rmdrlo,w ;if msb equal then check lsb

nochk:

btfss STATUS,C ;carry set if c>a

goto nogo

movf denlo,w ;c-a into c

subwf rmdrlo, f

btfss STATUS,C

decf rmdrhi, f

movf denhi,w

subwf rmdrhi, f

bsf STATUS,C ;shift a 1 into b (result)

nogo:

rlf numlo,f

rlf numhi,f

decfsz temp, f ;loop untill all bits checked

goto dloop

setup:

movlw .16 ; for 16 shifts

movwf temp

movf numhi,w ;move Num to Res

movwf reshi

movf numlo,w

movwf reslo

clrf numhi

clrf numlo

retlw 0

;--------------------------End Div 16 by 16----------------------------

 

 

return

;---------------------------------------------------------------------*

; END DIVISION 16/16 OUT 16

;---------------------------------------------------------------

;---------------------------------------------------------------------*

; START Addition 16-16 OUT 16

;---------------------------------------------------------------

Add: ; R = q1 + q2

movf q1lo, W

addwf q2lo, W

movwf rlo

movf q1hi, W

btfsc STATUS, C

addlw .1 ; If A Carry Occurred, Add 1

addwf q2hi, W

movwf rhi

;clrf q1hi ; added this to stop next user summing;

;clrf q1lo

;clrf q2hi

;clrf q2lo

Return

;---------------------------------------------------------------------*

; END Addition 16-16 OUT 16

;---------------------------------------------------------------

 

 

;---------------------------------------------------------------------*

; START Subtraction 16-16 OUT 16

;---------------------------------------------------------------

Sub: ; R = q1 - q2

movf q2lo, W

subwf q1lo, W ; W = q1lo - q2lo

movwf rlo

btfss STATUS, C

Goto Borrow

Goto Sub1

Borrow:

Decf q1hi, F

Sub1:

movf q2hi, W

subwf q1hi, W ; W = q1hi - q2hi

movwf rhi

Return

;---------------------------------------------------------------

; END Subtraction 16-16 OUT 16

;---------------------------------------------------------------

 

 

 

 

 

;---------------------------------------------------------------

; Dist = counting wheel pulses

;---------------------------------------------------------------

Dist: ; whlcirc = 2.0747, for initial test =2

;

; movlw 0x2 ; <-- don't forget, this is just for 26"wheel

; movwf whlcirc ; start count at 0 and inc till same as whlcirc

; (range will be 1 to 4 m)

clrf count ; count can be 2 or 4 in this 26" case

Whloop: ; although the distance pulses ( in this example) jump in steps of 2m

; the m counter has to increase in 1's to catch the

; decimal rollover from 10 to 0

; so count, here, is stepped from 0 to 2 (whlcirc)

; Also, when the dist54 var increases 54m, COUNT adds an extra 2m

; to the hex and decimal totals, before resetting to zero.

; Note that as dist54 is in the loop it will also receive

; the 2m increase so it really counts to 56 (54 +2).

movlw 0x2 ; wheel circumference of 26 inch

xorwf count,w ; if equal, w= 0 and Z bit=1

btfsc STATUS,2 ; test Z bit

goto DistanceEnd ; they are the same, so jump distanceEnd and return

goto Mcount ; NOT yet = whlcirc, so inc mcount by 1 and return

Mcount: ; Distance to decimal for display , i/p m, o/p 000km 000m

; starts with m, m10, m100, m1000 , m10000, m100000 = 0

; Later correct m every 54m (add 2m ???? )

incf dm,f

movlw D'10'

xorwf dm,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto Mcountend ; NOT 0 so return

clrf dm

incf dm10,f

movlw D'10'

xorwf dm10,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto Mcountend ; NOT 0 so return

clrf dm10

incf dm100,f

movlw D'10'

xorwf dm100,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto Mcountend ; NOT 0 so return

clrf dm100

incf dm1000,f

movlw D'10'

xorwf dm1000,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto Mcountend ; NOT 0 so return

clrf dm1000

incf dm10000,f

movlw D'10'

xorwf dm10000,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto Mcountend ; NOT 0 so return

clrf dm10000

incf dm100000,f

movlw D'10'

xorwf dm100000,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto Mcountend ; NOT 0 so return

clrf dm ; is distmax, reset to 0

clrf dm10

clrf dm100

clrf dm1000

clrf dm10000

clrf dm100000

goto Mcountend ; see if whpl update is now finished

 

 

Mcountend: ;update the hex counters dtot /lo/hi/hi2

incf dtotlo,f

clrw

xorwf dtotlo,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto Dtotend ; dtotlo NOT 0

incf dtothi,f ; add 1, dtotlo is 0

clrw

xorwf dtothi,w ; if equal, w= 0 and Z bit=1

btfss STATUS,2 ; test Z bit

goto Dtotend ; dtothi NOT 0

incf dtothi2,f ; add 1, dtothi is 0

Dtotend:

movlw D'54'

movwf numhi ; not in use here, use to store 54

movf dist54,w

subwf numhi,w

btfsc STATUS,C

goto Noextra ; dist54=< 53, don't freeze COUNT

movlw D'56' ; dist54>53 add 2 extra counts

movwf numhi ; not in use here to store 56

movf dist54,w

subwf numhi,w

btfsc STATUS,C

goto Extra ; dist54=< 56, freeze COUNT

clrf dist54

goto Noextra

 

 

Noextra:

incf dist54,f

incf count,f

goto Whloop

Extra: ; an extra loop BUT count is NOT increased

incf dist54,f

goto Whloop

DistanceEnd: ; All conversion loops have executed and

; only left to display in decimal, when selected

;

return ; BACK TO MAIN

;--------------------------------------------------------------------------

; End of Trip Distance calculation Module

;--------------------------------------------------------------------------

 

;----------------------------------------------------------

; Calculate Average velocity from Velav = totdist/totsec

;-----------------------------------------------------------

; 1st time round distto = 0 and sectot =0.

; Disttot lo/hi zero is prob OKbut test sec=0. If zero return

Velav:

clrw

xorwf sectotlo,w

btfss STATUS,Z

goto Spdstart ; not 0, onto Avspeed calc

clrw ; lo was 0, but hi byte may not be

xorwf sectothi,w

btfss STATUS,Z

goto Spdstart ; was not 0, onto Avspeed calc

;incf sectotlo,f ; DUMMY

;goto Spdstart ; DUMMY

return ; was also 0, abort module wait for sec inc

; to slow down the number of whpul in the test we add Dummies

Spdstart: ; for test delay incf sec and sectot, gives 7.2km/hr

;incf sec,f ; DUMMY

;incf sectotlo,f ; DUMMY

;Lpstart:

movlw 0x07 ; 1800 comp hi bytes

subwf dtothi,w

btfsc STATUS,C

goto Divratio ; dtothi is > 1800hi and needs dividing

; we suppose that the hibyte test is sufficient,

; it may not be true. e.g hi's the same but lo's diff

; pass dtot to m1000,m100

movf dtothi,w ; dtothi <1800

movwf m1000

movf dtotlo,w

movwf m100 ; m1000,m100 hold dtothi/lo ( no div needed)

movf sectothi,w

movwf m10

movf sectotlo,w

movwf m ; m10,m hold sectothi/lo ( no div needed)

; note, this is dtot to m1000,m100 not needing division

goto Ratend ; if divratio is needed, then m1000,m100 is used there

Divratio: ; enter variables and 1800

movf dtothi,w

movwf numhi

movf dtotlo,w

movwf numlo

movlw 0x07

movwf denhi

movlw 0x08

movwf denlo

call Div

incf reslo,w ; reslo holds INT of Divratio +1

movwf count ; not used at the moment

movf dtothi,w ; divide dtothi/lo by count

movwf numhi

movf dtotlo,w

movwf numlo

clrf denhi

movf count,w ; e.g. D 37

movwf denlo

call Div ; we need parking space for results, REuse the m1000 etc

movf reshi,w

movwf m1000 ;

movf reslo,w

movwf m100 ; m1000, m100 =dtot/count

; repeat for sectot

movf sectothi,w

movwf numhi

movf sectotlo,w

movwf numlo

clrf denhi

movf count,w ; e.g D 37

movwf denlo

call Div

movf reshi,w

movwf m10

movf reslo,w

movwf m ; m10, m =sectot/count

Ratend:

; WE CAN NOW DO DTOT/SECTOT x3.6 as we have SCALED TO AVOID OVERFLOW

; m1000,m100 x 36 (top line)

; Vav= ------------------------- = Average speed in km/hr

; m10,m x 10 (bottom line) ; 36(24H), 10(AH)

movf m1000,w ; MULT dtot, top line, by 24H

movwf mah

movf m100,w

movwf mal

clrf mbh

movlw 0x24

movwf mbl

call Mult16x16 ; ( store top line result in the same variables)

movf mq2,w

movwf m1000

movf mq1,w

movwf m100 ; dtot x 36

movf m10,w ; MULT sectot, bottom line, by AH

movwf mah

movf m,w

movwf mal

clrf mbh

movlw 0xA

movwf mbl

call Mult16x16 ; ( store bottom line result in the same variables)

movf mq2,w

movwf m10

movf mq1,w

movwf m ; sectot x 10

Tp3:

; As we are reusing variables, trying to show where the results to here are being held

; m1000,m100

; We now have as Average speed ----- --------- km/hr

; m10,m

;the AVERAGE SPEED AT LAST

movf m1000,w ; dtotx36/sectotx10

movwf numhi

movf m100,w

movwf numlo

movf m10,w

movwf denhi ; needed below for decimal place

movf m,w

movwf denlo ; needed below for decimal place

call Div

; denhi/lo can chanfge as the div routine reuses bits

; so we reestablish previous denom values before losing

movf m10,w

movwf denhi

movf m,w

movwf denlo ; we can now write over m and m10

movf reshi,w ;will be zero

;(bikes don't exceed 256km/hr normally)

movf reslo,w ; reuse variables m10 INT and later m FRAC

movwf m10 ;we have integer part of Vav Average speed

; rmdrhi/lo holds decimal fraction.we will only use 1 decimal place.

; so mult the rmdrhi,lo x10 before dividing by denhi/lo

movf rmdrhi,w ; mult top by 10

movwf mah

movf rmdrlo,w

movwf mal ; rmdr in tot storage

clrf mbh

movlw 0xA

movwf mbl

call Mult16x16 ; rmdrhi,lo x 10

; top line is now mq2,mq1 ( nothing in mq4,mq3)

; Bottom line..remember we already have loaded

; the denominator above which says

; " needed below for decimal place"

Tp4:

movf mq2,w ;rmdrhi,w

movwf numhi

movf mq1,w ;rmdrlo,w

movwf numlo

call Div ; div for the decimal( just 1 place), in reslo

; reshi,reslo holds decimal place results

; m10+m are av speed as INT+DEC but in hex

; now change to decimal.

; m10 and m are going to be wiped, but there is no

;divide routine so for INT +FRAC we use reshi reslo

movf m10,w

movwf reshi ; OK? yes reshi +reslo = INT+FRAC in hex, convert

Vavh2d:

clrf m

clrf m10

clrf count

Vavloh2d: ; m is 2nd dec, use m10

movf count,w

xorwf reslo,w

btfsc STATUS,Z

goto Vavloend

incf count,f

incf m10,f

movlw 0xA

xorwf m10,w

btfss STATUS,Z

goto Vavloh2d

clrf m10

incf m,f

goto Vavloh2d

Vavloend:

clrf m100

clrf m1000

clrf count

Vavhih2d:

movf count,w

xorwf reshi,w

btfsc STATUS,Z

goto Vavhiend

incf count,f

incf m100,f

movlw 0xA

xorwf m100,w

btfss STATUS,Z

goto Vavhih2d

clrf m100

incf m1000,f

goto Vavhih2d

Vavhiend: ; We have Vav as: INT m1000,m100 and FRAC m10,m with Frac

Vavend:

nop

return

 

;----------------------------------------------------------------------;

; Display the Average velocity ;

;----------------------------------------------------------------------;

Dispvav:

movlw H'C0' ; position at beginning of second line

call SendINS

movf m1000, W ; x0 tens of km

call SendASCII

movf m100,W ; 0x ones of km

call SendASCII

movlw "." ; "." punto decimal

call SendCHAR

movf m10,W ; "0.x0" decimal

call SendASCII

movf m, W ; "0.0x" decimal

call SendASCII

movlw "k" ; k

call SendCHAR

movlw "m" ; m

call SendCHAR

movlw "/" ; /

call SendCHAR

movlw "h" ; h

call SendCHAR

movlw "r" ; r

call SendCHAR

movlw " " ; " "

call SendCHAR

movlw "V" ; V

call SendCHAR

movlw "e" ; e

call SendCHAR

movlw "l" ; l

call SendCHAR

movlw "A" ; A

call SendCHAR

movlw "v" ; v

call SendCHAR

movlw "g" ; g

call SendCHAR

movlw " " ; " "

call SendCHAR

Dispvavend:

Return ; to change seconds for next second

;--------------END OF AV SPEED-------------------

 

 

 

 

 

 

 

; ---------------------------------------------------------------

; Instantaneous Speed

;-----------------------------------------------------------------

; Previous time values are subtracted from the present

; sec, TMR18, TMR0 values.

; This time difference is the time between

; wheel pulses. This in turn for 26" wheel is a distance of 2.0747m

; is covered in totms

; ---------------------------------------------------------------

; Instantaneous Speed

;-----------------------------------------------------------------

; Note sec can only move between 0 and 9, 10 is a new 0

; We start by reading sec, TMR18, TMR0 TO GET START TIME

Speed:

Spdflg0: ; FIRST TIMEwith spdflg=0, second time with spdflg=1

; First time captures timezero 0 in ms in totms

clrw

xorwf spdflg,w

btfss STATUS ,Z

goto Spdflg1 ; spdflg is not 0, this is the second time

call Summs

movf mshi,w

movwf totmshi

movf mslo,w

movwf totmslo

incf spdflg,f ; (spdflg = 1 for SECOND TIME)

return ;jump back to main menu

Summs: ; this routine is common to the first and second time

movf sec,w ; spdflg = 0

movwf mbl ; sec can only be in range 0 to 9

clrf mbh

movlw 0x03 ; 1000 = 03E8

movwf mah

movlw 0xE8 ; 1000 = 03E8

movwf mal

call Mult16x16 ;

movf mq2,w ; hi byte

movwf mshi

movf mq1,w ; lo byte

movwf mslo

movf TMR18,w

movwf mal

clrf mah

movlw D'56'

movwf mbl

clrf mbh

call Mult16x16 ; after themult we add

movf mshi,w

movwf q1hi

movf mslo,w

movwf q1lo

movf mq2,w

movwf q2hi

movf mq1,w

movwf q2lo

call Add

movf rhi,w

movwf mshi

movf rlo,w

movwf mslo ; sum (sec +TMR18)

;TMR0 is a little more complex as we have to subtract39

; before we can calculate ms in TMR0

movf TMR0,w

movwf q1lo

clrf q1hi

movlw D'39'

movwf q2lo

clrf q2hi

call Sub

movf rlo, w

movwf numlo

clrf numhi

movlw 0x4

movwf denlo

clrf denhi

call Div

movf mshi,w

movwf q1hi

movf mslo,w

movwf q1lo

movf reshi,w

movwf q2hi

movf reslo,w

movwf q2lo

call Add

movf rhi,w

movwf mshi

movf rlo,w

movwf mslo ; ( SEC +TMR18+ TMR0) in ms mshi/lo

RETURN ; Summs

Summsend:

 

Spdflg1: ; SECOND TIME is with spdflg =1

; Second time captures timezero to 2nd Pulse

; in ms, store in totms2

; for test we add 250ms to simulate time between

; wheel pulses

; 250ms delay

;movlw D'63' ; DUMMY FOR TEST

;call nmsec ; DUMMY FOR TEST

call Summs

movf mshi,w ;

movwf totms2hi ;

movf mslo,w ;

movwf totms2lo ;

 

; totms2 should be larger than totms,however if totms2 has just rolled,

; then add 10000 to tot2

Testtot2:

movf totms2hi,w

subwf totmshi,w

btfss STATUS,C ;compare for greater

goto Diffms ;totms2 > totms no add 10000 needed

movlw 0xA ;totms2 < totms, add 10000, hex 2710

movlw 0x27

movwf q1hi

movlw 0x10

movwf q1lo

movf totms2hi,w

movwf q2hi

movf totms2lo,w

movwf q2lo

call Add ; tot2 +10000

movf rhi,w

movwf totms2hi

movf rlo,w

movwf totms2lo ; tot2 = tot2+10000

 

Diffms:

 

; sub (tot2-tot1)for time between wheel pulses

movf totms2hi,w ;

movwf q1hi

movf totms2lo,w

movwf q1lo

movf totmshi,w

movwf q2hi

movf totmslo,w

movwf q2lo

call Sub ; result is time diff, stored in rhi, rlo

tp2:

; we are almost ready to divide dist/time for speed

; complete equation is dist/time x3.6

; to avoid as far as possible fractions we multiply before divide

; but this time, better divide first.

; 2000 36 <--- this is more than 65536

; ---- x --------

; denhi/lo 10 ( denhi/lo is sub result rhi/lo)

; so we can divide by 10 and x by 36 ( always,)

; so top line is simply 7200.

; we finally have 7200/(denhi/lo) , SPEED IN HEX

 

movf rhi,w

movwf denhi

movf rlo,w

movwf denlo ; denom is time in hex

movlw 0x1C ; 7200, hex 1C20

movwf numhi

movlw 0x20 ; 7200, hex 1C20

movwf numlo

call Div

; the result , res, is more than 1

;and a remainder rmdr/den

;we now have 6 free variables

; mshi/lo for INT hex speed lo is enough

; totmshi/lo

; totms2hi/lo

;we will reuse to convert from hex to decimal

movf reslo,w

movwf mshi ; INT part of hex speed ( hi, because FRAC will be in lo)

;we will only use 1 decimal of

;the hex speed remainder, so 1st rmdrx10

; so next calculation is

; 10 x rmdrhi/lo

; ---------------

; denhi/lo

movf rmdrhi,w

movwf mah

movf rmdrlo,w

movwf mal

clrf mbh

movlw 0x0A

movwf mbl

call Mult16x16 ;( ten times top)

movf mq2,w

movwf numhi

movf mq1,w

movwf numlo ; the den is previously loaded so divide for

; decimal part of speed ( still in hex)

call Div ; we only use 1 decimal, so just use lo of Div result

movf reslo,w

movwf mslo ; FRAC of speed in hex

; now convert speed to decimal form

; i.e. mshi, mslo --> 99.9 km/hr

Spdh2d:

clrf m

clrf m10

clrf m100

clrf m1000

clrf count

 

Spdlo:

movf count,w

xorwf mslo,w

btfsc STATUS,Z

goto Spdhicnt

incf count,f

incf m10,f

movlw 0xA

xorwf m10,w

btfss STATUS,Z

goto Spdlo

clrf m10

incf m,f

goto Spdlo

Spdhicnt:

clrf m100

clrf m1000

clrf count

Spdhi:

movf count,w

xorwf mshi,w

btfsc STATUS,Z

goto Spdhiend

incf count,f

incf m100,f

movlw 0xA

xorwf m100,w

btfss STATUS,Z

goto Spdhi

clrf m100

incf m1000,f

goto Spdhi

Spdhiend:; We have filled m1000,m100 with INT and m10,m with Frac, of Vin.

; Note we only need m10 ( 1 decimal place)

clrf spdflg ; reset to 0 for next pair of pulses

 

 

 

 

 

 

; incf spdflg,f ; (spdflg = 1 for SECOND TIME)

return

; ---------------------------------------------------------------**

; End of Instantaneous Speed

; ---------------------------------------------------------------**

 

 

Dispd:

;----------------------------------------------------------------------;

; Display the Instantaneous Speed (Speed) ;

;----------------------------------------------------------------------;

movlw H'C0' ; position at beginning of second line

call SendINS

 

movf m1000, W ; x0 tens of km

call SendASCII

movf m100,W ; 0x ones of km

call SendASCII

movlw "." ; "." punto decimal

call SendCHAR

movf m10,W ; "0.x0" decimal

call SendASCII

movf m, W ; "0.0x" decimal

call SendASCII

movlw "k" ; k

call SendCHAR

movlw "m" ; m

call SendCHAR

movlw "/" ; /

call SendCHAR

movlw "h" ; h

call SendCHAR

movlw "r" ; r

call SendCHAR

movlw " " ; " "

call SendCHAR

movlw "S" ; S

call SendCHAR

movlw "p" ; p

call SendCHAR

movlw "e" ; e

call SendCHAR

movlw "e" ; e

call SendCHAR

movlw "d" ; d

call SendCHAR

Dispdend:

Return ; to change seconds for next second

;--------------END OF Inst SPEED-------------------

end

;-----------------------------------------------------

; bike computer program end ....enjoy

;-----------------------------------------------------

 

 

; WORK IN HAND

; CLEAN UP SPEED, readout still a little jumpy,

; can try integrating but need more space. Next version

; Coventions used in the program text.

;Variables all small letters , exceptions, those defined

; by microchip. e.g. STATUS

;Labels: First letter always a Capital, exceptions imported

; routines

; Test points. These have a comment DUMMY, the value of the code

; has/had been changed for testing or simulating. If YOU want

;to polish these points should be useful for value changes

; example. In ISR the D'18' value to reach a sec is very slow.

;Use for test , say 2, and you get going about 10 times faster.

;Also LCD INIT: can be bypassed to debug quicker

 

;----------------------------------------------------------------------------------------------------

; End of the Simple Bike Computer

;----------------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

The END Product the HEX file

 

If you have managed to read to here, through all that has been written, then you certainly have determination.

Well " getting here" is the moment when you have mastered all the steps in writing the PIC assembler source code. Getting here also means you can do all the manual side as well for many future projects.

But maybe the most satisfaction is obtained by taking the final code version

and then burning it into the PIC to make your Bike Computer a reality,….not just a bit of theory.

Ah I almost forgot, here is the Bike3.asm squeezed into the END PRODUCT of our toil.

Bike3. hex

:020000000528D1

:080008004C289220BD20CB0121

:10001000C80138083206031909283208B800CB0A8B

:100020002E2186018612061A132886160A302221EE

:10003000061A18280A302221061A182886120608DD

:100040000A304B02031C25283028CB220A304B02F1

:10005000031C2B20302803014806031970230800D5

:10006000C4210A304B02031C392814304B02031CF4

:100070004B21122214304B02031C42281E304B022B

:10008000031CA4221F304B06031D4728CB01380850

:100090003206031911280928BB00030EBC00040E08

:1000A000BD0027308100BA0A12303A06031D8A28A3

:1000B000BA01B20AB00A030130060319B10A0A30C4

:1000C0003206031D8A28B201B30A06303306031D27

:1000D0008A28B301B40A0A303406031D8A28B40101

:1000E000B50A06303506031D8A28B501B60A0A305E

:1000F0003606031D8A28B601B70A0A303706031DE3

:100100008A28B201B301B401B501B601B701BA0141

:10011000B8018A283C0E83003D0E8400BB0E3B0EC6

:100120000B11090085018601003065005030660022

:10013000073062000030AC01AD01AE01AF01A60195

:10014000A701A801A901AA01AB01C301C201C50110

:10015000C401A501B701B601B501B401B801B301ED

:10016000B201B001A201A301B001B101BA0127306F

:1001700081008B01A0308B0008002830222105115E

:100180000330EB201F21E0201A21E0201A21051165

:100190000230EB201A212830E3201030E320013018

:1001A000E3201F210630E3200C30E3200800303E1E

:1001B000C900490E0515EB2049080515EB2008007C

:1001C000851585110800C900490E0511EB20490865

:1001D0000511EB2008008600E02085151A21080093

:1001E00084000408840AF920003803190800D82084

:1001F000F1288207423469346B3465342034433447

:100200006F346D3470347534743465347234003442

:1002100082074434693473347434003482072034E0

:100220004134763420347334703465346534643446

:100230003A3400342930FF3E031D1B2908000530E5

:100240002229FA30B900FE301B210000B90B232906

:100250000800212121212121212108008030E320D3

:100260003708D7203608D7203A30D8203508D7208D

:100270003408D7203A30D8203308D7203208D72086

:100280002030D8206830D8206D30D8207330D82066

:100290002030D8200800C030E3202B08D7202A08BF

:1002A000D7202908D7206B30D8206D30D8202030B7

:1002B000D8202808D7202708D7202608D7206D3037

:1002C000D8202030D8204430D8206930D82073304E

:1002D000D8207430D8202030D82008008C018D011F

:1002E0008E018F018E17920C930C031C7D2911082F

:1002F0008D0710080318100F8C078C0C8D0C8E0CBA

:100300008F0C031C73299001910192019301080045

:100310008B2100000800A6219901980103109B0D74

:100320009A0D980D990D15081902031D99291408A5

:100330001802031CA22914089802031C990315082B

:1003400099020314960D970DC90B8E291030C90020

:1003500017089A0016089B009701960100340800C0

:100360001D081F07A1001C080318013E1E07A0005E

:1003700008001F081D02A100031CBF29C0299C03FF

:100380001E081C02A0000800CA0102304A06031918

:10039000112AA60A0A302606031DF329A601A70A78

:1003A0000A302706031DF329A701A80A0A302806E8

:1003B000031DF329A801A90A0A302906031DF32900

:1003C000A901AA0A0A302A06031DF329AA01AB0AC9

:1003D0000A302B06031DF329A601A701A801A901D4

:1003E000AA01AB01F329A20A03012206031DFE297B

:1003F000A30A03012306031DFE29A40A3630970031

:100400002508170203180C2A383097002508170210

:1004100003180F2AA5010C2AA50ACA0AC529A50A8C

:10042000C529080003013006031D1B2A03013106FC

:10043000031D1B2A0800073023020318282A23085B

:10044000AF002208AE003108AD003008AC004B2AE6

:100450002308970022089600073095000830940082

:1004600088211B0ACA0023089700220896009501DC

:100470004A08940088211A08AF001B08AE00310812

:1004800097003008960095014A08940088211A08C0

:10049000AD001B08AC002F0892002E0893009001BD

:1004A000243091006E210E08AF000F08AE002D0819

:1004B00092002C08930090010A3091006E210E08E2

:1004C000AD000F08AC002F0897002E0896002D08ED

:1004D00095002C08940088212D0895002C08940084

:1004E0001A081B08AD001908920018089300900123

:1004F0000A3091006E210E0897000F08960088219F

:100500002D089A00AC01AD01CA014A081B06031967

:10051000922ACA0AAD0A0A302D06031D852AAD01AA

:10052000AC0A852AAE01AF01CA014A081A060319AE

:10053000A22ACA0AAE0A0A302E06031D952AAE0167

:10054000AF0A952A00000800C030E3202F08D7200A

:100550002E08D7202E30D8202D08D7202C08D720C1

:100560006B30D8206D30D8202F30D8206830D8207C

:100570007230D8202030D8205630D8206530D8208E

:100580006C30D8204130D8207630D8206730D82041

:100590002030D820080003014806031D122BD62264

:1005A0004608C3004708C200C80A08003208910084

:1005B000900103309200E83093006E210E08C600CF

:1005C0000F08C7003A08930092013830910090015B

:1005D0006E2146089C0047089D000E089E000F08EB

:1005E0009F00B0212008C6002108C70001089D0017

:1005F0009C0127309F009E01B92121089600970198

:10060000043094009501882146089C0047089D000D

:100610001A089E001B089F00B0212008C600210870

:10062000C7000800D6224608C5004708C400450890

:100630004302031C292B0A3027309C0010309D00F8

:1006400045089E0044089F00B0212008C5002108ED

:10065000C40045089C0044089D0043089E004208D1

:100660009F00B92120089500210894001C309700B4

:100670002030960088211B08C6001908920018082F

:10068000930090010A3091006E210E0897000F0828

:10069000960088211B08C700AC01AD01AE01AF0177

:1006A000CA014A08470603195E2BCA0AAD0A0A3076

:1006B0002D06031D512BAD01AC0A512BAE01AF012C

:1006C000CA014A08460603196E2BCA0AAE0A0A3046

:1006D0002E06031D612BAE01AF0A612BC801080075

:1006E000C030E3202F08D7202E08D7202E30D82066

:1006F0002D08D7202C08D7206B30D8206D30D8207B

:100700002F30D8206830D8207230D8202030D82020

:100710005330D8207030D8206530D8206530D820AC

:060720006430D82008003F

:02400E00F13F80

:00000001FF

Hasta la vista y Buena suerte

 

 

 

 

 

 

 

Appendix 1 Updated diagrams

 

PCB of Bike computer and test accessories.

This is the modified PCB diagram that now corresponds with the Theoretical bike and test Electrical circuit Diagram.

 

 

The Theoretical diag. +component layout

The theoretical electrical circuit of the Bike computer circuit , the test components and a layout diagram for component placement.